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*a90cf9f2SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24da6c28aaSamw */
25da6c28aaSamw
26da6c28aaSamw #include <sys/types.h>
2712b65585SGordon Ross #include <sys/sockio.h>
2812b65585SGordon Ross #include <sys/socket.h>
2912b65585SGordon Ross #include <sys/utsname.h>
3012b65585SGordon Ross
31da6c28aaSamw #include <stdarg.h>
32da6c28aaSamw #include <unistd.h>
33da6c28aaSamw #include <stdlib.h>
34da6c28aaSamw #include <time.h>
35da6c28aaSamw #include <synch.h>
36da6c28aaSamw #include <syslog.h>
37da6c28aaSamw #include <string.h>
38da6c28aaSamw #include <strings.h>
39da6c28aaSamw #include <errno.h>
40da6c28aaSamw #include <net/if.h>
41da6c28aaSamw #include <netdb.h>
42dc20a302Sas200622 #include <netinet/in.h>
43dc20a302Sas200622 #include <arpa/nameser.h>
44dc20a302Sas200622 #include <resolv.h>
4512b65585SGordon Ross
46da6c28aaSamw #include <smbsrv/smbinfo.h>
47da6c28aaSamw #include <smbsrv/netbios.h>
48da6c28aaSamw #include <smbsrv/libsmb.h>
4912b65585SGordon Ross #include <assert.h>
50da6c28aaSamw
51faa1795aSjb150015 static mutex_t seqnum_mtx;
52da6c28aaSamw
53eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /*
54a0aa776eSAlan Wright * IPC connection information that may be passed to the SMB Redirector.
55a0aa776eSAlan Wright */
56a0aa776eSAlan Wright typedef struct {
57a0aa776eSAlan Wright char user[SMB_USERNAME_MAXLEN];
58a0aa776eSAlan Wright uint8_t passwd[SMBAUTH_HASH_SZ];
59a0aa776eSAlan Wright } smb_ipc_t;
60a0aa776eSAlan Wright
61a0aa776eSAlan Wright static smb_ipc_t ipc_info;
62a0aa776eSAlan Wright static smb_ipc_t ipc_orig_info;
63a0aa776eSAlan Wright static rwlock_t smb_ipc_lock;
64a0aa776eSAlan Wright
65a0aa776eSAlan Wright /*
66*a90cf9f2SGordon Ross * These three parameters are all related:
67*a90cf9f2SGordon Ross * skc_initial_credits
68*a90cf9f2SGordon Ross * skc_maximum_credits
69*a90cf9f2SGordon Ross * skc_maxworkers (max worker threads)
70*a90cf9f2SGordon Ross * They must be in non-decreasing order. Get the values in order:
71*a90cf9f2SGordon Ross * maxworkers, maximum_credits, initial_credits
72*a90cf9f2SGordon Ross * enforcing maximum values and relations as we go. Then in the
73*a90cf9f2SGordon Ross * opposite order check minimum values and relations.
74*a90cf9f2SGordon Ross *
75*a90cf9f2SGordon Ross * smb_config_getnum puts a zero in the &citem if it fails getting
76*a90cf9f2SGordon Ross * the parameter value. When fetch parameters for which zero is OK,
77*a90cf9f2SGordon Ross * the return code is intentionally ignored.
78eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States */
79da6c28aaSamw void
smb_load_kconfig(smb_kmod_cfg_t * kcfg)80da6c28aaSamw smb_load_kconfig(smb_kmod_cfg_t *kcfg)
81da6c28aaSamw {
8212b65585SGordon Ross struct utsname uts;
83dc20a302Sas200622 int64_t citem;
84*a90cf9f2SGordon Ross int rc;
85dc20a302Sas200622
86da6c28aaSamw bzero(kcfg, sizeof (smb_kmod_cfg_t));
87da6c28aaSamw
88*a90cf9f2SGordon Ross /*
89*a90cf9f2SGordon Ross * skc_maxworkers (max. no. of taskq worker threads)
90*a90cf9f2SGordon Ross */
91*a90cf9f2SGordon Ross rc = smb_config_getnum(SMB_CI_MAX_WORKERS, &citem);
92*a90cf9f2SGordon Ross if (rc != SMBD_SMF_OK)
93*a90cf9f2SGordon Ross citem = SMB_PI_MAX_WORKERS_DEF;
94*a90cf9f2SGordon Ross if (citem > SMB_PI_MAX_WORKERS_MAX)
95*a90cf9f2SGordon Ross citem = SMB_PI_MAX_WORKERS_MAX;
96dc20a302Sas200622 kcfg->skc_maxworkers = (uint32_t)citem;
97*a90cf9f2SGordon Ross
98*a90cf9f2SGordon Ross /*
99*a90cf9f2SGordon Ross * The largest number of credits we let a single client have.
100*a90cf9f2SGordon Ross * It never makes sense for this to be > max_workers
101*a90cf9f2SGordon Ross */
102*a90cf9f2SGordon Ross rc = smb_config_getnum(SMB_CI_MAXIMUM_CREDITS, &citem);
103*a90cf9f2SGordon Ross if (rc != SMBD_SMF_OK)
104*a90cf9f2SGordon Ross citem = SMB_PI_MAXIMUM_CREDITS_DEF;
105*a90cf9f2SGordon Ross if (citem > SMB_PI_MAXIMUM_CREDITS_MAX)
106*a90cf9f2SGordon Ross citem = SMB_PI_MAXIMUM_CREDITS_MAX;
107*a90cf9f2SGordon Ross kcfg->skc_maximum_credits = (uint16_t)citem;
108*a90cf9f2SGordon Ross if (kcfg->skc_maximum_credits > kcfg->skc_maxworkers)
109*a90cf9f2SGordon Ross kcfg->skc_maximum_credits = (uint16_t)kcfg->skc_maxworkers;
110*a90cf9f2SGordon Ross
111*a90cf9f2SGordon Ross /*
112*a90cf9f2SGordon Ross * The number of credits we give a client initially.
113*a90cf9f2SGordon Ross * Should be enough for a "light" workload, as the
114*a90cf9f2SGordon Ross * client will request additional credits when the
115*a90cf9f2SGordon Ross * workload increases. Must be <= maximum_credits.
116*a90cf9f2SGordon Ross */
117*a90cf9f2SGordon Ross rc = smb_config_getnum(SMB_CI_INITIAL_CREDITS, &citem);
118*a90cf9f2SGordon Ross if (rc != SMBD_SMF_OK)
119*a90cf9f2SGordon Ross citem = SMB_PI_INITIAL_CREDITS_DEF;
120*a90cf9f2SGordon Ross if (citem > SMB_PI_INITIAL_CREDITS_MAX)
121*a90cf9f2SGordon Ross citem = SMB_PI_INITIAL_CREDITS_MAX;
122*a90cf9f2SGordon Ross kcfg->skc_initial_credits = (uint16_t)citem;
123*a90cf9f2SGordon Ross if (kcfg->skc_initial_credits > kcfg->skc_maximum_credits)
124*a90cf9f2SGordon Ross kcfg->skc_initial_credits = kcfg->skc_maximum_credits;
125*a90cf9f2SGordon Ross
126*a90cf9f2SGordon Ross /*
127*a90cf9f2SGordon Ross * Now enforce minimums, smaller to larger.
128*a90cf9f2SGordon Ross */
129*a90cf9f2SGordon Ross if (kcfg->skc_initial_credits < SMB_PI_INITIAL_CREDITS_MIN)
130*a90cf9f2SGordon Ross kcfg->skc_initial_credits = SMB_PI_INITIAL_CREDITS_MIN;
131*a90cf9f2SGordon Ross
132*a90cf9f2SGordon Ross if (kcfg->skc_maximum_credits < SMB_PI_MAXIMUM_CREDITS_MIN)
133*a90cf9f2SGordon Ross kcfg->skc_maximum_credits = SMB_PI_MAXIMUM_CREDITS_MIN;
134*a90cf9f2SGordon Ross if (kcfg->skc_maximum_credits < kcfg->skc_initial_credits)
135*a90cf9f2SGordon Ross kcfg->skc_maximum_credits = kcfg->skc_initial_credits;
136*a90cf9f2SGordon Ross
137*a90cf9f2SGordon Ross if (kcfg->skc_maxworkers < SMB_PI_MAX_WORKERS_MIN)
138*a90cf9f2SGordon Ross kcfg->skc_maxworkers = SMB_PI_MAX_WORKERS_MIN;
139*a90cf9f2SGordon Ross if (kcfg->skc_maxworkers < kcfg->skc_maximum_credits)
140*a90cf9f2SGordon Ross kcfg->skc_maxworkers = kcfg->skc_maximum_credits;
141eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
142dc20a302Sas200622 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem);
143dc20a302Sas200622 kcfg->skc_keepalive = (uint32_t)citem;
144da6c28aaSamw if ((kcfg->skc_keepalive != 0) &&
145da6c28aaSamw (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
146da6c28aaSamw kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
147da6c28aaSamw
148dc20a302Sas200622 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem);
149dc20a302Sas200622 kcfg->skc_maxconnections = (uint32_t)citem;
150dc20a302Sas200622 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON);
151dc20a302Sas200622 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE);
152dc20a302Sas200622 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD);
15383d2dfe6SGordon Ross kcfg->skc_netbios_enable = smb_config_getbool(SMB_CI_NETBIOS_ENABLE);
1547f667e74Sjose borrego kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE);
155cb174861Sjoyce mcintosh kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE);
156dc20a302Sas200622 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
157dc20a302Sas200622 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
1585f1ef25cSAram Hăvărneanu kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS);
159*a90cf9f2SGordon Ross kcfg->skc_max_protocol = smb_config_get_max_protocol();
160da6c28aaSamw kcfg->skc_secmode = smb_config_get_secmode();
161*a90cf9f2SGordon Ross
162b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) smb_getdomainname(kcfg->skc_nbdomain,
163b89a8333Snatalie li - Sun Microsystems - Irvine United States sizeof (kcfg->skc_nbdomain));
164b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) smb_getfqdomainname(kcfg->skc_fqdn,
165b89a8333Snatalie li - Sun Microsystems - Irvine United States sizeof (kcfg->skc_fqdn));
166b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) smb_getnetbiosname(kcfg->skc_hostname,
167b89a8333Snatalie li - Sun Microsystems - Irvine United States sizeof (kcfg->skc_hostname));
168dc20a302Sas200622 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment,
169da6c28aaSamw sizeof (kcfg->skc_system_comment));
1709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_config_get_version(&kcfg->skc_version);
171148c5f43SAlan Wright kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0);
17212b65585SGordon Ross if (smb_config_get_localuuid(kcfg->skc_machine_uuid) < 0) {
17312b65585SGordon Ross syslog(LOG_ERR, "smb_load_kconfig: no machine_uuid");
17412b65585SGordon Ross uuid_generate_time(kcfg->skc_machine_uuid);
17512b65585SGordon Ross }
17612b65585SGordon Ross /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */
17712b65585SGordon Ross
17812b65585SGordon Ross (void) uname(&uts);
17912b65585SGordon Ross (void) snprintf(kcfg->skc_native_os, sizeof (kcfg->skc_native_os),
18012b65585SGordon Ross "%s %s %s", uts.sysname, uts.release, uts.version);
18112b65585SGordon Ross
18212b65585SGordon Ross (void) strlcpy(kcfg->skc_native_lm, "Native SMB service",
18312b65585SGordon Ross sizeof (kcfg->skc_native_lm));
184da6c28aaSamw }
185da6c28aaSamw
186da6c28aaSamw /*
187da6c28aaSamw * Get the current system NetBIOS name. The hostname is truncated at
188da6c28aaSamw * the first `.` or 15 bytes, whichever occurs first, and converted
189da6c28aaSamw * to uppercase (by smb_gethostname). Text that appears after the
190da6c28aaSamw * first '.' is considered to be part of the NetBIOS scope.
191da6c28aaSamw *
192da6c28aaSamw * Returns 0 on success, otherwise -1 to indicate an error.
193da6c28aaSamw */
194da6c28aaSamw int
smb_getnetbiosname(char * buf,size_t buflen)195da6c28aaSamw smb_getnetbiosname(char *buf, size_t buflen)
196da6c28aaSamw {
1979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_gethostname(buf, buflen, SMB_CASE_UPPER) != 0)
198da6c28aaSamw return (-1);
199da6c28aaSamw
200da6c28aaSamw if (buflen >= NETBIOS_NAME_SZ)
201da6c28aaSamw buf[NETBIOS_NAME_SZ - 1] = '\0';
202da6c28aaSamw
203da6c28aaSamw return (0);
204da6c28aaSamw }
205da6c28aaSamw
206da6c28aaSamw /*
207b89a8333Snatalie li - Sun Microsystems - Irvine United States * Get the SAM account of the current system.
208b89a8333Snatalie li - Sun Microsystems - Irvine United States * Returns 0 on success, otherwise, -1 to indicate an error.
209b89a8333Snatalie li - Sun Microsystems - Irvine United States */
210b89a8333Snatalie li - Sun Microsystems - Irvine United States int
smb_getsamaccount(char * buf,size_t buflen)211b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_getsamaccount(char *buf, size_t buflen)
212b89a8333Snatalie li - Sun Microsystems - Irvine United States {
213b89a8333Snatalie li - Sun Microsystems - Irvine United States if (smb_getnetbiosname(buf, buflen - 1) != 0)
214b89a8333Snatalie li - Sun Microsystems - Irvine United States return (-1);
215b89a8333Snatalie li - Sun Microsystems - Irvine United States
216b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) strlcat(buf, "$", buflen);
217b89a8333Snatalie li - Sun Microsystems - Irvine United States return (0);
218b89a8333Snatalie li - Sun Microsystems - Irvine United States }
219b89a8333Snatalie li - Sun Microsystems - Irvine United States
220b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
221da6c28aaSamw * Get the current system node name. The returned name is guaranteed
222da6c28aaSamw * to be null-terminated (gethostname may not null terminate the name).
223da6c28aaSamw * If the hostname has been fully-qualified for some reason, the domain
2249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * part will be removed. The returned hostname is converted to the
2259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * specified case (lower, upper, or preserved).
226da6c28aaSamw *
227da6c28aaSamw * If gethostname fails, the returned buffer will contain an empty
228da6c28aaSamw * string.
229da6c28aaSamw */
230da6c28aaSamw int
smb_gethostname(char * buf,size_t buflen,smb_caseconv_t which)2319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which)
232da6c28aaSamw {
233da6c28aaSamw char *p;
234da6c28aaSamw
235da6c28aaSamw if (buf == NULL || buflen == 0)
236da6c28aaSamw return (-1);
237da6c28aaSamw
238da6c28aaSamw if (gethostname(buf, buflen) != 0) {
239da6c28aaSamw *buf = '\0';
240da6c28aaSamw return (-1);
241da6c28aaSamw }
242da6c28aaSamw
243da6c28aaSamw buf[buflen - 1] = '\0';
244da6c28aaSamw
245da6c28aaSamw if ((p = strchr(buf, '.')) != NULL)
246da6c28aaSamw *p = '\0';
247da6c28aaSamw
2489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States switch (which) {
2499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States case SMB_CASE_LOWER:
2509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_strlwr(buf);
2519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break;
2529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
2539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States case SMB_CASE_UPPER:
254bbf6f00cSJordan Brown (void) smb_strupr(buf);
2559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break;
2569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
2579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States case SMB_CASE_PRESERVE:
2589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States default:
2599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break;
2609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
261da6c28aaSamw
262da6c28aaSamw return (0);
263da6c28aaSamw }
264da6c28aaSamw
265da6c28aaSamw /*
2669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Obtain the fully-qualified name for this machine in lower case. If
2679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * the hostname is fully-qualified, accept it. Otherwise, try to find an
2689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * appropriate domain name to append to the hostname.
269da6c28aaSamw */
270da6c28aaSamw int
smb_getfqhostname(char * buf,size_t buflen)271da6c28aaSamw smb_getfqhostname(char *buf, size_t buflen)
272da6c28aaSamw {
273da6c28aaSamw char hostname[MAXHOSTNAMELEN];
274da6c28aaSamw char domain[MAXHOSTNAMELEN];
275da6c28aaSamw
276da6c28aaSamw hostname[0] = '\0';
277da6c28aaSamw domain[0] = '\0';
278da6c28aaSamw
2799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_gethostname(hostname, MAXHOSTNAMELEN,
2809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_CASE_LOWER) != 0)
281da6c28aaSamw return (-1);
282da6c28aaSamw
283dc20a302Sas200622 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
284da6c28aaSamw return (-1);
285da6c28aaSamw
286da6c28aaSamw if (hostname[0] == '\0')
287da6c28aaSamw return (-1);
288da6c28aaSamw
289da6c28aaSamw if (domain[0] == '\0') {
290da6c28aaSamw (void) strlcpy(buf, hostname, buflen);
291da6c28aaSamw return (0);
292da6c28aaSamw }
293da6c28aaSamw
294da6c28aaSamw (void) snprintf(buf, buflen, "%s.%s", hostname, domain);
295da6c28aaSamw return (0);
296da6c28aaSamw }
297da6c28aaSamw
298da6c28aaSamw /*
299dc20a302Sas200622 * smb_getdomainname
300dc20a302Sas200622 *
301dc20a302Sas200622 * Returns NETBIOS name of the domain if the system is in domain
302dc20a302Sas200622 * mode. Or returns workgroup name if the system is in workgroup
303dc20a302Sas200622 * mode.
304dc20a302Sas200622 */
305dc20a302Sas200622 int
smb_getdomainname(char * buf,size_t buflen)306dc20a302Sas200622 smb_getdomainname(char *buf, size_t buflen)
307dc20a302Sas200622 {
308dc20a302Sas200622 int rc;
309dc20a302Sas200622
310dc20a302Sas200622 if (buf == NULL || buflen == 0)
311dc20a302Sas200622 return (-1);
312dc20a302Sas200622
313dc20a302Sas200622 *buf = '\0';
3148d7e4166Sjose borrego rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen);
315dc20a302Sas200622
3168d7e4166Sjose borrego if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
317dc20a302Sas200622 return (-1);
318dc20a302Sas200622
319dc20a302Sas200622 return (0);
320dc20a302Sas200622 }
321dc20a302Sas200622
322dc20a302Sas200622 /*
323dc20a302Sas200622 * smb_getfqdomainname
324dc20a302Sas200622 *
3258d7e4166Sjose borrego * In the system is in domain mode, the dns_domain property value
3268d7e4166Sjose borrego * is returned. Otherwise, it returns the local domain obtained via
3278d7e4166Sjose borrego * resolver.
328dc20a302Sas200622 *
329dc20a302Sas200622 * Returns 0 upon success. Otherwise, returns -1.
330dc20a302Sas200622 */
331dc20a302Sas200622 int
smb_getfqdomainname(char * buf,size_t buflen)332dc20a302Sas200622 smb_getfqdomainname(char *buf, size_t buflen)
333dc20a302Sas200622 {
3348d7e4166Sjose borrego struct __res_state res_state;
3358d7e4166Sjose borrego int rc;
336dc20a302Sas200622
337dc20a302Sas200622 if (buf == NULL || buflen == 0)
338dc20a302Sas200622 return (-1);
339dc20a302Sas200622
340dc20a302Sas200622 *buf = '\0';
341dc20a302Sas200622 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) {
3428d7e4166Sjose borrego rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen);
343dc20a302Sas200622
3448d7e4166Sjose borrego if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
3458d7e4166Sjose borrego return (-1);
3468d7e4166Sjose borrego } else {
3478d7e4166Sjose borrego bzero(&res_state, sizeof (struct __res_state));
3488d7e4166Sjose borrego if (res_ninit(&res_state))
349dc20a302Sas200622 return (-1);
350dc20a302Sas200622
3518d7e4166Sjose borrego if (*res_state.defdname == '\0') {
3528d7e4166Sjose borrego res_ndestroy(&res_state);
3538d7e4166Sjose borrego return (-1);
354dc20a302Sas200622 }
3558d7e4166Sjose borrego
3568d7e4166Sjose borrego (void) strlcpy(buf, res_state.defdname, buflen);
3578d7e4166Sjose borrego res_ndestroy(&res_state);
3588d7e4166Sjose borrego rc = 0;
359dc20a302Sas200622 }
360dc20a302Sas200622
361dc20a302Sas200622 return (rc);
362dc20a302Sas200622 }
363dc20a302Sas200622
364dc20a302Sas200622
365faa1795aSjb150015 /*
366faa1795aSjb150015 * smb_set_machine_passwd
367faa1795aSjb150015 *
368faa1795aSjb150015 * This function should be used when setting the machine password property.
369faa1795aSjb150015 * The associated sequence number is incremented.
370faa1795aSjb150015 */
371faa1795aSjb150015 static int
smb_set_machine_passwd(char * passwd)372faa1795aSjb150015 smb_set_machine_passwd(char *passwd)
373faa1795aSjb150015 {
374faa1795aSjb150015 int64_t num;
375faa1795aSjb150015 int rc = -1;
376faa1795aSjb150015
377faa1795aSjb150015 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK)
378faa1795aSjb150015 return (-1);
379faa1795aSjb150015
380faa1795aSjb150015 (void) mutex_lock(&seqnum_mtx);
381faa1795aSjb150015 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
382faa1795aSjb150015 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num)
383faa1795aSjb150015 == SMBD_SMF_OK)
384faa1795aSjb150015 rc = 0;
385faa1795aSjb150015 (void) mutex_unlock(&seqnum_mtx);
386faa1795aSjb150015 return (rc);
387faa1795aSjb150015 }
388faa1795aSjb150015
389a0aa776eSAlan Wright static int
smb_get_machine_passwd(uint8_t * buf,size_t buflen)390a0aa776eSAlan Wright smb_get_machine_passwd(uint8_t *buf, size_t buflen)
391a0aa776eSAlan Wright {
392a0aa776eSAlan Wright char pwd[SMB_PASSWD_MAXLEN + 1];
393a0aa776eSAlan Wright int rc;
394a0aa776eSAlan Wright
395a0aa776eSAlan Wright if (buflen < SMBAUTH_HASH_SZ)
396a0aa776eSAlan Wright return (-1);
397a0aa776eSAlan Wright
398a0aa776eSAlan Wright rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd));
399a0aa776eSAlan Wright if ((rc != SMBD_SMF_OK) || *pwd == '\0')
400a0aa776eSAlan Wright return (-1);
401a0aa776eSAlan Wright
402a0aa776eSAlan Wright if (smb_auth_ntlm_hash(pwd, buf) != 0)
403a0aa776eSAlan Wright return (-1);
404a0aa776eSAlan Wright
405a0aa776eSAlan Wright return (rc);
406a0aa776eSAlan Wright }
407a0aa776eSAlan Wright
408a0aa776eSAlan Wright /*
409a0aa776eSAlan Wright * Set up IPC connection credentials.
410a0aa776eSAlan Wright */
411a0aa776eSAlan Wright void
smb_ipc_init(void)412a0aa776eSAlan Wright smb_ipc_init(void)
413a0aa776eSAlan Wright {
414a0aa776eSAlan Wright int rc;
415a0aa776eSAlan Wright
416a0aa776eSAlan Wright (void) rw_wrlock(&smb_ipc_lock);
417a0aa776eSAlan Wright bzero(&ipc_info, sizeof (smb_ipc_t));
418a0aa776eSAlan Wright bzero(&ipc_orig_info, sizeof (smb_ipc_t));
419a0aa776eSAlan Wright
420a0aa776eSAlan Wright (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
421a0aa776eSAlan Wright rc = smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
422a0aa776eSAlan Wright if (rc != 0)
423a0aa776eSAlan Wright *ipc_info.passwd = 0;
424a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
425a0aa776eSAlan Wright
426a0aa776eSAlan Wright }
427a0aa776eSAlan Wright
428a0aa776eSAlan Wright /*
429a0aa776eSAlan Wright * Set the IPC username and password hash in memory. If the domain
430a0aa776eSAlan Wright * join succeeds, the credentials will be committed for use with
431a0aa776eSAlan Wright * authenticated IPC. Otherwise, they should be rolled back.
432a0aa776eSAlan Wright */
433a0aa776eSAlan Wright void
smb_ipc_set(char * plain_user,uint8_t * passwd_hash)434a0aa776eSAlan Wright smb_ipc_set(char *plain_user, uint8_t *passwd_hash)
435a0aa776eSAlan Wright {
436a0aa776eSAlan Wright (void) rw_wrlock(&smb_ipc_lock);
437a0aa776eSAlan Wright (void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user));
438a0aa776eSAlan Wright (void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ);
439a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
440a0aa776eSAlan Wright
441a0aa776eSAlan Wright }
442a0aa776eSAlan Wright
443a0aa776eSAlan Wright /*
444a0aa776eSAlan Wright * Save the host credentials to be used for authenticated IPC.
445a0aa776eSAlan Wright * The credentials are also saved to the original IPC info as
446a0aa776eSAlan Wright * rollback data in case the join domain process fails later.
447a0aa776eSAlan Wright */
448a0aa776eSAlan Wright void
smb_ipc_commit(void)449a0aa776eSAlan Wright smb_ipc_commit(void)
450a0aa776eSAlan Wright {
451a0aa776eSAlan Wright (void) rw_wrlock(&smb_ipc_lock);
452a0aa776eSAlan Wright (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
453a0aa776eSAlan Wright (void) smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
454a0aa776eSAlan Wright (void) memcpy(&ipc_orig_info, &ipc_info, sizeof (smb_ipc_t));
455a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
456a0aa776eSAlan Wright }
457a0aa776eSAlan Wright
458a0aa776eSAlan Wright /*
459a0aa776eSAlan Wright * Restore the original credentials
460a0aa776eSAlan Wright */
461a0aa776eSAlan Wright void
smb_ipc_rollback(void)462a0aa776eSAlan Wright smb_ipc_rollback(void)
463a0aa776eSAlan Wright {
464a0aa776eSAlan Wright (void) rw_wrlock(&smb_ipc_lock);
465a0aa776eSAlan Wright (void) strlcpy(ipc_info.user, ipc_orig_info.user,
466a0aa776eSAlan Wright sizeof (ipc_info.user));
467a0aa776eSAlan Wright (void) memcpy(ipc_info.passwd, ipc_orig_info.passwd,
468a0aa776eSAlan Wright sizeof (ipc_info.passwd));
469a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
470a0aa776eSAlan Wright }
471a0aa776eSAlan Wright
472a0aa776eSAlan Wright void
smb_ipc_get_user(char * buf,size_t buflen)473a0aa776eSAlan Wright smb_ipc_get_user(char *buf, size_t buflen)
474a0aa776eSAlan Wright {
475a0aa776eSAlan Wright (void) rw_rdlock(&smb_ipc_lock);
476a0aa776eSAlan Wright (void) strlcpy(buf, ipc_info.user, buflen);
477a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
478a0aa776eSAlan Wright }
479a0aa776eSAlan Wright
480a0aa776eSAlan Wright void
smb_ipc_get_passwd(uint8_t * buf,size_t buflen)481a0aa776eSAlan Wright smb_ipc_get_passwd(uint8_t *buf, size_t buflen)
482a0aa776eSAlan Wright {
483a0aa776eSAlan Wright if (buflen < SMBAUTH_HASH_SZ)
484a0aa776eSAlan Wright return;
485a0aa776eSAlan Wright
486a0aa776eSAlan Wright (void) rw_rdlock(&smb_ipc_lock);
487a0aa776eSAlan Wright (void) memcpy(buf, ipc_info.passwd, SMBAUTH_HASH_SZ);
488a0aa776eSAlan Wright (void) rw_unlock(&smb_ipc_lock);
489a0aa776eSAlan Wright }
490a0aa776eSAlan Wright
491faa1795aSjb150015 /*
492faa1795aSjb150015 * smb_match_netlogon_seqnum
493faa1795aSjb150015 *
494faa1795aSjb150015 * A sequence number is associated with each machine password property
495faa1795aSjb150015 * update and the netlogon credential chain setup. If the
496faa1795aSjb150015 * sequence numbers don't match, a NETLOGON credential chain
497faa1795aSjb150015 * establishment is required.
498faa1795aSjb150015 *
499faa1795aSjb150015 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise,
500faa1795aSjb150015 * returns -1.
501faa1795aSjb150015 */
502faa1795aSjb150015 boolean_t
smb_match_netlogon_seqnum(void)503faa1795aSjb150015 smb_match_netlogon_seqnum(void)
504faa1795aSjb150015 {
505faa1795aSjb150015 int64_t setpasswd_seqnum;
506faa1795aSjb150015 int64_t netlogon_seqnum;
507faa1795aSjb150015
508faa1795aSjb150015 (void) mutex_lock(&seqnum_mtx);
509faa1795aSjb150015 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum);
510faa1795aSjb150015 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum);
511faa1795aSjb150015 (void) mutex_unlock(&seqnum_mtx);
512faa1795aSjb150015 return (setpasswd_seqnum == netlogon_seqnum);
513faa1795aSjb150015 }
514faa1795aSjb150015
515faa1795aSjb150015 /*
516faa1795aSjb150015 * smb_setdomainprops
517faa1795aSjb150015 *
518faa1795aSjb150015 * This function should be called after joining an AD to
519faa1795aSjb150015 * set all the domain related SMF properties.
520faa1795aSjb150015 *
521faa1795aSjb150015 * The kpasswd_domain property is the AD domain to which the system
522faa1795aSjb150015 * is joined via kclient. If this function is invoked by the SMB
523faa1795aSjb150015 * daemon, fqdn should be set to NULL.
524faa1795aSjb150015 */
525faa1795aSjb150015 int
smb_setdomainprops(char * fqdn,char * server,char * passwd)526faa1795aSjb150015 smb_setdomainprops(char *fqdn, char *server, char *passwd)
527faa1795aSjb150015 {
528faa1795aSjb150015 if (server == NULL || passwd == NULL)
529faa1795aSjb150015 return (-1);
530faa1795aSjb150015
531faa1795aSjb150015 if ((*server == '\0') || (*passwd == '\0'))
532faa1795aSjb150015 return (-1);
533faa1795aSjb150015
534faa1795aSjb150015 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0))
535faa1795aSjb150015 return (-1);
536faa1795aSjb150015
537faa1795aSjb150015 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0)
538faa1795aSjb150015 return (-1);
539faa1795aSjb150015
540faa1795aSjb150015 if (smb_set_machine_passwd(passwd) != 0) {
541faa1795aSjb150015 syslog(LOG_ERR, "smb_setdomainprops: failed to set"
542faa1795aSjb150015 " machine account password");
543faa1795aSjb150015 return (-1);
544faa1795aSjb150015 }
545faa1795aSjb150015
546faa1795aSjb150015 /*
547faa1795aSjb150015 * If we successfully create a trust account, we mark
548faa1795aSjb150015 * ourselves as a domain member in the environment so
549faa1795aSjb150015 * that we use the SAMLOGON version of the NETLOGON
550faa1795aSjb150015 * PDC location protocol.
551faa1795aSjb150015 */
552faa1795aSjb150015 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE);
553faa1795aSjb150015
554faa1795aSjb150015 return (0);
555faa1795aSjb150015 }
556faa1795aSjb150015
557faa1795aSjb150015 /*
558faa1795aSjb150015 * smb_update_netlogon_seqnum
559faa1795aSjb150015 *
560faa1795aSjb150015 * This function should only be called upon a successful netlogon
561faa1795aSjb150015 * credential chain establishment to set the sequence number of the
562faa1795aSjb150015 * netlogon to match with that of the kpasswd.
563faa1795aSjb150015 */
564faa1795aSjb150015 void
smb_update_netlogon_seqnum(void)565faa1795aSjb150015 smb_update_netlogon_seqnum(void)
566faa1795aSjb150015 {
567faa1795aSjb150015 int64_t num;
568faa1795aSjb150015
569faa1795aSjb150015 (void) mutex_lock(&seqnum_mtx);
570faa1795aSjb150015 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
571faa1795aSjb150015 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num);
572faa1795aSjb150015 (void) mutex_unlock(&seqnum_mtx);
573faa1795aSjb150015 }
574faa1795aSjb150015
575dc20a302Sas200622
576dc20a302Sas200622 /*
577da6c28aaSamw * Temporary fbt for dtrace until user space sdt enabled.
578da6c28aaSamw */
579da6c28aaSamw void
smb_tracef(const char * fmt,...)580da6c28aaSamw smb_tracef(const char *fmt, ...)
581da6c28aaSamw {
582da6c28aaSamw va_list ap;
583da6c28aaSamw char buf[128];
584da6c28aaSamw
585da6c28aaSamw va_start(ap, fmt);
586da6c28aaSamw (void) vsnprintf(buf, 128, fmt, ap);
587da6c28aaSamw va_end(ap);
588da6c28aaSamw
589da6c28aaSamw smb_trace(buf);
590da6c28aaSamw }
591da6c28aaSamw
592da6c28aaSamw /*
593da6c28aaSamw * Temporary fbt for dtrace until user space sdt enabled.
594b819cea2SGordon Ross *
595b819cea2SGordon Ross * This function is designed to be used with dtrace, i.e. see:
596b819cea2SGordon Ross * usr/src/cmd/smbsrv/dtrace/smbd-all.d
597b819cea2SGordon Ross *
598b819cea2SGordon Ross * Outside of dtrace, the messages passed to this function usually
599b819cea2SGordon Ross * lack sufficient context to be useful, so we don't log them.
600da6c28aaSamw */
601b819cea2SGordon Ross /* ARGSUSED */
602da6c28aaSamw void
smb_trace(const char * s)603da6c28aaSamw smb_trace(const char *s)
604da6c28aaSamw {
605da6c28aaSamw }
6067b59d02dSjb150015
6077b59d02dSjb150015 /*
6087b59d02dSjb150015 * smb_tonetbiosname
6097b59d02dSjb150015 *
6107b59d02dSjb150015 * Creates a NetBIOS name based on the given name and suffix.
6117b59d02dSjb150015 * NetBIOS name is 15 capital characters, padded with space if needed
6127b59d02dSjb150015 * and the 16th byte is the suffix.
6137b59d02dSjb150015 */
6147b59d02dSjb150015 void
smb_tonetbiosname(char * name,char * nb_name,char suffix)6157b59d02dSjb150015 smb_tonetbiosname(char *name, char *nb_name, char suffix)
6167b59d02dSjb150015 {
6177b59d02dSjb150015 char tmp_name[NETBIOS_NAME_SZ];
618bbf6f00cSJordan Brown smb_wchar_t wtmp_name[NETBIOS_NAME_SZ];
6197b59d02dSjb150015 int len;
6207b59d02dSjb150015 size_t rc;
6217b59d02dSjb150015
6227b59d02dSjb150015 len = 0;
623bbf6f00cSJordan Brown rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
6247b59d02dSjb150015
6257b59d02dSjb150015 if (rc != (size_t)-1) {
6267b59d02dSjb150015 wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
627bbf6f00cSJordan Brown rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ,
628bbf6f00cSJordan Brown OEM_CPG_850);
6297b59d02dSjb150015 if (rc > 0)
6307b59d02dSjb150015 len = strlen(tmp_name);
6317b59d02dSjb150015 }
6327b59d02dSjb150015
6337b59d02dSjb150015 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1);
6347b59d02dSjb150015 if (len) {
635bbf6f00cSJordan Brown (void) smb_strupr(tmp_name);
6367b59d02dSjb150015 (void) memcpy(nb_name, tmp_name, len);
6377b59d02dSjb150015 }
6387b59d02dSjb150015 nb_name[NETBIOS_NAME_SZ - 1] = suffix;
6397b59d02dSjb150015 }
6407b59d02dSjb150015
6417b59d02dSjb150015 int
smb_get_nameservers(smb_inaddr_t * ips,int sz)6427f667e74Sjose borrego smb_get_nameservers(smb_inaddr_t *ips, int sz)
6437b59d02dSjb150015 {
6447b59d02dSjb150015 union res_sockaddr_union set[MAXNS];
6457b59d02dSjb150015 int i, cnt;
6467b59d02dSjb150015 struct __res_state res_state;
6477f667e74Sjose borrego char ipstr[INET6_ADDRSTRLEN];
6487b59d02dSjb150015
6497b59d02dSjb150015 if (ips == NULL)
6507b59d02dSjb150015 return (0);
6517b59d02dSjb150015
6527b59d02dSjb150015 bzero(&res_state, sizeof (struct __res_state));
6537b59d02dSjb150015 if (res_ninit(&res_state) < 0)
6547b59d02dSjb150015 return (0);
6557b59d02dSjb150015
6567b59d02dSjb150015 cnt = res_getservers(&res_state, set, MAXNS);
6577b59d02dSjb150015 for (i = 0; i < cnt; i++) {
6587b59d02dSjb150015 if (i >= sz)
6597b59d02dSjb150015 break;
6607f667e74Sjose borrego ips[i].a_family = AF_INET;
661b819cea2SGordon Ross bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, NS_INADDRSZ);
6627f667e74Sjose borrego if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr,
6637f667e74Sjose borrego INET_ADDRSTRLEN)) {
6647f667e74Sjose borrego syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
6657f667e74Sjose borrego continue;
6667b59d02dSjb150015 }
6677f667e74Sjose borrego ips[i].a_family = AF_INET6;
668b819cea2SGordon Ross bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, NS_IN6ADDRSZ);
6697f667e74Sjose borrego if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr,
6707f667e74Sjose borrego INET6_ADDRSTRLEN)) {
6717f667e74Sjose borrego syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
6727f667e74Sjose borrego }
6737f667e74Sjose borrego }
6747b59d02dSjb150015 res_ndestroy(&res_state);
6757b59d02dSjb150015 return (i);
6767b59d02dSjb150015 }
67729bd2886SAlan Wright
6788d7e4166Sjose borrego /*
6798d7e4166Sjose borrego * smb_gethostbyname
6808d7e4166Sjose borrego *
6818d7e4166Sjose borrego * Looks up a host by the given name. The host entry can come
6828d7e4166Sjose borrego * from any of the sources for hosts specified in the
6838d7e4166Sjose borrego * /etc/nsswitch.conf and the NetBIOS cache.
6848d7e4166Sjose borrego *
6858d7e4166Sjose borrego * XXX Invokes nbt_name_resolve API once the NBTD is integrated
6868d7e4166Sjose borrego * to look in the NetBIOS cache if getipnodebyname fails.
6878d7e4166Sjose borrego *
6888d7e4166Sjose borrego * Caller should invoke freehostent to free the returned hostent.
6898d7e4166Sjose borrego */
6908d7e4166Sjose borrego struct hostent *
smb_gethostbyname(const char * name,int * err_num)6918d7e4166Sjose borrego smb_gethostbyname(const char *name, int *err_num)
6928d7e4166Sjose borrego {
6938d7e4166Sjose borrego struct hostent *h;
6948d7e4166Sjose borrego
6958d7e4166Sjose borrego h = getipnodebyname(name, AF_INET, 0, err_num);
6967f667e74Sjose borrego if ((h == NULL) || h->h_length != INADDRSZ)
6977f667e74Sjose borrego h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num);
6988d7e4166Sjose borrego return (h);
6998d7e4166Sjose borrego }
7008d7e4166Sjose borrego
7018d7e4166Sjose borrego /*
7028d7e4166Sjose borrego * smb_gethostbyaddr
7038d7e4166Sjose borrego *
7048d7e4166Sjose borrego * Looks up a host by the given IP address. The host entry can come
7058d7e4166Sjose borrego * from any of the sources for hosts specified in the
7068d7e4166Sjose borrego * /etc/nsswitch.conf and the NetBIOS cache.
7078d7e4166Sjose borrego *
7088d7e4166Sjose borrego * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated
7098d7e4166Sjose borrego * to look in the NetBIOS cache if getipnodebyaddr fails.
7108d7e4166Sjose borrego *
7118d7e4166Sjose borrego * Caller should invoke freehostent to free the returned hostent.
7128d7e4166Sjose borrego */
7138d7e4166Sjose borrego struct hostent *
smb_gethostbyaddr(const char * addr,int len,int type,int * err_num)7148d7e4166Sjose borrego smb_gethostbyaddr(const char *addr, int len, int type, int *err_num)
7158d7e4166Sjose borrego {
7168d7e4166Sjose borrego struct hostent *h;
7178d7e4166Sjose borrego
7188d7e4166Sjose borrego h = getipnodebyaddr(addr, len, type, err_num);
7198d7e4166Sjose borrego
7208d7e4166Sjose borrego return (h);
7218d7e4166Sjose borrego }
722