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]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
37 #include <smbsrv/libsmb.h>
38 #include <smbsrv/libsmbns.h>
39 #include <smbsrv/libmlsvc.h>
40 #include <smbsrv/smbinfo.h>
43 #define SMBD_DC_MONITOR_ATTEMPTS 3
44 #define SMBD_DC_MONITOR_RETRY_INTERVAL 3 /* seconds */
45 #define SMBD_DC_MONITOR_INTERVAL 60 /* seconds */
49 static mutex_t smbd_dc_mutex
;
50 static cond_t smbd_dc_cv
;
52 static void *smbd_dc_monitor(void *);
53 static void smbd_dc_update(void);
54 static int smbd_dc_check(smb_domainex_t
*);
55 /* Todo: static boolean_t smbd_set_netlogon_cred(void); */
56 static void smbd_join_workgroup(smb_joininfo_t
*, smb_joinres_t
*);
57 static void smbd_join_domain(smb_joininfo_t
*, smb_joinres_t
*);
60 * Launch the DC discovery and monitor thread.
63 smbd_dc_monitor_init(void)
68 (void) smb_config_getstr(SMB_CI_ADS_SITE
, smbd
.s_site
,
70 (void) smb_config_getip(SMB_CI_DOMAIN_SRV
, &smbd
.s_pdc
);
73 if (smbd
.s_secmode
!= SMB_SECMODE_DOMAIN
)
76 (void) pthread_attr_init(&attr
);
77 (void) pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
78 rc
= pthread_create(&smbd
.s_dc_monitor_tid
, &attr
, smbd_dc_monitor
,
80 (void) pthread_attr_destroy(&attr
);
85 * Refresh the DC monitor. Called from SMF refresh and when idmap
86 * finds a different DC from what we were using previously.
87 * Update our domain (and current DC) information.
90 smbd_dc_monitor_refresh(void)
93 syslog(LOG_INFO
, "smbd_dc_monitor_refresh");
95 smb_ddiscover_refresh();
97 (void) mutex_lock(&smbd_dc_mutex
);
99 smbd
.s_pdc_changed
= B_TRUE
;
100 (void) cond_signal(&smbd_dc_cv
);
102 (void) mutex_unlock(&smbd_dc_mutex
);
107 smbd_dc_monitor(void *arg
)
110 boolean_t ds_not_responding
;
111 boolean_t ds_cfg_changed
;
115 /* Wait for smb_dclocator_init() to complete. */
116 smbd_online_wait("smbd_dc_monitor");
119 while (smbd_online()) {
120 ds_not_responding
= B_FALSE
;
121 ds_cfg_changed
= B_FALSE
;
122 delay
.tv_sec
= SMBD_DC_MONITOR_INTERVAL
;
125 (void) mutex_lock(&smbd_dc_mutex
);
126 (void) cond_reltimedwait(&smbd_dc_cv
, &smbd_dc_mutex
, &delay
);
128 if (smbd
.s_pdc_changed
) {
129 smbd
.s_pdc_changed
= B_FALSE
;
130 ds_cfg_changed
= B_TRUE
;
131 /* NB: smb_ddiscover_refresh was called. */
134 (void) mutex_unlock(&smbd_dc_mutex
);
136 if (ds_cfg_changed
) {
137 syslog(LOG_DEBUG
, "smbd_dc_monitor: config changed");
141 if (!smb_domain_getinfo(&di
)) {
142 syslog(LOG_DEBUG
, "smbd_dc_monitor: no domain info");
146 if (di
.d_dci
.dc_name
[0] == '\0') {
147 syslog(LOG_DEBUG
, "smbd_dc_monitor: no DC name");
151 for (i
= 0; i
< SMBD_DC_MONITOR_ATTEMPTS
; ++i
) {
152 if (smbd_dc_check(&di
) == 0) {
153 ds_not_responding
= B_FALSE
;
157 ds_not_responding
= B_TRUE
;
158 (void) sleep(SMBD_DC_MONITOR_RETRY_INTERVAL
);
161 if (ds_not_responding
) {
163 "smbd_dc_monitor: DC not responding: %s",
165 smb_ddiscover_bad_dc(di
.d_dci
.dc_name
);
168 if (ds_not_responding
|| ds_cfg_changed
) {
171 * An smb_ads_refresh will be done by the
172 * smb_ddiscover_service when necessary.
173 * Note: smbd_dc_monitor_refresh was already
174 * called if appropriate.
180 smbd
.s_dc_monitor_tid
= 0;
185 * Simply attempt a connection to the DC.
188 smbd_dc_check(smb_domainex_t
*di
)
193 int tmo
= 5 * 1000; /* 5 sec. */
196 bzero(&sa
, sizeof (sa
));
197 switch (di
->d_dci
.dc_addr
.a_family
) {
199 struct sockaddr_in
*sin
= (void *)&sa
;
200 sin
->sin_family
= AF_INET
;
201 sin
->sin_port
= htons(IPPORT_SMB
);
202 sin
->sin_addr
.s_addr
= di
->d_dci
.dc_addr
.a_ipv4
;
203 salen
= sizeof (*sin
);
207 struct sockaddr_in6
*sin6
= (void *)&sa
;
208 sin6
->sin6_family
= AF_INET6
;
209 sin6
->sin6_port
= htons(IPPORT_SMB
);
210 (void) memcpy(&sin6
->sin6_addr
,
211 &di
->d_dci
.dc_addr
.a_ipv6
,
212 sizeof (in6_addr_t
));
213 salen
= sizeof (*sin6
);
220 sock
= socket(di
->d_dci
.dc_addr
.a_family
, SOCK_STREAM
, 0);
223 (void) setsockopt(sock
, IPPROTO_TCP
,
224 TCP_CONN_ABORT_THRESHOLD
, &tmo
, sizeof (tmo
));
226 rc
= connect(sock
, &sa
, salen
);
235 * Locate a domain controller in the current resource domain and Update
236 * the Netlogon credential chain.
238 * The domain configuration will be updated upon successful DC discovery.
243 char domain
[MAXHOSTNAMELEN
];
249 * Don't want this active until we're a domain member.
251 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN
)
254 if (smb_getfqdomainname(domain
, MAXHOSTNAMELEN
) != 0)
257 if (domain
[0] == '\0') {
259 "smbd_dc_update: no domain name set");
263 if (!smb_locate_dc(domain
, &info
)) {
265 "smbd_dc_update: %s: locate failed", domain
);
269 di
= &info
.d_primary
;
271 "smbd_dc_update: %s: located %s", domain
, info
.d_dci
.dc_name
);
273 status
= mlsvc_netlogon(info
.d_dci
.dc_name
, di
->di_nbname
);
274 if (status
!= NT_STATUS_SUCCESS
) {
276 "failed to establish NETLOGON credential chain");
277 syslog(LOG_NOTICE
, " with server %s for domain %s (%s)",
278 info
.d_dci
.dc_name
, domain
,
279 xlate_nt_status(status
));
286 * Joins the specified domain/workgroup.
288 * If the security mode or domain name is being changed,
289 * the caller must restart the service.
292 smbd_join(smb_joininfo_t
*info
, smb_joinres_t
*res
)
294 dssetup_clear_domain_info();
295 if (info
->mode
== SMB_SECMODE_WORKGRP
)
296 smbd_join_workgroup(info
, res
);
298 smbd_join_domain(info
, res
);
302 smbd_join_workgroup(smb_joininfo_t
*info
, smb_joinres_t
*res
)
304 char nb_domain
[SMB_PI_MAX_DOMAIN
];
306 syslog(LOG_DEBUG
, "smbd: join workgroup: %s", info
->domain_name
);
308 (void) smb_config_getstr(SMB_CI_DOMAIN_NAME
, nb_domain
,
311 smbd_set_secmode(SMB_SECMODE_WORKGRP
);
312 smb_config_setdomaininfo(info
->domain_name
, "", "", "", "");
313 (void) smb_config_set_idmap_domain("");
314 (void) smb_config_refresh_idmap();
316 if (strcasecmp(nb_domain
, info
->domain_name
))
317 smb_browser_reconfig();
319 res
->status
= NT_STATUS_SUCCESS
;
323 smbd_join_domain(smb_joininfo_t
*info
, smb_joinres_t
*res
)
326 syslog(LOG_DEBUG
, "smbd: join domain: %s", info
->domain_name
);
328 /* info->domain_name could either be NetBIOS domain name or FQDN */
329 mlsvc_join(info
, res
);
330 if (res
->status
== 0) {
331 smbd_set_secmode(SMB_SECMODE_DOMAIN
);
333 syslog(LOG_ERR
, "smbd: failed joining %s (%s)",
334 info
->domain_name
, xlate_nt_status(res
->status
));