summaryrefslogtreecommitdiff
path: root/usr/src/cmd/smbsrv
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2012-12-16 22:41:29 -0500
committerGordon Ross <gwr@nexenta.com>2014-11-18 14:17:36 -0500
commit1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f (patch)
treecbf5612fc6b3f93ddc715d40058879ef005f72de /usr/src/cmd/smbsrv
parent177d5b5f8c0e969013441207a0a705ae66b08cf7 (diff)
downloadillumos-joyent-1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f.tar.gz
5316 allow smbadm join to use RPC
Reviewed by: Bayard Bell <bayard.bell@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Thomas Keiser <thomas.keiser@nexenta.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/cmd/smbsrv')
-rw-r--r--usr/src/cmd/smbsrv/smbadm/smbadm.c142
-rw-r--r--usr/src/cmd/smbsrv/smbd/smbd_join.c242
2 files changed, 133 insertions, 251 deletions
diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c
index 7874a71bed..07887fa7a3 100644
--- a/usr/src/cmd/smbsrv/smbadm/smbadm.c
+++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c
@@ -19,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -229,8 +229,14 @@ smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
return;
case HELP_JOIN:
+#if 0 /* Don't document "-p" yet, still needs work (NX 11960) */
+ (void) fprintf(fp, gettext("\t%s -p domain\n"
+ "\t%s -u username domain\n\t%s -w workgroup\n"),
+ cmd->name, cmd->name, cmd->name);
+#else
(void) fprintf(fp, gettext("\t%s -u username domain\n"
"\t%s -w workgroup\n"), cmd->name, cmd->name);
+#endif
return;
case HELP_LIST:
@@ -457,45 +463,25 @@ smbadm_join(int argc, char **argv)
uint32_t mode = 0;
char option;
- while ((option = getopt(argc, argv, "u:w:")) != -1) {
+ while ((option = getopt(argc, argv, "pu:w")) != -1) {
+ if (mode != 0) {
+ (void) fprintf(stderr, gettext(
+ "join options are mutually exclusive\n"));
+ smbadm_usage(B_FALSE);
+ }
switch (option) {
- case 'w':
- if (mode != 0) {
- (void) fprintf(stderr,
- gettext("-u and -w must only appear "
- "once and are mutually exclusive\n"));
- smbadm_usage(B_FALSE);
- }
-
- mode = SMB_SECMODE_WORKGRP;
- domain = optarg;
+ case 'p':
+ mode = SMB_SECMODE_DOMAIN;
+ /* leave username = NULL */
break;
case 'u':
- if (mode != 0) {
- (void) fprintf(stderr,
- gettext("-u and -w must only appear "
- "once and are mutually exclusive\n"));
- smbadm_usage(B_FALSE);
- }
-
mode = SMB_SECMODE_DOMAIN;
username = optarg;
+ break;
- if ((domain = argv[optind]) == NULL) {
- /*
- * The domain was not specified as a separate
- * argument, check for the combination forms.
- */
- (void) strlcpy(buf, username, sizeof (buf));
- smbadm_extract_domain(buf, &username, &domain);
- }
-
- if ((username == NULL) || (*username == '\0')) {
- (void) fprintf(stderr,
- gettext("missing username\n"));
- smbadm_usage(B_FALSE);
- }
+ case 'w':
+ mode = SMB_SECMODE_WORKGRP;
break;
default:
@@ -504,16 +490,28 @@ smbadm_join(int argc, char **argv)
}
}
+ if (optind < argc)
+ domain = argv[optind];
+
+ if (username != NULL && domain == NULL) {
+ /*
+ * The domain was not specified as a separate
+ * argument, check for the combination forms.
+ */
+ (void) strlcpy(buf, username, sizeof (buf));
+ smbadm_extract_domain(buf, &username, &domain);
+ }
+
if ((domain == NULL) || (*domain == '\0')) {
(void) fprintf(stderr, gettext("missing %s name\n"),
(mode == SMB_SECMODE_WORKGRP) ? "workgroup" : "domain");
smbadm_usage(B_FALSE);
}
- if (mode == SMB_SECMODE_WORKGRP)
+ if (mode == SMB_SECMODE_WORKGRP) {
return (smbadm_join_workgroup(domain));
- else
- return (smbadm_join_domain(domain, username));
+ }
+ return (smbadm_join_domain(domain, username));
}
/*
@@ -582,37 +580,46 @@ smbadm_join_domain(const char *domain, const char *username)
if (!smbadm_join_prompt(jdi.domain_name))
return (0);
- if ((p = strchr(username, '+')) != NULL) {
- ++p;
-
- len = (int)(p - username);
- if (len > sizeof (jdi.domain_name))
- len = sizeof (jdi.domain_name);
-
- (void) strlcpy(jdi.domain_username, username, len);
- (void) strlcpy(jdi.domain_passwd, p,
- sizeof (jdi.domain_passwd));
- } else {
- (void) strlcpy(jdi.domain_username, username,
- sizeof (jdi.domain_username));
- }
+ /*
+ * Note: username is null for "unsecure join"
+ * (join using a pre-created computer account)
+ * No password either.
+ */
+ if (username != NULL) {
+ if ((p = strchr(username, '+')) != NULL) {
+ ++p;
- if (smb_name_validate_account(jdi.domain_username) != ERROR_SUCCESS) {
- (void) fprintf(stderr,
- gettext("username contains invalid characters\n"));
- smbadm_usage(B_FALSE);
- }
+ len = (int)(p - username);
+ if (len > sizeof (jdi.domain_name))
+ len = sizeof (jdi.domain_name);
- if (*jdi.domain_passwd == '\0') {
- prompt = gettext("Enter domain password: ");
+ (void) strlcpy(jdi.domain_username, username, len);
+ (void) strlcpy(jdi.domain_passwd, p,
+ sizeof (jdi.domain_passwd));
+ } else {
+ (void) strlcpy(jdi.domain_username, username,
+ sizeof (jdi.domain_username));
+ }
- if ((p = getpassphrase(prompt)) == NULL) {
- (void) fprintf(stderr, gettext("missing password\n"));
+ if (smb_name_validate_account(jdi.domain_username)
+ != ERROR_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("username contains invalid characters\n"));
smbadm_usage(B_FALSE);
}
- (void) strlcpy(jdi.domain_passwd, p,
- sizeof (jdi.domain_passwd));
+ if (*jdi.domain_passwd == '\0') {
+ prompt = gettext("Enter domain password: ");
+
+ if ((p = getpassphrase(prompt)) == NULL) {
+ (void) fprintf(stderr, gettext(
+ "missing password\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ (void) strlcpy(jdi.domain_passwd, p,
+ sizeof (jdi.domain_passwd));
+ }
}
(void) printf(gettext("Joining %s ... this may take a minute ...\n"),
@@ -635,6 +642,19 @@ smbadm_join_domain(const char *domain, const char *username)
bzero(&jdi, sizeof (jdi));
return (1);
+ case NT_STATUS_BAD_NETWORK_PATH:
+ (void) fprintf(stderr,
+ gettext("failed to resolve domain controller name\n"));
+ bzero(&jdi, sizeof (jdi));
+ return (1);
+
+ case NT_STATUS_NETWORK_ACCESS_DENIED:
+ case NT_STATUS_BAD_NETWORK_NAME:
+ (void) fprintf(stderr,
+ gettext("failed connecting to domain controller\n"));
+ bzero(&jdi, sizeof (jdi));
+ return (1);
+
default:
(void) fprintf(stderr, gettext("failed to join %s: %s\n"),
jdi.domain_name, xlate_nt_status(status));
diff --git a/usr/src/cmd/smbsrv/smbd/smbd_join.c b/usr/src/cmd/smbsrv/smbd/smbd_join.c
index 54fcaccfbb..74d5fac9be 100644
--- a/usr/src/cmd/smbsrv/smbd/smbd_join.c
+++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <syslog.h>
@@ -48,8 +49,7 @@ static cond_t smbd_dc_cv;
static void *smbd_dc_monitor(void *);
static void smbd_dc_update(void);
-static boolean_t smbd_set_netlogon_cred(void);
-static int smbd_get_kpasswd_srv(char *, size_t);
+/* Todo: static boolean_t smbd_set_netlogon_cred(void); */
static uint32_t smbd_join_workgroup(smb_joininfo_t *);
static uint32_t smbd_join_domain(smb_joininfo_t *);
@@ -164,8 +164,8 @@ smbd_dc_update(void)
{
char domain[MAXHOSTNAMELEN];
smb_domainex_t info;
- smb_domain_t *primary;
-
+ smb_domain_t *di;
+ DWORD status;
if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) {
(void) smb_getdomainname(domain, MAXHOSTNAMELEN);
@@ -175,26 +175,24 @@ smbd_dc_update(void)
if (!smb_locate_dc(domain, "", &info)) {
smb_log(smbd.s_loghd, LOG_NOTICE,
"smbd_dc_update: %s: locate failed", domain);
- } else {
- primary = &info.d_primary;
+ return;
+ }
- smb_config_setdomaininfo(primary->di_nbname,
- primary->di_fqname,
- primary->di_sid,
- primary->di_u.di_dns.ddi_forest,
- primary->di_u.di_dns.ddi_guid);
+ di = &info.d_primary;
+ smb_log(smbd.s_loghd, LOG_NOTICE,
+ "smbd_dc_update: %s: located %s", domain, info.d_dc);
- smb_log(smbd.s_loghd, LOG_NOTICE,
- "smbd_dc_update: %s: located %s", domain, info.d_dc);
- }
+ status = mlsvc_netlogon(info.d_dc, di->di_nbname);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_NOTICE,
+ "failed to establish NETLOGON credential chain");
- if (smbd_set_netlogon_cred()) {
/*
* Restart required because the domain changed
* or the credential chain setup failed.
*/
smb_log(smbd.s_loghd, LOG_NOTICE,
- "smbd_dc_update: %s: smb/server restart required");
+ "smbd_dc_update: smb/server restart required");
if (smb_smf_restart_service() != 0)
smb_log(smbd.s_loghd, LOG_ERR,
@@ -225,148 +223,6 @@ smbd_join(smb_joininfo_t *info)
return (status);
}
-/*
- * smbd_set_netlogon_cred
- *
- * If the system is joined to an AD domain via kclient, SMB daemon will need
- * to establish the NETLOGON credential chain.
- *
- * Since the kclient has updated the machine password stored in SMF
- * repository, the cached ipc_info must be updated accordingly by calling
- * smb_ipc_commit.
- *
- * Due to potential replication delays in a multiple DC environment, the
- * NETLOGON rpc request must be sent to the DC, to which the KPASSWD request
- * is sent. If the DC discovered by the SMB daemon is different than the
- * kpasswd server, the current connection with the DC will be torn down
- * and a DC discovery process will be triggered to locate the kpasswd
- * server.
- *
- * If joining a new domain, the domain_name property must be set after a
- * successful credential chain setup.
- */
-static boolean_t
-smbd_set_netlogon_cred(void)
-{
- char kpasswd_srv[MAXHOSTNAMELEN];
- char kpasswd_domain[MAXHOSTNAMELEN];
- char sam_acct[SMB_SAMACCT_MAXLEN];
- char ipc_usr[SMB_USERNAME_MAXLEN];
- char *dom;
- boolean_t new_domain = B_FALSE;
- smb_domainex_t dxi;
- smb_domain_t *di;
-
- if (smb_match_netlogon_seqnum())
- return (B_FALSE);
-
- (void) smb_config_getstr(SMB_CI_KPASSWD_SRV, kpasswd_srv,
- sizeof (kpasswd_srv));
-
- if (*kpasswd_srv == '\0')
- return (B_FALSE);
-
- /*
- * If the domain join initiated by smbadm join CLI is in
- * progress, don't do anything.
- */
- (void) smb_getsamaccount(sam_acct, sizeof (sam_acct));
- smb_ipc_get_user(ipc_usr, SMB_USERNAME_MAXLEN);
- if (smb_strcasecmp(ipc_usr, sam_acct, 0))
- return (B_FALSE);
-
- di = &dxi.d_primary;
- if (!smb_domain_getinfo(&dxi))
- (void) smb_getfqdomainname(di->di_fqname, MAXHOSTNAMELEN);
-
- (void) smb_config_getstr(SMB_CI_KPASSWD_DOMAIN, kpasswd_domain,
- sizeof (kpasswd_domain));
-
- if (*kpasswd_domain != '\0' &&
- smb_strcasecmp(kpasswd_domain, di->di_fqname, 0)) {
- dom = kpasswd_domain;
- new_domain = B_TRUE;
- } else {
- dom = di->di_fqname;
- }
-
- /*
- * DC discovery will be triggered if the domain info is not
- * currently cached or the SMB daemon has previously discovered a DC
- * that is different than the kpasswd server.
- */
- if (new_domain || smb_strcasecmp(dxi.d_dc, kpasswd_srv, 0) != 0) {
- if (*dxi.d_dc != '\0')
- mlsvc_disconnect(dxi.d_dc);
-
- if (!smb_locate_dc(dom, kpasswd_srv, &dxi)) {
- if (!smb_locate_dc(di->di_fqname, "", &dxi)) {
- smb_ipc_commit();
- return (B_FALSE);
- }
- }
- }
-
- smb_ipc_commit();
- if (mlsvc_netlogon(dxi.d_dc, di->di_nbname)) {
- syslog(LOG_NOTICE,
- "failed to establish NETLOGON credential chain");
- return (B_TRUE);
- } else {
- if (new_domain) {
- smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
- di->di_sid,
- di->di_u.di_dns.ddi_forest,
- di->di_u.di_dns.ddi_guid);
- (void) smb_config_setstr(SMB_CI_KPASSWD_DOMAIN, "");
- }
- }
-
- return (new_domain);
-}
-
-/*
- * Retrieve the kpasswd server from krb5.conf.
- *
- * Initialization of the locate dc thread.
- * Returns 0 on success, an error number if thread creation fails.
- */
-static int
-smbd_get_kpasswd_srv(char *srv, size_t len)
-{
- FILE *fp;
- static char buf[512];
- char *p;
-
- *srv = '\0';
- p = getenv("KRB5_CONFIG");
- if (p == NULL || *p == '\0')
- p = "/etc/krb5/krb5.conf";
-
- if ((fp = fopen(p, "r")) == NULL)
- return (-1);
-
- while (fgets(buf, sizeof (buf), fp)) {
-
- /* Weed out any comment text */
- (void) trim_whitespace(buf);
- if (*buf == '#')
- continue;
-
- if ((p = strstr(buf, "kpasswd_server")) != NULL) {
- if ((p = strchr(p, '=')) != NULL) {
- (void) trim_whitespace(++p);
- (void) strlcpy(srv, p, len);
- }
- break;
- }
- }
-
-
- (void) fclose(fp);
- return ((*srv == '\0') ? -1 : 0);
-}
-
static uint32_t
smbd_join_workgroup(smb_joininfo_t *info)
{
@@ -387,11 +243,10 @@ smbd_join_workgroup(smb_joininfo_t *info)
static uint32_t
smbd_join_domain(smb_joininfo_t *info)
{
- uint32_t status;
- unsigned char passwd_hash[SMBAUTH_HASH_SZ];
- char dc[MAXHOSTNAMELEN];
+ static unsigned char zero_hash[SMBAUTH_HASH_SZ];
smb_domainex_t dxi;
smb_domain_t *di;
+ uint32_t status;
/*
* Ensure that any previous membership of this domain has
@@ -399,43 +254,50 @@ smbd_join_domain(smb_joininfo_t *info)
* will ensure that we don't attempt a NETLOGON_SAMLOGON
* when attempting to find the PDC.
*/
-
(void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE);
- if (smb_auth_ntlm_hash(info->domain_passwd, passwd_hash)
- != SMBAUTH_SUCCESS) {
- syslog(LOG_ERR, "smbd: could not compute ntlm hash for '%s'",
- info->domain_username);
- return (NT_STATUS_INTERNAL_ERROR);
- }
+ /* Clear DNS local (ADS) lookup cache too. */
+ smb_ads_refresh();
- smb_ipc_set(info->domain_username, passwd_hash);
+ /*
+ * Use a NULL session while searching for a DC, and
+ * while getting information about the domain.
+ */
+ smb_ipc_set(MLSVC_ANON_USER, zero_hash);
+
+ if (!smb_locate_dc(info->domain_name, "", &dxi)) {
+ syslog(LOG_ERR, "smbd: failed locating "
+ "domain controller for %s",
+ info->domain_name);
+ status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ goto errout;
+ }
- (void) smbd_get_kpasswd_srv(dc, sizeof (dc));
/* info->domain_name could either be NetBIOS domain name or FQDN */
- if (smb_locate_dc(info->domain_name, dc, &dxi)) {
- status = mlsvc_join(&dxi, info->domain_username,
- info->domain_passwd);
-
- if (status == NT_STATUS_SUCCESS) {
- di = &dxi.d_primary;
- smbd_set_secmode(SMB_SECMODE_DOMAIN);
- smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
- di->di_sid,
- di->di_u.di_dns.ddi_forest,
- di->di_u.di_dns.ddi_guid);
- smb_ipc_commit();
- return (status);
- }
-
- smb_ipc_rollback();
+ status = mlsvc_join(&dxi, info->domain_username, info->domain_passwd);
+ if (status != NT_STATUS_SUCCESS) {
syslog(LOG_ERR, "smbd: failed joining %s (%s)",
info->domain_name, xlate_nt_status(status));
- return (status);
+ goto errout;
}
+ /*
+ * Success!
+ *
+ * Strange, mlsvc_join does some of the work to
+ * save the config, then the rest happens here.
+ * Todo: Do the config update all in one place.
+ */
+ di = &dxi.d_primary;
+ smbd_set_secmode(SMB_SECMODE_DOMAIN);
+ smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
+ di->di_sid,
+ di->di_u.di_dns.ddi_forest,
+ di->di_u.di_dns.ddi_guid);
+ smb_ipc_commit();
+ return (status);
+
+errout:
smb_ipc_rollback();
- syslog(LOG_ERR, "smbd: failed locating domain controller for %s",
- info->domain_name);
- return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
+ return (status);
}