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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/sockio.h>
28 #include <sys/socket.h>
29 #include <sys/utsname.h>
42 #include <netinet/in.h>
43 #include <arpa/nameser.h>
46 #include <smbsrv/smbinfo.h>
47 #include <smbsrv/netbios.h>
48 #include <smbsrv/libsmb.h>
51 static mutex_t seqnum_mtx
;
54 * IPC connection information that may be passed to the SMB Redirector.
57 char user
[SMB_USERNAME_MAXLEN
];
58 uint8_t passwd
[SMBAUTH_HASH_SZ
];
61 static smb_ipc_t ipc_info
;
62 static smb_ipc_t ipc_orig_info
;
63 static rwlock_t smb_ipc_lock
;
66 * These three parameters are all related:
69 * skc_maxworkers (max worker threads)
70 * They must be in non-decreasing order. Get the values in order:
71 * maxworkers, maximum_credits, initial_credits
72 * enforcing maximum values and relations as we go. Then in the
73 * opposite order check minimum values and relations.
75 * smb_config_getnum puts a zero in the &citem if it fails getting
76 * the parameter value. When fetch parameters for which zero is OK,
77 * the return code is intentionally ignored.
80 smb_load_kconfig(smb_kmod_cfg_t
*kcfg
)
86 bzero(kcfg
, sizeof (smb_kmod_cfg_t
));
89 * skc_maxworkers (max. no. of taskq worker threads)
91 rc
= smb_config_getnum(SMB_CI_MAX_WORKERS
, &citem
);
92 if (rc
!= SMBD_SMF_OK
)
93 citem
= SMB_PI_MAX_WORKERS_DEF
;
94 if (citem
> SMB_PI_MAX_WORKERS_MAX
)
95 citem
= SMB_PI_MAX_WORKERS_MAX
;
96 kcfg
->skc_maxworkers
= (uint32_t)citem
;
99 * The largest number of credits we let a single client have.
100 * It never makes sense for this to be > max_workers
102 rc
= smb_config_getnum(SMB_CI_MAXIMUM_CREDITS
, &citem
);
103 if (rc
!= SMBD_SMF_OK
)
104 citem
= SMB_PI_MAXIMUM_CREDITS_DEF
;
105 if (citem
> SMB_PI_MAXIMUM_CREDITS_MAX
)
106 citem
= SMB_PI_MAXIMUM_CREDITS_MAX
;
107 kcfg
->skc_maximum_credits
= (uint16_t)citem
;
108 if (kcfg
->skc_maximum_credits
> kcfg
->skc_maxworkers
)
109 kcfg
->skc_maximum_credits
= (uint16_t)kcfg
->skc_maxworkers
;
112 * The number of credits we give a client initially.
113 * Should be enough for a "light" workload, as the
114 * client will request additional credits when the
115 * workload increases. Must be <= maximum_credits.
117 rc
= smb_config_getnum(SMB_CI_INITIAL_CREDITS
, &citem
);
118 if (rc
!= SMBD_SMF_OK
)
119 citem
= SMB_PI_INITIAL_CREDITS_DEF
;
120 if (citem
> SMB_PI_INITIAL_CREDITS_MAX
)
121 citem
= SMB_PI_INITIAL_CREDITS_MAX
;
122 kcfg
->skc_initial_credits
= (uint16_t)citem
;
123 if (kcfg
->skc_initial_credits
> kcfg
->skc_maximum_credits
)
124 kcfg
->skc_initial_credits
= kcfg
->skc_maximum_credits
;
127 * Now enforce minimums, smaller to larger.
129 if (kcfg
->skc_initial_credits
< SMB_PI_INITIAL_CREDITS_MIN
)
130 kcfg
->skc_initial_credits
= SMB_PI_INITIAL_CREDITS_MIN
;
132 if (kcfg
->skc_maximum_credits
< SMB_PI_MAXIMUM_CREDITS_MIN
)
133 kcfg
->skc_maximum_credits
= SMB_PI_MAXIMUM_CREDITS_MIN
;
134 if (kcfg
->skc_maximum_credits
< kcfg
->skc_initial_credits
)
135 kcfg
->skc_maximum_credits
= kcfg
->skc_initial_credits
;
137 if (kcfg
->skc_maxworkers
< SMB_PI_MAX_WORKERS_MIN
)
138 kcfg
->skc_maxworkers
= SMB_PI_MAX_WORKERS_MIN
;
139 if (kcfg
->skc_maxworkers
< kcfg
->skc_maximum_credits
)
140 kcfg
->skc_maxworkers
= kcfg
->skc_maximum_credits
;
142 (void) smb_config_getnum(SMB_CI_KEEPALIVE
, &citem
);
143 kcfg
->skc_keepalive
= (uint32_t)citem
;
144 if ((kcfg
->skc_keepalive
!= 0) &&
145 (kcfg
->skc_keepalive
< SMB_PI_KEEP_ALIVE_MIN
))
146 kcfg
->skc_keepalive
= SMB_PI_KEEP_ALIVE_MIN
;
148 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS
, &citem
);
149 kcfg
->skc_maxconnections
= (uint32_t)citem
;
150 kcfg
->skc_restrict_anon
= smb_config_getbool(SMB_CI_RESTRICT_ANON
);
151 kcfg
->skc_signing_enable
= smb_config_getbool(SMB_CI_SIGNING_ENABLE
);
152 kcfg
->skc_signing_required
= smb_config_getbool(SMB_CI_SIGNING_REQD
);
153 kcfg
->skc_netbios_enable
= smb_config_getbool(SMB_CI_NETBIOS_ENABLE
);
154 kcfg
->skc_ipv6_enable
= smb_config_getbool(SMB_CI_IPV6_ENABLE
);
155 kcfg
->skc_print_enable
= smb_config_getbool(SMB_CI_PRINT_ENABLE
);
156 kcfg
->skc_oplock_enable
= smb_config_getbool(SMB_CI_OPLOCK_ENABLE
);
157 kcfg
->skc_sync_enable
= smb_config_getbool(SMB_CI_SYNC_ENABLE
);
158 kcfg
->skc_traverse_mounts
= smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS
);
159 kcfg
->skc_max_protocol
= smb_config_get_max_protocol();
160 kcfg
->skc_secmode
= smb_config_get_secmode();
162 (void) smb_getdomainname(kcfg
->skc_nbdomain
,
163 sizeof (kcfg
->skc_nbdomain
));
164 (void) smb_getfqdomainname(kcfg
->skc_fqdn
,
165 sizeof (kcfg
->skc_fqdn
));
166 (void) smb_getnetbiosname(kcfg
->skc_hostname
,
167 sizeof (kcfg
->skc_hostname
));
168 (void) smb_config_getstr(SMB_CI_SYS_CMNT
, kcfg
->skc_system_comment
,
169 sizeof (kcfg
->skc_system_comment
));
170 smb_config_get_version(&kcfg
->skc_version
);
171 kcfg
->skc_execflags
= smb_config_get_execinfo(NULL
, NULL
, 0);
172 if (smb_config_get_localuuid(kcfg
->skc_machine_uuid
) < 0) {
173 syslog(LOG_ERR
, "smb_load_kconfig: no machine_uuid");
174 uuid_generate_time(kcfg
->skc_machine_uuid
);
176 /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */
179 (void) snprintf(kcfg
->skc_native_os
, sizeof (kcfg
->skc_native_os
),
180 "%s %s %s", uts
.sysname
, uts
.release
, uts
.version
);
182 (void) strlcpy(kcfg
->skc_native_lm
, "Native SMB service",
183 sizeof (kcfg
->skc_native_lm
));
187 * Get the current system NetBIOS name. The hostname is truncated at
188 * the first `.` or 15 bytes, whichever occurs first, and converted
189 * to uppercase (by smb_gethostname). Text that appears after the
190 * first '.' is considered to be part of the NetBIOS scope.
192 * Returns 0 on success, otherwise -1 to indicate an error.
195 smb_getnetbiosname(char *buf
, size_t buflen
)
197 if (smb_gethostname(buf
, buflen
, SMB_CASE_UPPER
) != 0)
200 if (buflen
>= NETBIOS_NAME_SZ
)
201 buf
[NETBIOS_NAME_SZ
- 1] = '\0';
207 * Get the SAM account of the current system.
208 * Returns 0 on success, otherwise, -1 to indicate an error.
211 smb_getsamaccount(char *buf
, size_t buflen
)
213 if (smb_getnetbiosname(buf
, buflen
- 1) != 0)
216 (void) strlcat(buf
, "$", buflen
);
221 * Get the current system node name. The returned name is guaranteed
222 * to be null-terminated (gethostname may not null terminate the name).
223 * If the hostname has been fully-qualified for some reason, the domain
224 * part will be removed. The returned hostname is converted to the
225 * specified case (lower, upper, or preserved).
227 * If gethostname fails, the returned buffer will contain an empty
231 smb_gethostname(char *buf
, size_t buflen
, smb_caseconv_t which
)
235 if (buf
== NULL
|| buflen
== 0)
238 if (gethostname(buf
, buflen
) != 0) {
243 buf
[buflen
- 1] = '\0';
245 if ((p
= strchr(buf
, '.')) != NULL
)
250 (void) smb_strlwr(buf
);
254 (void) smb_strupr(buf
);
257 case SMB_CASE_PRESERVE
:
266 * Obtain the fully-qualified name for this machine in lower case. If
267 * the hostname is fully-qualified, accept it. Otherwise, try to find an
268 * appropriate domain name to append to the hostname.
271 smb_getfqhostname(char *buf
, size_t buflen
)
273 char hostname
[MAXHOSTNAMELEN
];
274 char domain
[MAXHOSTNAMELEN
];
279 if (smb_gethostname(hostname
, MAXHOSTNAMELEN
,
280 SMB_CASE_LOWER
) != 0)
283 if (smb_getfqdomainname(domain
, MAXHOSTNAMELEN
) != 0)
286 if (hostname
[0] == '\0')
289 if (domain
[0] == '\0') {
290 (void) strlcpy(buf
, hostname
, buflen
);
294 (void) snprintf(buf
, buflen
, "%s.%s", hostname
, domain
);
301 * Returns NETBIOS name of the domain if the system is in domain
302 * mode. Or returns workgroup name if the system is in workgroup
306 smb_getdomainname(char *buf
, size_t buflen
)
310 if (buf
== NULL
|| buflen
== 0)
314 rc
= smb_config_getstr(SMB_CI_DOMAIN_NAME
, buf
, buflen
);
316 if ((rc
!= SMBD_SMF_OK
) || (*buf
== '\0'))
323 * smb_getfqdomainname
325 * In the system is in domain mode, the dns_domain property value
326 * is returned. Otherwise, it returns the local domain obtained via
329 * Returns 0 upon success. Otherwise, returns -1.
332 smb_getfqdomainname(char *buf
, size_t buflen
)
334 struct __res_state res_state
;
337 if (buf
== NULL
|| buflen
== 0)
341 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN
) {
342 rc
= smb_config_getstr(SMB_CI_DOMAIN_FQDN
, buf
, buflen
);
344 if ((rc
!= SMBD_SMF_OK
) || (*buf
== '\0'))
347 bzero(&res_state
, sizeof (struct __res_state
));
348 if (res_ninit(&res_state
))
351 if (*res_state
.defdname
== '\0') {
352 res_ndestroy(&res_state
);
356 (void) strlcpy(buf
, res_state
.defdname
, buflen
);
357 res_ndestroy(&res_state
);
366 * smb_set_machine_passwd
368 * This function should be used when setting the machine password property.
369 * The associated sequence number is incremented.
372 smb_set_machine_passwd(char *passwd
)
377 if (smb_config_set(SMB_CI_MACHINE_PASSWD
, passwd
) != SMBD_SMF_OK
)
380 (void) mutex_lock(&seqnum_mtx
);
381 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM
, &num
);
382 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM
, ++num
)
385 (void) mutex_unlock(&seqnum_mtx
);
390 smb_get_machine_passwd(uint8_t *buf
, size_t buflen
)
392 char pwd
[SMB_PASSWD_MAXLEN
+ 1];
395 if (buflen
< SMBAUTH_HASH_SZ
)
398 rc
= smb_config_getstr(SMB_CI_MACHINE_PASSWD
, pwd
, sizeof (pwd
));
399 if ((rc
!= SMBD_SMF_OK
) || *pwd
== '\0')
402 if (smb_auth_ntlm_hash(pwd
, buf
) != 0)
409 * Set up IPC connection credentials.
416 (void) rw_wrlock(&smb_ipc_lock
);
417 bzero(&ipc_info
, sizeof (smb_ipc_t
));
418 bzero(&ipc_orig_info
, sizeof (smb_ipc_t
));
420 (void) smb_getsamaccount(ipc_info
.user
, SMB_USERNAME_MAXLEN
);
421 rc
= smb_get_machine_passwd(ipc_info
.passwd
, SMBAUTH_HASH_SZ
);
423 *ipc_info
.passwd
= 0;
424 (void) rw_unlock(&smb_ipc_lock
);
429 * Set the IPC username and password hash in memory. If the domain
430 * join succeeds, the credentials will be committed for use with
431 * authenticated IPC. Otherwise, they should be rolled back.
434 smb_ipc_set(char *plain_user
, uint8_t *passwd_hash
)
436 (void) rw_wrlock(&smb_ipc_lock
);
437 (void) strlcpy(ipc_info
.user
, plain_user
, sizeof (ipc_info
.user
));
438 (void) memcpy(ipc_info
.passwd
, passwd_hash
, SMBAUTH_HASH_SZ
);
439 (void) rw_unlock(&smb_ipc_lock
);
444 * Save the host credentials to be used for authenticated IPC.
445 * The credentials are also saved to the original IPC info as
446 * rollback data in case the join domain process fails later.
451 (void) rw_wrlock(&smb_ipc_lock
);
452 (void) smb_getsamaccount(ipc_info
.user
, SMB_USERNAME_MAXLEN
);
453 (void) smb_get_machine_passwd(ipc_info
.passwd
, SMBAUTH_HASH_SZ
);
454 (void) memcpy(&ipc_orig_info
, &ipc_info
, sizeof (smb_ipc_t
));
455 (void) rw_unlock(&smb_ipc_lock
);
459 * Restore the original credentials
462 smb_ipc_rollback(void)
464 (void) rw_wrlock(&smb_ipc_lock
);
465 (void) strlcpy(ipc_info
.user
, ipc_orig_info
.user
,
466 sizeof (ipc_info
.user
));
467 (void) memcpy(ipc_info
.passwd
, ipc_orig_info
.passwd
,
468 sizeof (ipc_info
.passwd
));
469 (void) rw_unlock(&smb_ipc_lock
);
473 smb_ipc_get_user(char *buf
, size_t buflen
)
475 (void) rw_rdlock(&smb_ipc_lock
);
476 (void) strlcpy(buf
, ipc_info
.user
, buflen
);
477 (void) rw_unlock(&smb_ipc_lock
);
481 smb_ipc_get_passwd(uint8_t *buf
, size_t buflen
)
483 if (buflen
< SMBAUTH_HASH_SZ
)
486 (void) rw_rdlock(&smb_ipc_lock
);
487 (void) memcpy(buf
, ipc_info
.passwd
, SMBAUTH_HASH_SZ
);
488 (void) rw_unlock(&smb_ipc_lock
);
492 * smb_match_netlogon_seqnum
494 * A sequence number is associated with each machine password property
495 * update and the netlogon credential chain setup. If the
496 * sequence numbers don't match, a NETLOGON credential chain
497 * establishment is required.
499 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise,
503 smb_match_netlogon_seqnum(void)
505 int64_t setpasswd_seqnum
;
506 int64_t netlogon_seqnum
;
508 (void) mutex_lock(&seqnum_mtx
);
509 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM
, &setpasswd_seqnum
);
510 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM
, &netlogon_seqnum
);
511 (void) mutex_unlock(&seqnum_mtx
);
512 return (setpasswd_seqnum
== netlogon_seqnum
);
518 * This function should be called after joining an AD to
519 * set all the domain related SMF properties.
521 * The kpasswd_domain property is the AD domain to which the system
522 * is joined via kclient. If this function is invoked by the SMB
523 * daemon, fqdn should be set to NULL.
526 smb_setdomainprops(char *fqdn
, char *server
, char *passwd
)
528 if (server
== NULL
|| passwd
== NULL
)
531 if ((*server
== '\0') || (*passwd
== '\0'))
534 if (fqdn
&& (smb_config_set(SMB_CI_KPASSWD_DOMAIN
, fqdn
) != 0))
537 if (smb_config_set(SMB_CI_KPASSWD_SRV
, server
) != 0)
540 if (smb_set_machine_passwd(passwd
) != 0) {
541 syslog(LOG_ERR
, "smb_setdomainprops: failed to set"
542 " machine account password");
547 * If we successfully create a trust account, we mark
548 * ourselves as a domain member in the environment so
549 * that we use the SAMLOGON version of the NETLOGON
550 * PDC location protocol.
552 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB
, B_TRUE
);
558 * smb_update_netlogon_seqnum
560 * This function should only be called upon a successful netlogon
561 * credential chain establishment to set the sequence number of the
562 * netlogon to match with that of the kpasswd.
565 smb_update_netlogon_seqnum(void)
569 (void) mutex_lock(&seqnum_mtx
);
570 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM
, &num
);
571 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM
, num
);
572 (void) mutex_unlock(&seqnum_mtx
);
577 * Temporary fbt for dtrace until user space sdt enabled.
580 smb_tracef(const char *fmt
, ...)
586 (void) vsnprintf(buf
, 128, fmt
, ap
);
593 * Temporary fbt for dtrace until user space sdt enabled.
595 * This function is designed to be used with dtrace, i.e. see:
596 * usr/src/cmd/smbsrv/dtrace/smbd-all.d
598 * Outside of dtrace, the messages passed to this function usually
599 * lack sufficient context to be useful, so we don't log them.
603 smb_trace(const char *s
)
610 * Creates a NetBIOS name based on the given name and suffix.
611 * NetBIOS name is 15 capital characters, padded with space if needed
612 * and the 16th byte is the suffix.
615 smb_tonetbiosname(char *name
, char *nb_name
, char suffix
)
617 char tmp_name
[NETBIOS_NAME_SZ
];
618 smb_wchar_t wtmp_name
[NETBIOS_NAME_SZ
];
623 rc
= smb_mbstowcs(wtmp_name
, (const char *)name
, NETBIOS_NAME_SZ
);
625 if (rc
!= (size_t)-1) {
626 wtmp_name
[NETBIOS_NAME_SZ
- 1] = 0;
627 rc
= ucstooem(tmp_name
, wtmp_name
, NETBIOS_NAME_SZ
,
630 len
= strlen(tmp_name
);
633 (void) memset(nb_name
, ' ', NETBIOS_NAME_SZ
- 1);
635 (void) smb_strupr(tmp_name
);
636 (void) memcpy(nb_name
, tmp_name
, len
);
638 nb_name
[NETBIOS_NAME_SZ
- 1] = suffix
;
642 smb_get_nameservers(smb_inaddr_t
*ips
, int sz
)
644 union res_sockaddr_union set
[MAXNS
];
646 struct __res_state res_state
;
647 char ipstr
[INET6_ADDRSTRLEN
];
652 bzero(&res_state
, sizeof (struct __res_state
));
653 if (res_ninit(&res_state
) < 0)
656 cnt
= res_getservers(&res_state
, set
, MAXNS
);
657 for (i
= 0; i
< cnt
; i
++) {
660 ips
[i
].a_family
= AF_INET
;
661 bcopy(&set
[i
].sin
.sin_addr
, &ips
[i
].a_ipv4
, NS_INADDRSZ
);
662 if (inet_ntop(AF_INET
, &ips
[i
].a_ipv4
, ipstr
,
664 syslog(LOG_DEBUG
, "Found %s name server\n", ipstr
);
667 ips
[i
].a_family
= AF_INET6
;
668 bcopy(&set
[i
].sin
.sin_addr
, &ips
[i
].a_ipv6
, NS_IN6ADDRSZ
);
669 if (inet_ntop(AF_INET6
, &ips
[i
].a_ipv6
, ipstr
,
671 syslog(LOG_DEBUG
, "Found %s name server\n", ipstr
);
674 res_ndestroy(&res_state
);
681 * Looks up a host by the given name. The host entry can come
682 * from any of the sources for hosts specified in the
683 * /etc/nsswitch.conf and the NetBIOS cache.
685 * XXX Invokes nbt_name_resolve API once the NBTD is integrated
686 * to look in the NetBIOS cache if getipnodebyname fails.
688 * Caller should invoke freehostent to free the returned hostent.
691 smb_gethostbyname(const char *name
, int *err_num
)
695 h
= getipnodebyname(name
, AF_INET
, 0, err_num
);
696 if ((h
== NULL
) || h
->h_length
!= INADDRSZ
)
697 h
= getipnodebyname(name
, AF_INET6
, AI_DEFAULT
, err_num
);
704 * Looks up a host by the given IP address. The host entry can come
705 * from any of the sources for hosts specified in the
706 * /etc/nsswitch.conf and the NetBIOS cache.
708 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated
709 * to look in the NetBIOS cache if getipnodebyaddr fails.
711 * Caller should invoke freehostent to free the returned hostent.
714 smb_gethostbyaddr(const char *addr
, int len
, int type
, int *err_num
)
718 h
= getipnodebyaddr(addr
, len
, type
, err_num
);