diff options
author | Gordon Ross <gwr@racktopsystems.com> | 2021-10-14 21:25:42 -0400 |
---|---|---|
committer | Toomas Soome <tsoome@me.com> | 2022-10-05 09:01:46 +0300 |
commit | 857c33c4a4bcde4bcde111ad59066aff44fb3f51 (patch) | |
tree | 39ca0aeee0a272fc5adafa23a6e30b15b21bf435 | |
parent | f40487698292848b93d33bbc76f92ca1c063e39e (diff) | |
download | illumos-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.c | 28 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c | 22 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libsmb/common/libsmb.h | 3 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libsmb/common/smb_doorclnt.c | 10 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libsmbns/common/libsmbns.h | 2 | ||||
-rw-r--r-- | usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c | 147 | ||||
-rw-r--r-- | usr/src/man/man8/smbadm.8 | 15 |
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 |