#include "nsswitch/libwbclient/wbclient.h"
#include "ads.h"
#include "libads/cldap.h"
-#include "libads/dns.h"
+#include "../lib/addns/dnsquery.h"
#include "../libds/common/flags.h"
#include "librpc/gen_ndr/libnet_join.h"
#include "libnet/libnet_join.h"
#include "krb5_env.h"
#include "../libcli/security/security.h"
#include "libsmb/libsmb.h"
+#include "lib/param/loadparm.h"
+#include "utils/net_dns.h"
#ifdef HAVE_ADS
*cp++ = '\0';
SAFE_FREE(ads->auth.realm);
ads->auth.realm = smb_xstrdup(cp);
- strupper_m(ads->auth.realm);
+ if (!strupper_m(ads->auth.realm)) {
+ ads_destroy(&ads);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
}
status = ads_connect(ads);
goto done;
}
- /* Based on what we requseted, we shouldn't get here, but if
+ /* Based on what we requested, we shouldn't get here, but if
we did, it means the secrets were removed, and therefore
we have left the domain */
d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
#if defined(WITH_DNS_UPDATES)
#include "../lib/addns/dns.h"
-DNS_ERROR DoDNSUpdate(char *pszServerName,
- const char *pszDomainName, const char *pszHostName,
- const struct sockaddr_storage *sslist,
- size_t num_addrs );
-static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
+static NTSTATUS net_update_dns_internal(struct net_context *c,
+ TALLOC_CTX *ctx, ADS_STRUCT *ads,
const char *machine_name,
const struct sockaddr_storage *addrs,
int num_addrs)
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
DNS_ERROR dns_err;
fstring dns_server;
+ const char *dns_hosts_file;
const char *dnsdomain = NULL;
char *root_domain = NULL;
}
dnsdomain++;
- status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
+ dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
+ status = ads_dns_lookup_ns(ctx, dns_hosts_file,
+ dnsdomain, &nameservers, &ns_count);
if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
/* Child domains often do not have NS records. Look
for the NS record for the forest root domain
/* try again for NS servers */
- status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
+ status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain,
+ &nameservers, &ns_count);
if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
- DEBUG(3,("net_ads_join: Failed to find name server for the %s "
+ DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
"realm\n", ads->config.realm));
goto done;
}
for (i=0; i < ns_count; i++) {
+ uint32_t flags = DNS_UPDATE_SIGNED |
+ DNS_UPDATE_UNSIGNED |
+ DNS_UPDATE_UNSIGNED_SUFFICIENT |
+ DNS_UPDATE_PROBE |
+ DNS_UPDATE_PROBE_SUFFICIENT;
+
+ if (c->opt_force) {
+ flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
+ flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
+ }
+
status = NT_STATUS_UNSUCCESSFUL;
/* Now perform the dns update - we'll try non-secure and if we fail,
fstrcpy( dns_server, nameservers[i].hostname );
- dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
+ dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags);
if (ERR_DNS_IS_OK(dns_err)) {
status = NT_STATUS_OK;
goto done;
return status;
}
-static NTSTATUS net_update_dns_ext(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
+static NTSTATUS net_update_dns_ext(struct net_context *c,
+ TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
const char *hostname,
struct sockaddr_storage *iplist,
int num_addrs)
} else {
name_to_fqdn( machine_name, lp_netbios_name() );
}
- strlower_m( machine_name );
+ if (!strlower_m( machine_name )) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
if (num_addrs == 0 || iplist == NULL) {
/*
iplist = iplist_alloc;
}
- status = net_update_dns_internal(mem_ctx, ads, machine_name,
+ status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
iplist, num_addrs);
SAFE_FREE(iplist_alloc);
return status;
}
-static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
+static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
{
NTSTATUS status;
- status = net_update_dns_ext(mem_ctx, ads, hostname, NULL, 0);
+ status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
return status;
}
#endif
" E.g. \"createcomputer=Computers/Servers/Unix\"\n"
" NB: A backslash '\\' is used as escape at multiple levels and may\n"
" need to be doubled or even quadrupled. It is not used as a separator.\n"));
+ d_printf(_(" machinepass=PASS Set the machine password to a specific value during the join.\n"
+ " The deault password is random.\n"));
d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
" NB: osName and osVer must be specified together for either to take effect.\n"
return -1;
}
-/*******************************************************************
- ********************************************************************/
+
+static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
+{
+#if defined(WITH_DNS_UPDATES)
+ ADS_STRUCT *ads_dns = NULL;
+ int ret;
+ NTSTATUS status;
+
+ /*
+ * In a clustered environment, don't do dynamic dns updates:
+ * Registering the set of ip addresses that are assigned to
+ * the interfaces of the node that performs the join does usually
+ * not have the desired effect, since the local interfaces do not
+ * carry the complete set of the cluster's public IP addresses.
+ * And it can also contain internal addresses that should not
+ * be visible to the outside at all.
+ * In order to do dns updates in a clustererd setup, use
+ * net ads dns register.
+ */
+ if (lp_clustering()) {
+ d_fprintf(stderr, _("Not doing automatic DNS update in a "
+ "clustered setup.\n"));
+ return;
+ }
+
+ if (!r->out.domain_is_ad) {
+ return;
+ }
+
+ /*
+ * We enter this block with user creds.
+ * kinit with the machine password to do dns update.
+ */
+
+ ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
+
+ if (ads_dns == NULL) {
+ d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
+ goto done;
+ }
+
+ use_in_memory_ccache();
+
+ ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
+ if (ret == -1) {
+ d_fprintf(stderr, _("DNS update failed: out of memory\n"));
+ goto done;
+ }
+
+ ads_dns->auth.password = secrets_fetch_machine_password(
+ r->out.netbios_domain_name, NULL, NULL);
+ if (ads_dns->auth.password == NULL) {
+ d_fprintf(stderr, _("DNS update failed: out of memory\n"));
+ goto done;
+ }
+
+ ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
+ if (ads_dns->auth.realm == NULL) {
+ d_fprintf(stderr, _("DNS update failed: out of memory\n"));
+ goto done;
+ }
+
+ if (!strupper_m(ads_dns->auth.realm)) {
+ d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
+ goto done;
+ }
+
+ ret = ads_kinit_password(ads_dns);
+ if (ret != 0) {
+ d_fprintf(stderr,
+ _("DNS update failed: kinit failed: %s\n"),
+ error_message(ret));
+ goto done;
+ }
+
+ status = net_update_dns(c, ctx, ads_dns, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_fprintf( stderr, _("DNS update failed: %s\n"),
+ nt_errstr(status));
+ }
+
+done:
+ ads_destroy(&ads_dns);
+#endif
+
+ return;
+}
+
int net_ads_join(struct net_context *c, int argc, const char **argv)
{
WERROR werr = WERR_SETUP_NOT_JOINED;
bool createupn = false;
const char *machineupn = NULL;
+ const char *machine_password = NULL;
const char *create_in_ou = NULL;
int i;
const char *os_name = NULL;
goto fail;
}
}
+ else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
+ if ( (machine_password = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
+ werr = WERR_INVALID_PARAM;
+ goto fail;
+ }
+ }
else {
domain = argv[i];
}
r->in.dc_name = c->opt_host;
r->in.admin_account = c->opt_user_name;
r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
+ r->in.machine_password = machine_password;
r->in.debug = true;
r->in.use_kerberos = c->opt_kerberos;
r->in.modify_config = modify_config;
d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
if (r->out.dns_domain_name) {
- d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
+ d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
r->out.dns_domain_name);
} else {
d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
r->out.netbios_domain_name);
}
-#if defined(WITH_DNS_UPDATES)
/*
- * In a clustered environment, don't do dynamic dns updates:
- * Registering the set of ip addresses that are assigned to
- * the interfaces of the node that performs the join does usually
- * not have the desired effect, since the local interfaces do not
- * carry the complete set of the cluster's public IP addresses.
- * And it can also contain internal addresses that should not
- * be visible to the outside at all.
- * In order to do dns updates in a clustererd setup, use
- * net ads dns register.
+ * We try doing the dns update (if it was compiled in).
+ * If the dns update fails, we still consider the join
+ * operation as succeeded if we came this far.
*/
- if (lp_clustering()) {
- d_fprintf(stderr, _("Not doing automatic DNS update in a "
- "clustered setup.\n"));
- goto done;
- }
-
- if (r->out.domain_is_ad) {
- /* We enter this block with user creds */
- ADS_STRUCT *ads_dns = NULL;
- int ret;
-
- ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
-
- if (ads_dns == NULL) {
- d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
- goto done;
- }
-
- /* kinit with the machine password */
-
- use_in_memory_ccache();
-
- ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
- if (ret == -1) {
- d_fprintf(stderr, _("DNS update failed: out of memory\n"));
- goto dns_done;
- }
-
- ads_dns->auth.password = secrets_fetch_machine_password(
- r->out.netbios_domain_name, NULL, NULL);
- if (ads_dns->auth.password == NULL) {
- d_fprintf(stderr, _("DNS update failed: out of memory\n"));
- goto dns_done;
- }
-
- ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
- if (ads_dns->auth.realm == NULL) {
- d_fprintf(stderr, _("DNS update failed: out of memory\n"));
- goto dns_done;
- }
-
- strupper_m(ads_dns->auth.realm);
-
- ret = ads_kinit_password(ads_dns);
- if (ret != 0) {
- d_fprintf(stderr,
- _("DNS update failed: kinit failed: %s\n"),
- error_message(ret));
- goto dns_done;
- }
-
- if (!NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns, NULL))) {
- d_fprintf( stderr, _("DNS update failed!\n"));
- }
-
- /* exit from this block using machine creds */
-dns_done:
- ads_destroy(&ads_dns);
- }
-
-done:
-#endif
+ _net_ads_join_dns_updates(c, ctx, r);
TALLOC_FREE(r);
TALLOC_FREE( ctx );
return -1;
}
- ntstatus = net_update_dns_ext(ctx, ads, hostname, addrs, num_addrs);
+ ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
if (!NT_STATUS_IS_OK(ntstatus)) {
d_fprintf( stderr, _("DNS update failed!\n") );
ads_destroy( &ads );
#endif
}
-#if defined(WITH_DNS_UPDATES)
-DNS_ERROR do_gethostbyname(const char *server, const char *host);
-#endif
-
static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
{
#if defined(WITH_DNS_UPDATES)
SAFE_FREE(srv_cn_escaped);
SAFE_FREE(printername_escaped);
- nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
+ nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
if (!NT_STATUS_IS_OK(nt_status)) {
d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
servername);
const char *new_password = NULL;
char *chr, *prompt;
const char *user;
+ char pwd[256] = {0};
ADS_STATUS ret;
if (c->display_usage) {
if (argv[1]) {
new_password = (const char *)argv[1];
} else {
+ int rc;
+
if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
return -1;
}
- new_password = getpass(prompt);
+ rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
+ if (rc < 0) {
+ return -1;
+ }
+ new_password = pwd;
free(prompt);
}
ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
auth_password, user, new_password, ads->auth.time_offset);
+ memset(pwd, '\0', sizeof(pwd));
if (!ADS_ERR_OK(ret)) {
d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
ads_destroy(&ads);
}
fstrcpy(my_name, lp_netbios_name());
- strlower_m(my_name);
+ if (!strlower_m(my_name)) {
+ ads_destroy(&ads);
+ return -1;
+ }
+
if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
ads_destroy(&ads);
return -1;
ldap_exp = argv[0];
attrs = (argv + 1);
- rc = ads_do_search_all(ads, ads->config.bind_path,
+ rc = ads_do_search_retry(ads, ads->config.bind_path,
LDAP_SCOPE_SUBTREE,
ldap_exp, attrs, &res);
if (!ADS_ERR_OK(rc)) {
static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
{
struct PAC_LOGON_INFO *info = NULL;
+ struct PAC_DATA *pac_data = NULL;
TALLOC_CTX *mem_ctx = NULL;
NTSTATUS status;
int ret = -1;
const char *impersonate_princ_s = NULL;
+ const char *local_service = NULL;
+ int i;
if (c->display_usage) {
d_printf( "%s\n"
- "net ads kerberos pac\n"
+ "net ads kerberos pac [impersonation_principal]\n"
" %s\n",
_("Usage:"),
_("Dump the Kerberos PAC"));
return 0;
}
+ for (i=0; i<argc; i++) {
+ if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
+ impersonate_princ_s = get_string_param(argv[i]);
+ if (impersonate_princ_s == NULL) {
+ return -1;
+ }
+ }
+ if (strnequal(argv[i], "local_service", strlen("local_service"))) {
+ local_service = get_string_param(argv[i]);
+ if (local_service == NULL) {
+ return -1;
+ }
+ }
+ }
+
mem_ctx = talloc_init("net_ads_kerberos_pac");
if (!mem_ctx) {
goto out;
}
- if (argc > 0) {
- impersonate_princ_s = argv[0];
+ if (local_service == NULL) {
+ local_service = talloc_asprintf(mem_ctx, "%s$@%s",
+ lp_netbios_name(), lp_realm());
+ if (local_service == NULL) {
+ goto out;
+ }
}
c->opt_password = net_prompt_pass(c, c->opt_user_name);
true,
2592000, /* one month */
impersonate_princ_s,
- &info);
+ local_service,
+ &pac_data);
if (!NT_STATUS_IS_OK(status)) {
d_printf(_("failed to query kerberos PAC: %s\n"),
nt_errstr(status));
goto out;
}
+ for (i=0; i < pac_data->num_buffers; i++) {
+
+ if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
+ continue;
+ }
+
+ info = pac_data->buffers[i].info->logon_info.info;
+ if (!info) {
+ goto out;
+ }
+
+ break;
+ }
+
if (info) {
const char *s;
s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);