summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gwr@racktopsystems.com>2021-10-14 21:25:42 -0400
committerToomas Soome <tsoome@me.com>2022-10-05 09:01:46 +0300
commit857c33c4a4bcde4bcde111ad59066aff44fb3f51 (patch)
tree39ca0aeee0a272fc5adafa23a6e30b15b21bf435
parentf40487698292848b93d33bbc76f92ca1c063e39e (diff)
downloadillumos-joyent-857c33c4a4bcde4bcde111ad59066aff44fb3f51.tar.gz
15030 AD join should allow specifying container OU
Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Albert Lee <alee@racktopsystems.com> Reviewed by: Matt Barden <mbarden@tintri.com> Approved by: Dan McDonald <danmcd@mnx.io>
-rw-r--r--usr/src/cmd/smbsrv/smbadm/smbadm.c28
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c22
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/libsmb.h3
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c10
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/libsmbns.h2
-rw-r--r--usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c147
-rw-r--r--usr/src/man/man8/smbadm.815
7 files changed, 133 insertions, 94 deletions
diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c
index e41667200c..e55ea8633b 100644
--- a/usr/src/cmd/smbsrv/smbadm/smbadm.c
+++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c
@@ -100,7 +100,8 @@ static boolean_t smbadm_checkauth(const char *);
static void smbadm_usage(boolean_t);
static int smbadm_join_workgroup(const char *, boolean_t);
-static int smbadm_join_domain(const char *, const char *, boolean_t);
+static int smbadm_join_domain(const char *, const char *,
+ const char *, boolean_t);
static void smbadm_extract_domain(char *, char **, char **);
static int smbadm_join(int, char **);
@@ -246,11 +247,12 @@ smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
case HELP_JOIN:
#if 0 /* Don't document "-p" yet, still needs work (NEX-11960) */
(void) fprintf(fp, gettext("\t%s [-y] -p <domain>\n"
- "\t%s [-y] -u <username domain>\n"
+ "\t%s [-y] [-c container] -u <username domain>\n"
"\t%s [-y] -w <workgroup>\n"),
cmd->name, cmd->name, cmd->name);
#else
- (void) fprintf(fp, gettext("\t%s [-y] -u <username> <domain>\n"
+ (void) fprintf(fp, gettext(
+ "\t%s [-y] [-c container] -u <username> <domain>\n"
"\t%s [-y] -w <workgroup>\n"), cmd->name, cmd->name);
#endif
return;
@@ -468,17 +470,21 @@ smbadm_join(int argc, char **argv)
char buf[MAXHOSTNAMELEN * 2];
char *domain = NULL;
char *username = NULL;
+ char *container = NULL;
uint32_t mode = 0;
boolean_t do_prompt = B_TRUE;
char option;
- while ((option = getopt(argc, argv, "pu:wy")) != -1) {
+ while ((option = getopt(argc, argv, "c:pu:wy")) != -1) {
if (mode != 0) {
(void) fprintf(stderr, gettext(
"join options are mutually exclusive\n"));
smbadm_usage(B_FALSE);
}
switch (option) {
+ case 'c':
+ container = optarg;
+ break;
case 'p':
mode = SMB_SECMODE_DOMAIN;
/* leave username = NULL */
@@ -524,7 +530,7 @@ smbadm_join(int argc, char **argv)
if (mode == SMB_SECMODE_WORKGRP) {
return (smbadm_join_workgroup(domain, do_prompt));
}
- return (smbadm_join_domain(domain, username, do_prompt));
+ return (smbadm_join_domain(domain, container, username, do_prompt));
}
/*
@@ -574,7 +580,8 @@ smbadm_join_workgroup(const char *workgroup, boolean_t prompt)
* to be appended to the username using '+' as a scripting convenience.
*/
static int
-smbadm_join_domain(const char *domain, const char *username, boolean_t prompt)
+smbadm_join_domain(const char *domain, const char *container,
+ const char *username, boolean_t prompt)
{
smb_joininfo_t jdi;
smb_joinres_t jdres;
@@ -587,6 +594,15 @@ smbadm_join_domain(const char *domain, const char *username, boolean_t prompt)
jdi.mode = SMB_SECMODE_DOMAIN;
(void) strlcpy(jdi.domain_name, domain, sizeof (jdi.domain_name));
(void) strtrim(jdi.domain_name, " \t\n");
+ if (container != NULL) {
+ if (strlcpy(jdi.container_name, container,
+ sizeof (jdi.container_name)) >=
+ sizeof (jdi.container_name)) {
+ (void) fprintf(stderr, gettext("container name is "
+ "too long\n"));
+ smbadm_usage(B_FALSE);
+ }
+ }
if (smb_name_validate_domain(jdi.domain_name) != ERROR_SUCCESS) {
(void) fprintf(stderr, gettext("domain name is invalid\n"));
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index 9191cfbce6..00326cb7dc 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -100,11 +100,22 @@ mlsvc_join(smb_joininfo_t *info, smb_joinres_t *res)
char addrbuf[INET6_ADDRSTRLEN];
smb_domainex_t dxi;
smb_domain_t *di = &dxi.d_primary;
+ char *container;
+ char *username;
DWORD status;
int rc;
bzero(&dxi, sizeof (dxi));
+ if (info->container_name[0] != '\0')
+ container = info->container_name;
+ else
+ container = NULL;
+ if (info->domain_username[0] != '\0')
+ username = info->domain_username;
+ else
+ username = NULL;
+
/*
* Domain join support: AD (Kerberos+LDAP) or MS-RPC?
*/
@@ -125,11 +136,10 @@ mlsvc_join(smb_joininfo_t *info, smb_joinres_t *res)
*/
(void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE);
- if (info->domain_username[0] != '\0') {
+ if (username != NULL) {
(void) smb_auth_ntlm_hash(info->domain_passwd, passwd_hash);
- smb_ipc_set(info->domain_username, passwd_hash);
- syslog(LOG_INFO, "smbd: joining with user %s",
- info->domain_username);
+ smb_ipc_set(username, passwd_hash);
+ syslog(LOG_INFO, "smbd: joining with user %s", username);
} else {
smb_ipc_set(MLSVC_ANON_USER, zero_hash);
syslog(LOG_INFO, "smbd: joining with anonymous");
@@ -210,14 +220,14 @@ mlsvc_join(smb_joininfo_t *info, smb_joinres_t *res)
* Create or update our machine account on the DC.
* A non-null user means we do "secure join".
*/
- if (info->domain_username[0] != '\0') {
+ if (username != NULL) {
/*
* If enabled, try to join using AD Services.
*/
status = NT_STATUS_UNSUCCESSFUL;
if (ads_enabled) {
syslog(LOG_INFO, "use_ads=true (LDAP join)");
- res->join_err = smb_ads_join(di->di_fqname,
+ res->join_err = smb_ads_join(di->di_fqname, container,
info->domain_username, info->domain_passwd,
machine_pw);
if (res->join_err == SMB_ADS_SUCCESS) {
diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
index 48336f2d73..388553e03c 100644
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
@@ -241,10 +241,11 @@ extern void smb_update_netlogon_seqnum(void);
/* See also: smb_joininfo_xdr() */
typedef struct smb_joininfo {
+ uint32_t mode;
char domain_name[MAXHOSTNAMELEN];
+ char container_name[MAXHOSTNAMELEN];
char domain_username[SMB_USERNAME_MAXLEN + 1];
char domain_passwd[SMB_PASSWD_MAXLEN + 1];
- uint32_t mode;
} smb_joininfo_t;
/* See also: smb_joinres_xdr() */
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c b/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c
index 96702e4c7d..23d10f9dbf 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c
@@ -207,10 +207,17 @@ smb_get_dcinfo(char *namebuf, uint32_t namebuflen, smb_inaddr_t *ipaddr)
bool_t
smb_joininfo_xdr(XDR *xdrs, smb_joininfo_t *objp)
{
+ if (!xdr_uint32_t(xdrs, &objp->mode))
+ return (FALSE);
+
if (!xdr_vector(xdrs, (char *)objp->domain_name, MAXHOSTNAMELEN,
sizeof (char), (xdrproc_t)xdr_char))
return (FALSE);
+ if (!xdr_vector(xdrs, (char *)objp->container_name, MAXHOSTNAMELEN,
+ sizeof (char), (xdrproc_t)xdr_char))
+ return (FALSE);
+
if (!xdr_vector(xdrs, (char *)objp->domain_username,
SMB_USERNAME_MAXLEN + 1, sizeof (char), (xdrproc_t)xdr_char))
return (FALSE);
@@ -219,9 +226,6 @@ smb_joininfo_xdr(XDR *xdrs, smb_joininfo_t *objp)
SMB_PASSWD_MAXLEN + 1, sizeof (char), (xdrproc_t)xdr_char))
return (FALSE);
- if (!xdr_uint32_t(xdrs, &objp->mode))
- return (FALSE);
-
return (TRUE);
}
diff --git a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
index fc8bd69957..7cde269335 100644
--- a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
+++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
@@ -106,7 +106,7 @@ extern int smb_ads_lookup_share(smb_ads_handle_t *, const char *, const char *,
char *);
extern int smb_ads_add_share(smb_ads_handle_t *, const char *, const char *,
const char *);
-extern smb_ads_status_t smb_ads_join(char *, char *, char *, char *);
+extern smb_ads_status_t smb_ads_join(char *, char *, char *, char *, char *);
extern void smb_ads_log_errmsg(smb_ads_status_t);
extern const char *smb_ads_strerror(int);
extern uint32_t smb_ads_lookup_msdcs(char *, smb_dcinfo_t *);
diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
index ca2897aea1..8bbe0e8afb 100644
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
@@ -1187,33 +1187,22 @@ smb_ads_remove_share(smb_ads_handle_t *ah, const char *adsShareName,
}
/*
- * smb_ads_get_default_comp_container_dn
+ * smb_ads_get_new_comp_dn
*
- * Build the distinguished name for the default computer conatiner (i.e. the
- * pre-defined Computers container).
+ * Build the distinguished name for a new machine account
+ * prepend: cn=SamAccountName, cn=Computers, ...domain_dn...
*/
static void
-smb_ads_get_default_comp_container_dn(smb_ads_handle_t *ah, char *buf,
- size_t buflen)
-{
- (void) snprintf(buf, buflen, "cn=%s,%s", SMB_ADS_COMPUTERS_CN,
- ah->domain_dn);
-}
-
-/*
- * smb_ads_get_default_comp_dn
- *
- * Build the distinguished name for this system.
- */
-static void
-smb_ads_get_default_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen)
+smb_ads_get_new_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen,
+ char *container)
{
char nbname[NETBIOS_NAME_SZ];
- char container_dn[SMB_ADS_DN_MAX];
+ if (container == NULL)
+ container = "cn=" SMB_ADS_COMPUTERS_CN;
(void) smb_getnetbiosname(nbname, sizeof (nbname));
- smb_ads_get_default_comp_container_dn(ah, container_dn, SMB_ADS_DN_MAX);
- (void) snprintf(buf, buflen, "cn=%s,%s", nbname, container_dn);
+ (void) snprintf(buf, buflen, "cn=%s,%s,%s",
+ nbname, container, ah->domain_dn);
}
/*
@@ -1495,19 +1484,17 @@ smb_ads_getattr(LDAP *ld, LDAPMessage *entry, smb_ads_avpair_t *avpair)
* machine account, the DNS name will be not set, and that's OK.
* If we see a DNS name and it doesn't match our DNS name, we'll
* assume the account belongs to someone else and return "DUP".
+ *
+ * Only do the DNS name check for our initial search for the
+ * machine account, which has avpair->avp_attr = SMB_ADS_ATTR_DN
*/
static smb_ads_qstat_t
smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
smb_ads_avpair_t *avpair)
{
- char fqhost[MAXHOSTNAMELEN];
- smb_ads_avpair_t dnshost_avp;
smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
LDAPMessage *entry;
- if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
- return (SMB_ADS_STAT_ERR);
-
if (ldap_count_entries(ah->ld, res) == 0) {
syslog(LOG_DEBUG, "smbns: find_computer, "
"ldap_count_entries zero");
@@ -1520,48 +1507,62 @@ smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
return (SMB_ADS_STAT_ERR);
}
- syslog(LOG_DEBUG, "smbns: find_computer, check DNS name");
- dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
- rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
+ /* Have an LDAP entry (found something) */
+ syslog(LOG_DEBUG, "smbns: find_computer, have LDAP resp.");
- /*
- * Check the status of finding the DNS name
- */
- switch (rc) {
- case SMB_ADS_STAT_FOUND:
- /*
- * Found a DNS name. If it doesn't match ours,
- * returns SMB_ADS_STAT_DUP to avoid overwriting
- * the computer account of another system whose
- * NetBIOS name collides with that of the current
- * system.
- */
- if (strcasecmp(dnshost_avp.avp_val, fqhost)) {
- syslog(LOG_DEBUG, "smbns: find_computer, "
- "duplicate name (%s)",
- dnshost_avp.avp_val);
- rc = SMB_ADS_STAT_DUP;
- }
- free(dnshost_avp.avp_val);
- break;
+ if (avpair != NULL &&
+ strcmp(avpair->avp_attr, SMB_ADS_ATTR_DN) == 0) {
+ char fqhost[MAXHOSTNAMELEN];
+ smb_ads_avpair_t dnshost_avp;
+
+ syslog(LOG_DEBUG, "smbns: find_computer, check DNS name");
+
+ if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
+ return (SMB_ADS_STAT_ERR);
+
+ dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
+ dnshost_avp.avp_val = NULL;
+ rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
- case SMB_ADS_STAT_NOT_FOUND:
/*
- * No dNSHostname attribute, so probably a
- * pre-created computer account. Use it.
- *
- * Returns SMB_ADS_STAT_FOUND for the status
- * of finding the machine account.
+ * Status from finding the DNS name value
*/
- rc = SMB_ADS_STAT_FOUND;
- break;
+ switch (rc) {
+ case SMB_ADS_STAT_FOUND:
+ /*
+ * Found a DNS name. If it doesn't match ours,
+ * returns SMB_ADS_STAT_DUP to avoid overwriting
+ * the computer account of another system whose
+ * NetBIOS name collides with that of the current
+ * system.
+ */
+ if (strcasecmp(dnshost_avp.avp_val, fqhost)) {
+ syslog(LOG_DEBUG, "smbns: find_computer, "
+ "duplicate name (%s)",
+ dnshost_avp.avp_val);
+ rc = SMB_ADS_STAT_DUP;
+ }
+ free(dnshost_avp.avp_val);
+ break;
+
+ case SMB_ADS_STAT_NOT_FOUND:
+ /*
+ * No dNSHostname attribute, so probably a
+ * pre-created computer account. Use it.
+ *
+ * Returns SMB_ADS_STAT_FOUND for the status
+ * of finding the machine account.
+ */
+ rc = SMB_ADS_STAT_FOUND;
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
- if (rc != SMB_ADS_STAT_FOUND)
- return (rc);
+ if (rc != SMB_ADS_STAT_FOUND)
+ return (rc);
+ }
if (avpair) {
syslog(LOG_DEBUG, "smbns: find_computer, check %s",
@@ -1661,10 +1662,9 @@ smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, smb_ads_avpair_t *avpair,
/*
* smb_ads_find_computer
*
- * Starts by searching for the system's AD computer object in the default
- * container (i.e. cn=Computers). If not found, searches the entire directory.
- * If found, 'dn' will be set to the distinguished name of the system's AD
- * computer object.
+ * Searches the directory for the machine account (SamAccountName)
+ * If found, 'dn' will be set to the distinguished name of the system's
+ * AD computer object.
*/
static smb_ads_qstat_t
smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
@@ -1675,15 +1675,9 @@ smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
avpair.avp_attr = SMB_ADS_ATTR_DN;
avpair.avp_val = NULL;
- smb_ads_get_default_comp_container_dn(ah, dn, SMB_ADS_DN_MAX);
- stat = smb_ads_lookup_computer_n_attr(ah, &avpair, LDAP_SCOPE_ONELEVEL,
- dn);
-
- if (stat == SMB_ADS_STAT_NOT_FOUND) {
- (void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
- stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
- LDAP_SCOPE_SUBTREE, dn);
- }
+ (void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
+ stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
+ LDAP_SCOPE_SUBTREE, dn);
if (stat == SMB_ADS_STAT_FOUND) {
(void) strlcpy(dn, avpair.avp_val, SMB_ADS_DN_MAX);
@@ -1776,7 +1770,8 @@ smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn)
* principal after the domain join operation.
*/
smb_ads_status_t
-smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd)
+smb_ads_join(char *domain, char *container,
+ char *user, char *usr_passwd, char *machine_passwd)
{
smb_ads_handle_t *ah = NULL;
krb5_context ctx = NULL;
@@ -1822,7 +1817,7 @@ smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd)
case SMB_ADS_STAT_NOT_FOUND:
new_acct = B_TRUE;
- smb_ads_get_default_comp_dn(ah, dn, SMB_ADS_DN_MAX);
+ smb_ads_get_new_comp_dn(ah, dn, SMB_ADS_DN_MAX, container);
syslog(LOG_INFO, "smb_ads_join: machine account not found."
" Creating: %s", dn);
if (smb_ads_add_computer(ah, dclevel, dn) != 0) {
diff --git a/usr/src/man/man8/smbadm.8 b/usr/src/man/man8/smbadm.8
index 407958c072..8628cbefb4 100644
--- a/usr/src/man/man8/smbadm.8
+++ b/usr/src/man/man8/smbadm.8
@@ -17,8 +17,9 @@
.\"
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
+.\" Copyright 2021 RackTop Systems, Inc.
.\"
-.Dd June 6, 2019
+.Dd Oct 15, 2021
.Dt SMBADM 8
.Os
.Sh NAME
@@ -69,6 +70,7 @@ membership
.Nm
.Cm join
.Op Fl y
+.Op Fl c Ar container
.Fl u Ar username
.Ar domain
.Nm
@@ -349,6 +351,7 @@ module has been added to the system's PAM configuration.
.It Xo
.Cm join
.Op Fl y
+.Op Fl c Ar container
.Fl u Ar username
.Ar domain
.Xc
@@ -378,6 +381,16 @@ username@domain
.Ar domain
can be the NetBIOS or DNS domain name.
.Pp
+The optional
+.Ar container
+string specifies the Relative Distinguished Name (RDN) of the
+Active Directory Container in which the machine trust account
+should be created.
+If unspecified, the RDN used is:
+.Bd -literal -offset indent
+CN=Computers
+.Ed
+.Pp
If a machine trust account for the system already exists on a domain controller,
any authenticated user account can be used when joining the domain.
However, if the machine trust account does