1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*5f1ef25cSAram Hăvărneanu  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
268d7e4166Sjose borrego #include <assert.h>
27da6c28aaSamw #include <sys/types.h>
28da6c28aaSamw #include <stdarg.h>
29da6c28aaSamw #include <unistd.h>
30da6c28aaSamw #include <stdlib.h>
31da6c28aaSamw #include <time.h>
32da6c28aaSamw #include <synch.h>
33da6c28aaSamw #include <syslog.h>
34da6c28aaSamw #include <string.h>
35da6c28aaSamw #include <strings.h>
36da6c28aaSamw #include <errno.h>
37da6c28aaSamw #include <net/if.h>
38da6c28aaSamw #include <netdb.h>
39dc20a302Sas #include <netinet/in.h>
40dc20a302Sas #include <arpa/nameser.h>
41dc20a302Sas #include <resolv.h>
42da6c28aaSamw #include <sys/sockio.h>
438d7e4166Sjose borrego #include <sys/socket.h>
44da6c28aaSamw #include <smbsrv/smbinfo.h>
45da6c28aaSamw #include <smbsrv/netbios.h>
46da6c28aaSamw #include <smbsrv/libsmb.h>
47da6c28aaSamw 
48faa1795aSjb static mutex_t seqnum_mtx;
49da6c28aaSamw 
50a0aa776eSAlan Wright /*
51a0aa776eSAlan Wright  * IPC connection information that may be passed to the SMB Redirector.
52a0aa776eSAlan Wright  */
53a0aa776eSAlan Wright typedef struct {
54a0aa776eSAlan Wright 	char	user[SMB_USERNAME_MAXLEN];
55a0aa776eSAlan Wright 	uint8_t	passwd[SMBAUTH_HASH_SZ];
56a0aa776eSAlan Wright } smb_ipc_t;
57a0aa776eSAlan Wright 
58a0aa776eSAlan Wright static smb_ipc_t	ipc_info;
59a0aa776eSAlan Wright static smb_ipc_t	ipc_orig_info;
60a0aa776eSAlan Wright static rwlock_t		smb_ipc_lock;
61a0aa776eSAlan Wright 
62eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
63eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * Some older clients (Windows 98) only handle the low byte
64eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * of the max workers value. If the low byte is less than
65eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  * SMB_PI_MAX_WORKERS_MIN set it to SMB_PI_MAX_WORKERS_MIN.
66eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States  */
67da6c28aaSamw void
68da6c28aaSamw smb_load_kconfig(smb_kmod_cfg_t *kcfg)
69da6c28aaSamw {
70dc20a302Sas 	int64_t citem;
71dc20a302Sas 
72da6c28aaSamw 	bzero(kcfg, sizeof (smb_kmod_cfg_t));
73da6c28aaSamw 
74dc20a302Sas 	(void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem);
75dc20a302Sas 	kcfg->skc_maxworkers = (uint32_t)citem;
76eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((kcfg->skc_maxworkers & 0xFF) < SMB_PI_MAX_WORKERS_MIN) {
77eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		kcfg->skc_maxworkers &= ~0xFF;
78eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		kcfg->skc_maxworkers += SMB_PI_MAX_WORKERS_MIN;
79eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
80eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 
81dc20a302Sas 	(void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem);
82dc20a302Sas 	kcfg->skc_keepalive = (uint32_t)citem;
83da6c28aaSamw 	if ((kcfg->skc_keepalive != 0) &&
84da6c28aaSamw 	    (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
85da6c28aaSamw 		kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
86da6c28aaSamw 
87dc20a302Sas 	(void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem);
88dc20a302Sas 	kcfg->skc_maxconnections = (uint32_t)citem;
89dc20a302Sas 	kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON);
90dc20a302Sas 	kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE);
91dc20a302Sas 	kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD);
927f667e74Sjose borrego 	kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE);
93cb174861Sjoyce mcintosh 	kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE);
94dc20a302Sas 	kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
95dc20a302Sas 	kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
96*5f1ef25cSAram Hăvărneanu 	kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS);
97da6c28aaSamw 	kcfg->skc_secmode = smb_config_get_secmode();
98b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_getdomainname(kcfg->skc_nbdomain,
99b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sizeof (kcfg->skc_nbdomain));
100b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_getfqdomainname(kcfg->skc_fqdn,
101b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sizeof (kcfg->skc_fqdn));
102b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_getnetbiosname(kcfg->skc_hostname,
103b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sizeof (kcfg->skc_hostname));
104dc20a302Sas 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment,
105da6c28aaSamw 	    sizeof (kcfg->skc_system_comment));
1069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_config_get_version(&kcfg->skc_version);
107148c5f43SAlan Wright 	kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0);
108da6c28aaSamw }
109da6c28aaSamw 
110da6c28aaSamw /*
111da6c28aaSamw  * Get the current system NetBIOS name.  The hostname is truncated at
112da6c28aaSamw  * the first `.` or 15 bytes, whichever occurs first, and converted
113da6c28aaSamw  * to uppercase (by smb_gethostname).  Text that appears after the
114da6c28aaSamw  * first '.' is considered to be part of the NetBIOS scope.
115da6c28aaSamw  *
116da6c28aaSamw  * Returns 0 on success, otherwise -1 to indicate an error.
117da6c28aaSamw  */
118da6c28aaSamw int
119da6c28aaSamw smb_getnetbiosname(char *buf, size_t buflen)
120da6c28aaSamw {
1219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_gethostname(buf, buflen, SMB_CASE_UPPER) != 0)
122da6c28aaSamw 		return (-1);
123da6c28aaSamw 
124da6c28aaSamw 	if (buflen >= NETBIOS_NAME_SZ)
125da6c28aaSamw 		buf[NETBIOS_NAME_SZ - 1] = '\0';
126da6c28aaSamw 
127da6c28aaSamw 	return (0);
128da6c28aaSamw }
129da6c28aaSamw 
130b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
131b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Get the SAM account of the current system.
132b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns 0 on success, otherwise, -1 to indicate an error.
133b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
134b89a8333Snatalie li - Sun Microsystems - Irvine United States int
135b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_getsamaccount(char *buf, size_t buflen)
136b89a8333Snatalie li - Sun Microsystems - Irvine United States {
137b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getnetbiosname(buf, buflen - 1) != 0)
138b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (-1);
139b89a8333Snatalie li - Sun Microsystems - Irvine United States 
140b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) strlcat(buf, "$", buflen);
141b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (0);
142b89a8333Snatalie li - Sun Microsystems - Irvine United States }
143b89a8333Snatalie li - Sun Microsystems - Irvine United States 
144da6c28aaSamw /*
145da6c28aaSamw  * Get the current system node name.  The returned name is guaranteed
146da6c28aaSamw  * to be null-terminated (gethostname may not null terminate the name).
147da6c28aaSamw  * If the hostname has been fully-qualified for some reason, the domain
1489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * part will be removed.  The returned hostname is converted to the
1499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * specified case (lower, upper, or preserved).
150da6c28aaSamw  *
151da6c28aaSamw  * If gethostname fails, the returned buffer will contain an empty
152da6c28aaSamw  * string.
153da6c28aaSamw  */
154da6c28aaSamw int
1559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which)
156da6c28aaSamw {
157da6c28aaSamw 	char *p;
158da6c28aaSamw 
159da6c28aaSamw 	if (buf == NULL || buflen == 0)
160da6c28aaSamw 		return (-1);
161da6c28aaSamw 
162da6c28aaSamw 	if (gethostname(buf, buflen) != 0) {
163da6c28aaSamw 		*buf = '\0';
164da6c28aaSamw 		return (-1);
165da6c28aaSamw 	}
166da6c28aaSamw 
167da6c28aaSamw 	buf[buflen - 1] = '\0';
168da6c28aaSamw 
169da6c28aaSamw 	if ((p = strchr(buf, '.')) != NULL)
170da6c28aaSamw 		*p = '\0';
171da6c28aaSamw 
1729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	switch (which) {
1739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	case SMB_CASE_LOWER:
1749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) smb_strlwr(buf);
1759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		break;
1769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	case SMB_CASE_UPPER:
178bbf6f00cSJordan Brown 		(void) smb_strupr(buf);
1799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		break;
1809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	case SMB_CASE_PRESERVE:
1829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	default:
1839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		break;
1849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
185da6c28aaSamw 
186da6c28aaSamw 	return (0);
187da6c28aaSamw }
188da6c28aaSamw 
189da6c28aaSamw /*
1909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Obtain the fully-qualified name for this machine in lower case.  If
1919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * the hostname is fully-qualified, accept it.  Otherwise, try to find an
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * appropriate domain name to append to the hostname.
193da6c28aaSamw  */
194da6c28aaSamw int
195dc20a302Sas smb_getfqhostname(char *buf, size_t buflen)
196da6c28aaSamw {
197dc20a302Sas 	char hostname[MAXHOSTNAMELEN];
198dc20a302Sas 	char domain[MAXHOSTNAMELEN];
199da6c28aaSamw 
200dc20a302Sas 	hostname[0] = '\0';
201dc20a302Sas 	domain[0] = '\0';
202dc20a302Sas 
2039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_gethostname(hostname, MAXHOSTNAMELEN,
2049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    SMB_CASE_LOWER) != 0)
205da6c28aaSamw 		return (-1);
206da6c28aaSamw 
207dc20a302Sas 	if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
208dc20a302Sas 		return (-1);
209dc20a302Sas 
210dc20a302Sas 	if (hostname[0] == '\0')
211dc20a302Sas 		return (-1);
212da6c28aaSamw 
213dc20a302Sas 	if (domain[0] == '\0') {
214dc20a302Sas 		(void) strlcpy(buf, hostname, buflen);
215da6c28aaSamw 		return (0);
216da6c28aaSamw 	}
217da6c28aaSamw 
218dc20a302Sas 	(void) snprintf(buf, buflen, "%s.%s", hostname, domain);
219dc20a302Sas 	return (0);
220dc20a302Sas }
221da6c28aaSamw 
222da6c28aaSamw /*
223dc20a302Sas  * smb_getdomainname
224dc20a302Sas  *
225dc20a302Sas  * Returns NETBIOS name of the domain if the system is in domain
226dc20a302Sas  * mode. Or returns workgroup name if the system is in workgroup
227dc20a302Sas  * mode.
228da6c28aaSamw  */
229da6c28aaSamw int
230dc20a302Sas smb_getdomainname(char *buf, size_t buflen)
231da6c28aaSamw {
232dc20a302Sas 	int rc;
233da6c28aaSamw 
234dc20a302Sas 	if (buf == NULL || buflen == 0)
235dc20a302Sas 		return (-1);
236da6c28aaSamw 
237dc20a302Sas 	*buf = '\0';
2388d7e4166Sjose borrego 	rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen);
239dc20a302Sas 
2408d7e4166Sjose borrego 	if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
241da6c28aaSamw 		return (-1);
242da6c28aaSamw 
243dc20a302Sas 	return (0);
244dc20a302Sas }
245dc20a302Sas 
246dc20a302Sas /*
247dc20a302Sas  * smb_getfqdomainname
248dc20a302Sas  *
2498d7e4166Sjose borrego  * In the system is in domain mode, the dns_domain property value
2508d7e4166Sjose borrego  * is returned. Otherwise, it returns the local domain obtained via
2518d7e4166Sjose borrego  * resolver.
252dc20a302Sas  *
253dc20a302Sas  * Returns 0 upon success.  Otherwise, returns -1.
254dc20a302Sas  */
255dc20a302Sas int
256dc20a302Sas smb_getfqdomainname(char *buf, size_t buflen)
257dc20a302Sas {
2588d7e4166Sjose borrego 	struct __res_state res_state;
2598d7e4166Sjose borrego 	int rc;
260dc20a302Sas 
261dc20a302Sas 	if (buf == NULL || buflen == 0)
262dc20a302Sas 		return (-1);
263dc20a302Sas 
264dc20a302Sas 	*buf = '\0';
265dc20a302Sas 	if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) {
2668d7e4166Sjose borrego 		rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen);
267dc20a302Sas 
2688d7e4166Sjose borrego 		if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
2698d7e4166Sjose borrego 			return (-1);
2708d7e4166Sjose borrego 	} else {
2718d7e4166Sjose borrego 		bzero(&res_state, sizeof (struct __res_state));
2728d7e4166Sjose borrego 		if (res_ninit(&res_state))
273dc20a302Sas 			return (-1);
274dc20a302Sas 
2758d7e4166Sjose borrego 		if (*res_state.defdname == '\0') {
2768d7e4166Sjose borrego 			res_ndestroy(&res_state);
2778d7e4166Sjose borrego 			return (-1);
278dc20a302Sas 		}
2798d7e4166Sjose borrego 
2808d7e4166Sjose borrego 		(void) strlcpy(buf, res_state.defdname, buflen);
2818d7e4166Sjose borrego 		res_ndestroy(&res_state);
2828d7e4166Sjose borrego 		rc = 0;
283dc20a302Sas 	}
284dc20a302Sas 
285dc20a302Sas 	return (rc);
286da6c28aaSamw }
287da6c28aaSamw 
288dc20a302Sas 
289faa1795aSjb /*
290faa1795aSjb  * smb_set_machine_passwd
291faa1795aSjb  *
292faa1795aSjb  * This function should be used when setting the machine password property.
293faa1795aSjb  * The associated sequence number is incremented.
294faa1795aSjb  */
295faa1795aSjb static int
296faa1795aSjb smb_set_machine_passwd(char *passwd)
297faa1795aSjb {
298faa1795aSjb 	int64_t num;
299faa1795aSjb 	int rc = -1;
300faa1795aSjb 
301faa1795aSjb 	if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK)
302faa1795aSjb 		return (-1);
303faa1795aSjb 
304faa1795aSjb 	(void) mutex_lock(&seqnum_mtx);
305faa1795aSjb 	(void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
306faa1795aSjb 	if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num)
307faa1795aSjb 	    == SMBD_SMF_OK)
308faa1795aSjb 		rc = 0;
309faa1795aSjb 	(void) mutex_unlock(&seqnum_mtx);
310faa1795aSjb 	return (rc);
311faa1795aSjb }
312faa1795aSjb 
313a0aa776eSAlan Wright static int
314a0aa776eSAlan Wright smb_get_machine_passwd(uint8_t *buf, size_t buflen)
315a0aa776eSAlan Wright {
316a0aa776eSAlan Wright 	char pwd[SMB_PASSWD_MAXLEN + 1];
317a0aa776eSAlan Wright 	int rc;
318a0aa776eSAlan Wright 
319a0aa776eSAlan Wright 	if (buflen < SMBAUTH_HASH_SZ)
320a0aa776eSAlan Wright 		return (-1);
321a0aa776eSAlan Wright 
322a0aa776eSAlan Wright 	rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd));
323a0aa776eSAlan Wright 	if ((rc != SMBD_SMF_OK) || *pwd == '\0')
324a0aa776eSAlan Wright 		return (-1);
325a0aa776eSAlan Wright 
326a0aa776eSAlan Wright 	if (smb_auth_ntlm_hash(pwd, buf) != 0)
327a0aa776eSAlan Wright 		return (-1);
328a0aa776eSAlan Wright 
329a0aa776eSAlan Wright 	return (rc);
330a0aa776eSAlan Wright }
331a0aa776eSAlan Wright 
332a0aa776eSAlan Wright /*
333a0aa776eSAlan Wright  * Set up IPC connection credentials.
334a0aa776eSAlan Wright  */
335a0aa776eSAlan Wright void
336a0aa776eSAlan Wright smb_ipc_init(void)
337a0aa776eSAlan Wright {
338a0aa776eSAlan Wright 	int rc;
339a0aa776eSAlan Wright 
340a0aa776eSAlan Wright 	(void) rw_wrlock(&smb_ipc_lock);
341a0aa776eSAlan Wright 	bzero(&ipc_info, sizeof (smb_ipc_t));
342a0aa776eSAlan Wright 	bzero(&ipc_orig_info, sizeof (smb_ipc_t));
343a0aa776eSAlan Wright 
344a0aa776eSAlan Wright 	(void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
345a0aa776eSAlan Wright 	rc = smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
346a0aa776eSAlan Wright 	if (rc != 0)
347a0aa776eSAlan Wright 		*ipc_info.passwd = 0;
348a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
349a0aa776eSAlan Wright 
350a0aa776eSAlan Wright }
351a0aa776eSAlan Wright 
352a0aa776eSAlan Wright /*
353a0aa776eSAlan Wright  * Set the IPC username and password hash in memory.  If the domain
354a0aa776eSAlan Wright  * join succeeds, the credentials will be committed for use with
355a0aa776eSAlan Wright  * authenticated IPC.  Otherwise, they should be rolled back.
356a0aa776eSAlan Wright  */
357a0aa776eSAlan Wright void
358a0aa776eSAlan Wright smb_ipc_set(char *plain_user, uint8_t *passwd_hash)
359a0aa776eSAlan Wright {
360a0aa776eSAlan Wright 	(void) rw_wrlock(&smb_ipc_lock);
361a0aa776eSAlan Wright 	(void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user));
362a0aa776eSAlan Wright 	(void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ);
363a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
364a0aa776eSAlan Wright 
365a0aa776eSAlan Wright }
366a0aa776eSAlan Wright 
367a0aa776eSAlan Wright /*
368a0aa776eSAlan Wright  * Save the host credentials to be used for authenticated IPC.
369a0aa776eSAlan Wright  * The credentials are also saved to the original IPC info as
370a0aa776eSAlan Wright  * rollback data in case the join domain process fails later.
371a0aa776eSAlan Wright  */
372a0aa776eSAlan Wright void
373a0aa776eSAlan Wright smb_ipc_commit(void)
374a0aa776eSAlan Wright {
375a0aa776eSAlan Wright 	(void) rw_wrlock(&smb_ipc_lock);
376a0aa776eSAlan Wright 	(void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
377a0aa776eSAlan Wright 	(void) smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
378a0aa776eSAlan Wright 	(void) memcpy(&ipc_orig_info, &ipc_info, sizeof (smb_ipc_t));
379a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
380a0aa776eSAlan Wright }
381a0aa776eSAlan Wright 
382a0aa776eSAlan Wright /*
383a0aa776eSAlan Wright  * Restore the original credentials
384a0aa776eSAlan Wright  */
385a0aa776eSAlan Wright void
386a0aa776eSAlan Wright smb_ipc_rollback(void)
387a0aa776eSAlan Wright {
388a0aa776eSAlan Wright 	(void) rw_wrlock(&smb_ipc_lock);
389a0aa776eSAlan Wright 	(void) strlcpy(ipc_info.user, ipc_orig_info.user,
390a0aa776eSAlan Wright 	    sizeof (ipc_info.user));
391a0aa776eSAlan Wright 	(void) memcpy(ipc_info.passwd, ipc_orig_info.passwd,
392a0aa776eSAlan Wright 	    sizeof (ipc_info.passwd));
393a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
394a0aa776eSAlan Wright }
395a0aa776eSAlan Wright 
396a0aa776eSAlan Wright void
397a0aa776eSAlan Wright smb_ipc_get_user(char *buf, size_t buflen)
398a0aa776eSAlan Wright {
399a0aa776eSAlan Wright 	(void) rw_rdlock(&smb_ipc_lock);
400a0aa776eSAlan Wright 	(void) strlcpy(buf, ipc_info.user, buflen);
401a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
402a0aa776eSAlan Wright }
403a0aa776eSAlan Wright 
404a0aa776eSAlan Wright void
405a0aa776eSAlan Wright smb_ipc_get_passwd(uint8_t *buf, size_t buflen)
406a0aa776eSAlan Wright {
407a0aa776eSAlan Wright 	if (buflen < SMBAUTH_HASH_SZ)
408a0aa776eSAlan Wright 		return;
409a0aa776eSAlan Wright 
410a0aa776eSAlan Wright 	(void) rw_rdlock(&smb_ipc_lock);
411a0aa776eSAlan Wright 	(void) memcpy(buf, ipc_info.passwd, SMBAUTH_HASH_SZ);
412a0aa776eSAlan Wright 	(void) rw_unlock(&smb_ipc_lock);
413a0aa776eSAlan Wright }
414a0aa776eSAlan Wright 
415faa1795aSjb /*
416faa1795aSjb  * smb_match_netlogon_seqnum
417faa1795aSjb  *
418faa1795aSjb  * A sequence number is associated with each machine password property
419faa1795aSjb  * update and the netlogon credential chain setup. If the
420faa1795aSjb  * sequence numbers don't match, a NETLOGON credential chain
421faa1795aSjb  * establishment is required.
422faa1795aSjb  *
423faa1795aSjb  * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise,
424faa1795aSjb  * returns -1.
425faa1795aSjb  */
426faa1795aSjb boolean_t
427faa1795aSjb smb_match_netlogon_seqnum(void)
428faa1795aSjb {
429faa1795aSjb 	int64_t setpasswd_seqnum;
430faa1795aSjb 	int64_t netlogon_seqnum;
431faa1795aSjb 
432faa1795aSjb 	(void) mutex_lock(&seqnum_mtx);
433faa1795aSjb 	(void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum);
434faa1795aSjb 	(void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum);
435faa1795aSjb 	(void) mutex_unlock(&seqnum_mtx);
436faa1795aSjb 	return (setpasswd_seqnum == netlogon_seqnum);
437faa1795aSjb }
438faa1795aSjb 
439faa1795aSjb /*
440faa1795aSjb  * smb_setdomainprops
441faa1795aSjb  *
442faa1795aSjb  * This function should be called after joining an AD to
443faa1795aSjb  * set all the domain related SMF properties.
444faa1795aSjb  *
445faa1795aSjb  * The kpasswd_domain property is the AD domain to which the system
446faa1795aSjb  * is joined via kclient. If this function is invoked by the SMB
447faa1795aSjb  * daemon, fqdn should be set to NULL.
448faa1795aSjb  */
449faa1795aSjb int
450faa1795aSjb smb_setdomainprops(char *fqdn, char *server, char *passwd)
451faa1795aSjb {
452faa1795aSjb 	if (server == NULL || passwd == NULL)
453faa1795aSjb 		return (-1);
454faa1795aSjb 
455faa1795aSjb 	if ((*server == '\0') || (*passwd == '\0'))
456faa1795aSjb 		return (-1);
457faa1795aSjb 
458faa1795aSjb 	if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0))
459faa1795aSjb 		return (-1);
460faa1795aSjb 
461faa1795aSjb 	if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0)
462faa1795aSjb 		return (-1);
463faa1795aSjb 
464faa1795aSjb 	if (smb_set_machine_passwd(passwd) != 0) {
465faa1795aSjb 		syslog(LOG_ERR, "smb_setdomainprops: failed to set"
466faa1795aSjb 		    " machine account password");
467faa1795aSjb 		return (-1);
468faa1795aSjb 	}
469faa1795aSjb 
470faa1795aSjb 	/*
471faa1795aSjb 	 * If we successfully create a trust account, we mark
472faa1795aSjb 	 * ourselves as a domain member in the environment so
473faa1795aSjb 	 * that we use the SAMLOGON version of the NETLOGON
474faa1795aSjb 	 * PDC location protocol.
475faa1795aSjb 	 */
476faa1795aSjb 	(void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE);
477faa1795aSjb 
478faa1795aSjb 	return (0);
479faa1795aSjb }
480faa1795aSjb 
481faa1795aSjb /*
482faa1795aSjb  * smb_update_netlogon_seqnum
483faa1795aSjb  *
484faa1795aSjb  * This function should only be called upon a successful netlogon
485faa1795aSjb  * credential chain establishment to set the sequence number of the
486faa1795aSjb  * netlogon to match with that of the kpasswd.
487faa1795aSjb  */
488faa1795aSjb void
489faa1795aSjb smb_update_netlogon_seqnum(void)
490faa1795aSjb {
491faa1795aSjb 	int64_t num;
492faa1795aSjb 
493faa1795aSjb 	(void) mutex_lock(&seqnum_mtx);
494faa1795aSjb 	(void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
495faa1795aSjb 	(void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num);
496faa1795aSjb 	(void) mutex_unlock(&seqnum_mtx);
497faa1795aSjb }
498faa1795aSjb 
499dc20a302Sas 
500da6c28aaSamw /*
501da6c28aaSamw  * Temporary fbt for dtrace until user space sdt enabled.
502da6c28aaSamw  */
503da6c28aaSamw void
504da6c28aaSamw smb_tracef(const char *fmt, ...)
505da6c28aaSamw {
506da6c28aaSamw 	va_list ap;
507da6c28aaSamw 	char buf[128];
508da6c28aaSamw 
509da6c28aaSamw 	va_start(ap, fmt);
510da6c28aaSamw 	(void) vsnprintf(buf, 128, fmt, ap);
511da6c28aaSamw 	va_end(ap);
512da6c28aaSamw 
513da6c28aaSamw 	smb_trace(buf);
514da6c28aaSamw }
515da6c28aaSamw 
516da6c28aaSamw /*
517da6c28aaSamw  * Temporary fbt for dtrace until user space sdt enabled.
518da6c28aaSamw  */
519da6c28aaSamw void
520da6c28aaSamw smb_trace(const char *s)
521da6c28aaSamw {
522da6c28aaSamw 	syslog(LOG_DEBUG, "%s", s);
523da6c28aaSamw }
5247b59d02dSjb 
5257b59d02dSjb /*
5267b59d02dSjb  * smb_tonetbiosname
5277b59d02dSjb  *
5287b59d02dSjb  * Creates a NetBIOS name based on the given name and suffix.
5297b59d02dSjb  * NetBIOS name is 15 capital characters, padded with space if needed
5307b59d02dSjb  * and the 16th byte is the suffix.
5317b59d02dSjb  */
5327b59d02dSjb void
5337b59d02dSjb smb_tonetbiosname(char *name, char *nb_name, char suffix)
5347b59d02dSjb {
5357b59d02dSjb 	char tmp_name[NETBIOS_NAME_SZ];
536bbf6f00cSJordan Brown 	smb_wchar_t wtmp_name[NETBIOS_NAME_SZ];
5377b59d02dSjb 	int len;
5387b59d02dSjb 	size_t rc;
5397b59d02dSjb 
5407b59d02dSjb 	len = 0;
541bbf6f00cSJordan Brown 	rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
5427b59d02dSjb 
5437b59d02dSjb 	if (rc != (size_t)-1) {
5447b59d02dSjb 		wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
545bbf6f00cSJordan Brown 		rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ,
546bbf6f00cSJordan Brown 		    OEM_CPG_850);
5477b59d02dSjb 		if (rc > 0)
5487b59d02dSjb 			len = strlen(tmp_name);
5497b59d02dSjb 	}
5507b59d02dSjb 
5517b59d02dSjb 	(void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1);
5527b59d02dSjb 	if (len) {
553bbf6f00cSJordan Brown 		(void) smb_strupr(tmp_name);
5547b59d02dSjb 		(void) memcpy(nb_name, tmp_name, len);
5557b59d02dSjb 	}
5567b59d02dSjb 	nb_name[NETBIOS_NAME_SZ - 1] = suffix;
5577b59d02dSjb }
5587b59d02dSjb 
5597b59d02dSjb int
5607f667e74Sjose borrego smb_get_nameservers(smb_inaddr_t *ips, int sz)
5617b59d02dSjb {
5627b59d02dSjb 	union res_sockaddr_union set[MAXNS];
5637b59d02dSjb 	int i, cnt;
5647b59d02dSjb 	struct __res_state res_state;
5657f667e74Sjose borrego 	char ipstr[INET6_ADDRSTRLEN];
5667b59d02dSjb 
5677b59d02dSjb 	if (ips == NULL)
5687b59d02dSjb 		return (0);
5697b59d02dSjb 
5707b59d02dSjb 	bzero(&res_state, sizeof (struct __res_state));
5717b59d02dSjb 	if (res_ninit(&res_state) < 0)
5727b59d02dSjb 		return (0);
5737b59d02dSjb 
5747b59d02dSjb 	cnt = res_getservers(&res_state, set, MAXNS);
5757b59d02dSjb 	for (i = 0; i < cnt; i++) {
5767b59d02dSjb 		if (i >= sz)
5777b59d02dSjb 			break;
5787f667e74Sjose borrego 		ips[i].a_family = AF_INET;
5797f667e74Sjose borrego 		bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, INADDRSZ);
5807f667e74Sjose borrego 		if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr,
5817f667e74Sjose borrego 		    INET_ADDRSTRLEN)) {
5827f667e74Sjose borrego 			syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
5837f667e74Sjose borrego 			continue;
5847f667e74Sjose borrego 		}
5857f667e74Sjose borrego 		ips[i].a_family = AF_INET6;
5867f667e74Sjose borrego 		bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, IPV6_ADDR_LEN);
5877f667e74Sjose borrego 		if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr,
5887f667e74Sjose borrego 		    INET6_ADDRSTRLEN)) {
5897f667e74Sjose borrego 			syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
5907f667e74Sjose borrego 		}
5917b59d02dSjb 	}
5927b59d02dSjb 	res_ndestroy(&res_state);
5937b59d02dSjb 	return (i);
5947b59d02dSjb }
59529bd2886SAlan Wright 
5968d7e4166Sjose borrego /*
5978d7e4166Sjose borrego  * smb_gethostbyname
5988d7e4166Sjose borrego  *
5998d7e4166Sjose borrego  * Looks up a host by the given name. The host entry can come
6008d7e4166Sjose borrego  * from any of the sources for hosts specified in the
6018d7e4166Sjose borrego  * /etc/nsswitch.conf and the NetBIOS cache.
6028d7e4166Sjose borrego  *
6038d7e4166Sjose borrego  * XXX Invokes nbt_name_resolve API once the NBTD is integrated
6048d7e4166Sjose borrego  * to look in the NetBIOS cache if getipnodebyname fails.
6058d7e4166Sjose borrego  *
6068d7e4166Sjose borrego  * Caller should invoke freehostent to free the returned hostent.
6078d7e4166Sjose borrego  */
6088d7e4166Sjose borrego struct hostent *
6098d7e4166Sjose borrego smb_gethostbyname(const char *name, int *err_num)
6108d7e4166Sjose borrego {
6118d7e4166Sjose borrego 	struct hostent *h;
6128d7e4166Sjose borrego 
6138d7e4166Sjose borrego 	h = getipnodebyname(name, AF_INET, 0, err_num);
6147f667e74Sjose borrego 	if ((h == NULL) || h->h_length != INADDRSZ)
6157f667e74Sjose borrego 		h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num);
6168d7e4166Sjose borrego 	return (h);
6178d7e4166Sjose borrego }
6188d7e4166Sjose borrego 
6198d7e4166Sjose borrego /*
6208d7e4166Sjose borrego  * smb_gethostbyaddr
6218d7e4166Sjose borrego  *
6228d7e4166Sjose borrego  * Looks up a host by the given IP address. The host entry can come
6238d7e4166Sjose borrego  * from any of the sources for hosts specified in the
6248d7e4166Sjose borrego  * /etc/nsswitch.conf and the NetBIOS cache.
6258d7e4166Sjose borrego  *
6268d7e4166Sjose borrego  * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated
6278d7e4166Sjose borrego  * to look in the NetBIOS cache if getipnodebyaddr fails.
6288d7e4166Sjose borrego  *
6298d7e4166Sjose borrego  * Caller should invoke freehostent to free the returned hostent.
6308d7e4166Sjose borrego  */
6318d7e4166Sjose borrego struct hostent *
6328d7e4166Sjose borrego smb_gethostbyaddr(const char *addr, int len, int type, int *err_num)
6338d7e4166Sjose borrego {
6348d7e4166Sjose borrego 	struct hostent *h;
6358d7e4166Sjose borrego 
6368d7e4166Sjose borrego 	h = getipnodebyaddr(addr, len, type, err_num);
6378d7e4166Sjose borrego 
6388d7e4166Sjose borrego 	return (h);
6398d7e4166Sjose borrego }
640