diff options
| author | Gordon Ross <gwr@nexenta.com> | 2012-12-16 22:41:29 -0500 |
|---|---|---|
| committer | Gordon Ross <gwr@nexenta.com> | 2014-11-18 14:17:36 -0500 |
| commit | 1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f (patch) | |
| tree | cbf5612fc6b3f93ddc715d40058879ef005f72de /usr/src/cmd/smbsrv | |
| parent | 177d5b5f8c0e969013441207a0a705ae66b08cf7 (diff) | |
| download | illumos-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.c | 142 | ||||
| -rw-r--r-- | usr/src/cmd/smbsrv/smbd/smbd_join.c | 242 |
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); } |
