This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
#include "includes.h"
#include "utils/net.h"
-/* Macro for checking RPC error codes to make things more readable */
-
-#define CHECK_RPC_ERR(rpc, msg) \
- if (!NT_STATUS_IS_OK(result = rpc)) { \
- DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
- goto done; \
- }
-
-#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
- if (!NT_STATUS_IS_OK(result = rpc)) { \
- DEBUG(0, debug_args); \
- goto done; \
- }
-
#ifdef HAVE_ADS
int net_ads_usage(int argc, const char **argv)
{
- d_printf(
-"\nnet ads join <org_unit>"\
-"\n\tjoins the local machine to a ADS realm\n"\
-"\nnet ads leave"\
-"\n\tremoves the local machine from a ADS realm\n"\
-"\nnet ads testjoin"\
-"\n\ttests that an exiting join is OK\n"\
-"\nnet ads user"\
-"\n\tlist, add, or delete users in the realm\n"\
-"\nnet ads group"\
-"\n\tlist, add, or delete groups in the realm\n"\
-"\nnet ads info"\
-"\n\tshows some info on the server\n"\
-"\nnet ads status"\
-"\n\tdump the machine account details to stdout\n"
-"\nnet ads lookup"\
-"\n\tperform a CLDAP search on the server\n"
-"\nnet ads password <username@realm> <password> -Uadmin_username@realm%%admin_pass"\
-"\n\tchange a user's password using an admin account"\
-"\n\t(note: use realm in UPPERCASE, prompts if password is obmitted)\n"\
-"\nnet ads changetrustpw"\
-"\n\tchange the trust account password of this machine in the AD tree\n"\
-"\nnet ads printer [info | publish | remove] <printername> <servername>"\
-"\n\t lookup, add, or remove directory entry for a printer\n"\
-"\nnet ads search"\
-"\n\tperform a raw LDAP search and dump the results\n"
-"\nnet ads dn"\
-"\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
-"\nnet ads sid"\
-"\n\tperform a raw LDAP search and dump attributes of a particular SID\n"
-"\nnet ads keytab"\
-"\n\tcreates and updates the kerberos system keytab file\n"
- );
+ d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
+ d_printf(" Join the local machine to a ADS realm\n");
+ d_printf("leave\n");
+ d_printf(" Remove the local machine from a ADS realm\n");
+ d_printf("testjoin\n");
+ d_printf(" Validates the machine account in the domain\n");
+ d_printf("user\n");
+ d_printf(" List, add, or delete users in the realm\n");
+ d_printf("group\n");
+ d_printf(" List, add, or delete groups in the realm\n");
+ d_printf("info\n");
+ d_printf(" Displays details regarding a specific AD server\n");
+ d_printf("status\n");
+ d_printf(" Display details regarding the machine's account in AD\n");
+ d_printf("lookup\n");
+ d_printf(" Performs CLDAP query of AD domain controllers\n");
+ d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
+ d_printf(" Change a user's password using an admin account\n");
+ d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
+ d_printf("changetrustpw\n");
+ d_printf(" Change the trust account password of this machine in the AD tree\n");
+ d_printf("printer [info | publish | remove] <printername> <servername>\n");
+ d_printf(" Lookup, add, or remove directory entry for a printer\n");
+ d_printf("{search,dn,sid}\n");
+ d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
+ d_printf("keytab\n");
+ d_printf(" Manage a local keytab file based on the machine account in AD\n");
+ d_printf("dns\n");
+ d_printf(" Issue a dynamic DNS update request the server's hostname\n");
+ d_printf(" (using the machine credentials)\n");
+
return -1;
}
+/* when we do not have sufficient input parameters to contact a remote domain
+ * we always fall back to our own realm - Guenther*/
+
+static const char *assume_own_realm(void)
+{
+ if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
+ return lp_realm();
+ }
+
+ return NULL;
+}
/*
do a cldap netlogon query
if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
- printf("Site Name:\t\t%s\n", reply.site_name);
- printf("Site Name (2):\t\t%s\n", reply.site_name_2);
+ printf("Server Site Name :\t\t%s\n", reply.server_site_name);
+ printf("Client Site Name :\t\t%s\n", reply.client_site_name);
d_printf("NT Version: %d\n", reply.version);
d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
static int net_ads_lookup(int argc, const char **argv)
{
ADS_STRUCT *ads;
- ADS_STATUS status;
- const char *realm = NULL;
-
- if ( strequal(lp_workgroup(), opt_target_workgroup ) )
- realm = lp_realm();
-
- ads = ads_init(realm, opt_target_workgroup, opt_host);
- if (ads) {
- ads->auth.flags |= ADS_AUTH_NO_BIND;
- }
- status = ads_connect(ads);
- if (!ADS_ERR_OK(status) || !ads) {
+ if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
d_fprintf(stderr, "Didn't find the cldap server!\n");
return -1;
}
-
+
if (!ads->config.realm) {
ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
ads->ldap_port = 389;
{
ADS_STRUCT *ads;
- if ( (ads = ads_init(lp_realm(), opt_target_workgroup, opt_host)) != NULL ) {
- ads->auth.flags |= ADS_AUTH_NO_BIND;
+ if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
+ d_fprintf(stderr, "Didn't find the ldap server!\n");
+ return -1;
}
- ads_connect(ads);
-
if (!ads || !ads->config.realm) {
d_fprintf(stderr, "Didn't find the ldap server!\n");
return -1;
setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
}
-static ADS_STRUCT *ads_startup(void)
+static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
{
- ADS_STRUCT *ads;
+ ADS_STRUCT *ads = NULL;
ADS_STATUS status;
BOOL need_password = False;
BOOL second_time = False;
char *cp;
-
+ const char *realm = NULL;
+ BOOL tried_closest_dc = False;
+
/* lp_realm() should be handled by a command line param,
However, the join requires that realm be set in smb.conf
and compares our realm with the remote server's so this is
ok until someone needs more flexibility */
-
- ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
+
+ *ads_ret = NULL;
+
+retry_connect:
+ if (only_own_domain) {
+ realm = lp_realm();
+ } else {
+ realm = assume_own_realm();
+ }
+
+ ads = ads_init(realm, opt_target_workgroup, opt_host);
if (!opt_user_name) {
opt_user_name = "administrator";
retry:
if (!opt_password && need_password && !opt_machine_pass) {
- char *prompt;
+ char *prompt = NULL;
asprintf(&prompt,"%s's password: ", opt_user_name);
+ if (!prompt) {
+ ads_destroy(&ads);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
opt_password = getpass(prompt);
free(prompt);
}
if (opt_password) {
use_in_memory_ccache();
+ SAFE_FREE(ads->auth.password);
ads->auth.password = smb_xstrdup(opt_password);
}
+ ads->auth.flags |= auth_flags;
+ SAFE_FREE(ads->auth.user_name);
ads->auth.user_name = smb_xstrdup(opt_user_name);
/*
* This is only used to establish the connection.
*/
if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
- *cp++ = '\0';
- ads->auth.realm = smb_xstrdup(cp);
- strupper_m(ads->auth.realm);
+ *cp++ = '\0';
+ SAFE_FREE(ads->auth.realm);
+ ads->auth.realm = smb_xstrdup(cp);
+ strupper_m(ads->auth.realm);
}
status = ads_connect(ads);
if (!ADS_ERR_OK(status)) {
- if (!need_password && !second_time) {
+
+ if (NT_STATUS_EQUAL(ads_ntstatus(status),
+ NT_STATUS_NO_LOGON_SERVERS)) {
+ DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
+ ads_destroy(&ads);
+ return status;
+ }
+
+ if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
need_password = True;
second_time = True;
goto retry;
} else {
- DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
- return NULL;
+ ads_destroy(&ads);
+ return status;
}
}
- return ads;
+
+ /* when contacting our own domain, make sure we use the closest DC.
+ * This is done by reconnecting to ADS because only the first call to
+ * ads_connect will give us our own sitename */
+
+ if ((only_own_domain || !opt_host) && !tried_closest_dc) {
+
+ tried_closest_dc = True; /* avoid loop */
+
+ if (!ads->config.tried_closest_dc) {
+
+ namecache_delete(ads->server.realm, 0x1C);
+ namecache_delete(ads->server.workgroup, 0x1C);
+
+ ads_destroy(&ads);
+ ads = NULL;
+
+ goto retry_connect;
+ }
+ }
+
+ *ads_ret = ads;
+ return status;
}
+ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
+{
+ return ads_startup_int(only_own_domain, 0, ads);
+}
+
+ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads)
+{
+ return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
+}
/*
Check to see if connection can be made via ads.
ads_startup() stores the password in opt_password if it needs to so
that rpc or rap can use it without re-prompting.
*/
-int net_ads_check(void)
+static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
{
ADS_STRUCT *ads;
ADS_STATUS status;
- if ( (ads = ads_init( lp_realm(), lp_workgroup(), NULL )) == NULL ) {
+ if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
return -1;
}
return 0;
}
+int net_ads_check_our_domain(void)
+{
+ return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
+}
+
+int net_ads_check(void)
+{
+ return net_ads_check_int(NULL, opt_workgroup, opt_host);
+}
/*
determine the netbios workgroup name for a domain
*/
static int net_ads_workgroup(int argc, const char **argv)
{
ADS_STRUCT *ads;
- ADS_STATUS status;
- const char *realm = NULL;
struct cldap_netlogon_reply reply;
- if ( strequal(lp_workgroup(), opt_target_workgroup ) )
- realm = lp_realm();
-
- ads = ads_init(realm, opt_target_workgroup, opt_host);
- if (ads) {
- ads->auth.flags |= ADS_AUTH_NO_BIND;
- }
-
- status = ads_connect(ads);
- if (!ADS_ERR_OK(status) || !ads) {
+ if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
d_fprintf(stderr, "Didn't find the cldap server!\n");
return -1;
}
ADS_STRUCT *ads;
ADS_STATUS status;
char *upn, *userdn;
- void *res=NULL;
+ LDAPMessage *res=NULL;
int rc = -1;
+ char *ou_str = NULL;
if (argc < 1) return net_ads_user_usage(argc, argv);
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
goto done;
}
- if (opt_container == NULL) {
- opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+ if (opt_container) {
+ ou_str = SMB_STRDUP(opt_container);
+ } else {
+ ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
}
- status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
+ status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
if (!ADS_ERR_OK(status)) {
d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
if (res)
ads_msgfree(ads, res);
ads_destroy(&ads);
+ SAFE_FREE(ou_str);
return rc;
}
{
ADS_STRUCT *ads;
ADS_STATUS rc;
- void *res;
+ LDAPMessage *res;
const char *attrs[] = {"memberOf", NULL};
char *searchstring=NULL;
char **grouplist;
return -1;
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
SAFE_FREE(escaped_user);
return -1;
}
return -1;
}
- grouplist = ldap_get_values(ads->ld, res, "memberOf");
+ grouplist = ldap_get_values((LDAP *)ads->ld,
+ (LDAPMessage *)res, "memberOf");
if (grouplist) {
int i;
{
ADS_STRUCT *ads;
ADS_STATUS rc;
- void *res;
+ LDAPMessage *res = NULL;
char *userdn;
if (argc < 1) {
return net_ads_user_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
rc = ads_find_user_acct(ads, &res, argv[0]);
- if (!ADS_ERR_OK(rc)) {
- DEBUG(0, ("User %s does not exist\n", argv[0]));
+ if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
+ d_printf("User %s does not exist.\n", argv[0]);
+ ads_msgfree(ads, res);
ads_destroy(&ads);
return -1;
}
ads_msgfree(ads, res);
rc = ads_del_dn(ads, userdn);
ads_memfree(ads, userdn);
- if (!ADS_ERR_OK(rc)) {
+ if (ADS_ERR_OK(rc)) {
d_printf("User %s deleted\n", argv[0]);
ads_destroy(&ads);
return 0;
char *disp_fields[2] = {NULL, NULL};
if (argc == 0) {
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
shortattrs, usergrp_display,
disp_fields);
ads_destroy(&ads);
- return 0;
+ return ADS_ERR_OK(rc) ? 0 : -1;
}
return net_run_function(argc, argv, func, net_ads_user_usage);
{
ADS_STRUCT *ads;
ADS_STATUS status;
- void *res=NULL;
+ LDAPMessage *res=NULL;
int rc = -1;
+ char *ou_str = NULL;
if (argc < 1) {
return net_ads_group_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
if (ads_count_replies(ads, res)) {
d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
- ads_msgfree(ads, res);
goto done;
}
- if (opt_container == NULL) {
- opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+ if (opt_container) {
+ ou_str = SMB_STRDUP(opt_container);
+ } else {
+ ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
}
- status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
+ status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
if (ADS_ERR_OK(status)) {
d_printf("Group %s added\n", argv[0]);
if (res)
ads_msgfree(ads, res);
ads_destroy(&ads);
+ SAFE_FREE(ou_str);
return rc;
}
{
ADS_STRUCT *ads;
ADS_STATUS rc;
- void *res;
+ LDAPMessage *res = NULL;
char *groupdn;
if (argc < 1) {
return net_ads_group_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
rc = ads_find_user_acct(ads, &res, argv[0]);
- if (!ADS_ERR_OK(rc)) {
- DEBUG(0, ("Group %s does not exist\n", argv[0]));
+ if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
+ d_printf("Group %s does not exist.\n", argv[0]);
+ ads_msgfree(ads, res);
ads_destroy(&ads);
return -1;
}
ads_msgfree(ads, res);
rc = ads_del_dn(ads, groupdn);
ads_memfree(ads, groupdn);
- if (!ADS_ERR_OK(rc)) {
+ if (ADS_ERR_OK(rc)) {
d_printf("Group %s deleted\n", argv[0]);
ads_destroy(&ads);
return 0;
char *disp_fields[2] = {NULL, NULL};
if (argc == 0) {
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
disp_fields);
ads_destroy(&ads);
- return 0;
+ return ADS_ERR_OK(rc) ? 0 : -1;
}
return net_run_function(argc, argv, func, net_ads_group_usage);
}
{
ADS_STRUCT *ads;
ADS_STATUS rc;
- void *res;
+ LDAPMessage *res;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
return 0;
}
+/*******************************************************************
+ Leave an AD domain. Windows XP disables the machine account.
+ We'll try the same. The old code would do an LDAP delete.
+ That only worked using the machine creds because added the machine
+ with full control to the computer object's ACL.
+*******************************************************************/
+
static int net_ads_leave(int argc, const char **argv)
{
ADS_STRUCT *ads = NULL;
- ADS_STATUS rc;
+ ADS_STATUS adsret;
+ NTSTATUS status;
+ int ret = -1;
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *ctx;
+ DOM_SID *dom_sid = NULL;
+ char *short_domain_name = NULL;
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
return -1;
}
- if (!opt_password) {
- net_use_machine_password();
+ if (!(ctx = talloc_init("net_ads_leave"))) {
+ d_fprintf(stderr, "Could not initialise talloc context.\n");
+ return -1;
}
- if (!(ads = ads_startup())) {
+ /* The finds a DC and takes care of getting the
+ user creds if necessary */
+
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
- rc = ads_leave_realm(ads, global_myname());
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "Failed to delete host '%s' from the '%s' realm.\n",
+ /* make RPC calls here */
+
+ if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
+ ads->config.ldap_server_name)) )
+ {
+ goto done;
+ }
+
+ if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
+ goto done;
+ }
+
+ saf_delete( short_domain_name );
+
+ status = netdom_leave_domain(ctx, cli, dom_sid);
+
+ /* Try and delete it via LDAP - the old way we used to. */
+
+ adsret = ads_leave_realm(ads, global_myname());
+ if (ADS_ERR_OK(adsret)) {
+ d_printf("Deleted account for '%s' in realm '%s'\n",
global_myname(), ads->config.realm);
- ads_destroy(&ads);
- return -1;
+ ret = 0;
+ } else {
+ /* We couldn't delete it - see if the disable succeeded. */
+ if (NT_STATUS_IS_OK(status)) {
+ d_printf("Disabled account for '%s' in realm '%s'\n",
+ global_myname(), ads->config.realm);
+ ret = 0;
+ } else {
+ d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
+ global_myname(), ads->config.realm);
+ }
}
- d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
+done:
+
+ if ( cli )
+ cli_shutdown(cli);
+
ads_destroy(&ads);
- return 0;
+ TALLOC_FREE( ctx );
+
+ return ret;
}
-static int net_ads_join_ok(void)
+static NTSTATUS net_ads_join_ok(void)
{
ADS_STRUCT *ads = NULL;
+ ADS_STATUS status;
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
- return -1;
+ return NT_STATUS_ACCESS_DENIED;
}
net_use_machine_password();
- if (!(ads = ads_startup())) {
- return -1;
+ status = ads_startup(True, &ads);
+ if (!ADS_ERR_OK(status)) {
+ return ads_ntstatus(status);
}
ads_destroy(&ads);
- return 0;
+ return NT_STATUS_OK;
}
/*
*/
int net_ads_testjoin(int argc, const char **argv)
{
+ NTSTATUS status;
use_in_memory_ccache();
/* Display success or failure */
- if (net_ads_join_ok() != 0) {
- fprintf(stderr,"Join to domain is not valid\n");
+ status = net_ads_join_ok();
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr,"Join to domain is not valid: %s\n",
+ get_friendly_nt_error_msg(status));
return -1;
}
Simple configu checks before beginning the join
********************************************************************/
-static int check_ads_config( void )
+static NTSTATUS check_ads_config( void )
{
if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
d_printf("Host is not configured as a member server.\n");
- return -1;
+ return NT_STATUS_INVALID_DOMAIN_ROLE;
}
if (strlen(global_myname()) > 15) {
d_printf("Our netbios name can be at most 15 chars long, "
- "\"%s\" is %d chars long\n",
- global_myname(), strlen(global_myname()));
- return -1;
+ "\"%s\" is %u chars long\n", global_myname(),
+ (unsigned int)strlen(global_myname()));
+ return NT_STATUS_NAME_TOO_LONG;
}
if ( lp_security() == SEC_ADS && !*lp_realm()) {
- d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
- "join to succeed.\n");
- return -1;
+ d_fprintf(stderr, "realm must be set in in %s for ADS "
+ "join to succeed.\n", dyn_CONFIGFILE);
+ return NT_STATUS_INVALID_PARAMETER;
}
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
- return -1;
+ /* This is a good bet for failure of secrets_init ... */
+ return NT_STATUS_ACCESS_DENIED;
}
- return 0;
+ return NT_STATUS_OK;
}
/*******************************************************************
- Store the machine password and domain SID
+ Do the domain join
********************************************************************/
-static int store_domain_account( const char *domain, DOM_SID *sid, const char *pw )
+static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
+ struct in_addr *ip, char **domain,
+ DOM_SID **dom_sid,
+ const char *password)
{
- if (!secrets_store_domain_sid(domain, sid)) {
- DEBUG(1,("Failed to save domain sid\n"));
- return -1;
- }
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ struct cli_state *cli = NULL;
- if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
- DEBUG(1,("Failed to save machine password\n"));
- return -1;
+ ret = connect_to_ipc_krb5(&cli, ip, servername);
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ goto done;
}
-
- return 0;
-}
-
-/*******************************************************************
- ********************************************************************/
-
-static NTSTATUS join_fetch_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
-{
- struct rpc_pipe_client *pipe_hnd = NULL;
- POLICY_HND lsa_pol;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- char *domain = NULL;
-
- if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
- DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
- nt_errstr(status) ));
- return status;
+
+ ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ goto done;
}
- status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
- SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
+ /* cli->server_domain is not filled in when using krb5
+ session setups */
- status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
- &lsa_pol, 5, &domain, sid);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
+ saf_store( *domain, cli->desthost );
- rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
- cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+ ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
- /* Bail out if domain didn't get set. */
- if (!domain) {
- DEBUG(0, ("Could not get domain name.\n"));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- return NT_STATUS_OK;
+done:
+ if ( cli )
+ cli_shutdown(cli);
+
+ return ret;
}
/*******************************************************************
- Do the domain join
+ Set a machines dNSHostName and servicePrincipalName attributes
********************************************************************/
-
-static NTSTATUS join_create_machine( TALLOC_CTX *mem_ctx, struct cli_state *cli,
- DOM_SID *dom_sid, const char *clear_pw )
-{
- struct rpc_pipe_client *pipe_hnd = NULL;
- POLICY_HND sam_pol, domain_pol, user_pol;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- char *acct_name;
- const char *const_acct_name;
- uint32 user_rid;
- uint32 num_rids, *name_types, *user_rids;
- uint32 flags = 0x3e8;
- uint32 acb_info = ACB_WSTRUST;
- uchar pwbuf[516];
- SAM_USERINFO_CTR ctr;
- SAM_USER_INFO_24 p24;
- SAM_USER_INFO_16 p16;
- uchar md4_trust_password[16];
-
- /* Open the domain */
-
- if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
- DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
- nt_errstr(status) ));
- return status;
- }
-
- status = rpccli_samr_connect(pipe_hnd, mem_ctx,
- SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
+static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
+{
+ ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
+ char *new_dn;
+ ADS_MODLIST mods;
+ const char *servicePrincipalName[3] = {NULL, NULL, NULL};
+ char *psp;
+ fstring my_fqdn;
+ LDAPMessage *res = NULL;
+ char *dn_string = NULL;
+ const char *machine_name = global_myname();
+ int count;
- status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- /* Create domain user */
+ if ( !machine_name ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
- acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
- strlower_m(acct_name);
- const_acct_name = acct_name;
-
- /* Don't try to set any acb_info flags other than ACB_WSTRUST */
-
- status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
- acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
-
- if ( !NT_STATUS_IS_OK(status)
- && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
- {
- d_fprintf(stderr, "Creation of workstation account failed\n");
-
- /* If NT_STATUS_ACCESS_DENIED then we have a valid
- username/password combo but the user does not have
- administrator access. */
-
- if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
- d_fprintf(stderr, "User specified does not have administrator privileges\n");
-
+ /* Find our DN */
+
+ status = ads_find_machine_acct(ads_s, &res, machine_name);
+ if (!ADS_ERR_OK(status))
return status;
+
+ if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
+ DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
+ return ADS_ERROR(LDAP_NO_MEMORY);
}
-
- /* We *must* do this.... don't ask... */
-
- if (NT_STATUS_IS_OK(status)) {
- rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+
+ if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
+ DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
+ goto done;
}
-
- status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
- &domain_pol, flags, 1, &const_acct_name,
- &num_rids, &user_rids, &name_types);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- if ( name_types[0] != SID_NAME_USER) {
- DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
- return NT_STATUS_INVALID_WORKSTATION;
+
+ new_dn = talloc_strdup(ctx, dn_string);
+ ads_memfree(ads_s, dn_string);
+ if (!new_dn) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
}
- user_rid = user_rids[0];
-
- /* Open handle on user */
+ /* Windows only creates HOST/shortname & HOST/fqdn. */
+
+ if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
+ goto done;
+ strupper_m(psp);
+ servicePrincipalName[0] = psp;
- status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+ name_to_fqdn(my_fqdn, machine_name);
+ strlower_m(my_fqdn);
+ if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
+ goto done;
+ servicePrincipalName[1] = psp;
- /* Create a random machine account password */
-
- E_md4hash( clear_pw, md4_trust_password);
- encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
-
- /* Set password on machine account */
-
- ZERO_STRUCT(ctr);
- ZERO_STRUCT(p24);
-
- init_sam_user_info24(&p24, (char *)pwbuf,24);
-
- ctr.switch_value = 24;
- ctr.info.id24 = &p24;
-
- status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
- 24, &cli->user_session_key, &ctr);
-
- /* Why do we have to try to (re-)set the ACB to be the same as what
- we passed in the samr_create_dom_user() call? When a NT
- workstation is joined to a domain by an administrator the
- acb_info is set to 0x80. For a normal user with "Add
- workstations to the domain" rights the acb_info is 0x84. I'm
- not sure whether it is supposed to make a difference or not. NT
- seems to cope with either value so don't bomb out if the set
- userinfo2 level 0x10 fails. -tpot */
-
- ZERO_STRUCT(ctr);
- ctr.switch_value = 16;
- ctr.info.id16 = &p16;
-
- /* Fill in the additional account flags now */
-
- acb_info |= ACB_PWNOEXP;
-#ifndef ENCTYPE_ARCFOUR_HMAC
- acb_info |= ACB_USE_DES_KEY_ONLY;
-#endif
-
- init_sam_user_info16(&p16, acb_info);
+ if (!(mods = ads_init_mods(ctx))) {
+ goto done;
+ }
+
+ /* fields of primary importance */
+
+ ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
+ ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
- status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
- &cli->user_session_key, &ctr);
+ status = ads_gen_mod(ads_s, new_dn, mods);
- rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
- cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+done:
+ ads_msgfree(ads_s, res);
return status;
}
/*******************************************************************
- Do the domain join
+ Set a machines dNSHostName and servicePrincipalName attributes
********************************************************************/
-static int net_join_domain( TALLOC_CTX *ctx, const char *servername,
- struct in_addr *ip, DOM_SID **dom_sid, const char *password )
+static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
{
- int ret = -1;
- struct cli_state *cli = NULL;
-
- if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, ip, servername)) )
- goto done;
+ ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
+ char *new_dn;
+ ADS_MODLIST mods;
+ LDAPMessage *res = NULL;
+ char *dn_string = NULL;
+ const char *machine_name = global_myname();
+ int count;
- saf_store( cli->server_domain, cli->desthost );
-
- if ( !NT_STATUS_IS_OK(join_fetch_domain_sid( ctx, cli, dom_sid )) )
+ if ( !machine_name ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* Find our DN */
+
+ status = ads_find_machine_acct(ads_s, &res, machine_name);
+ if (!ADS_ERR_OK(status))
+ return status;
+
+ if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
+ DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
+ DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
goto done;
-
- if ( !NT_STATUS_IS_OK(join_create_machine( ctx, cli, *dom_sid, password )) )
+ }
+
+ new_dn = talloc_strdup(ctx, dn_string);
+ ads_memfree(ads_s, dn_string);
+ if (!new_dn) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ /* now do the mods */
+
+ if (!(mods = ads_init_mods(ctx))) {
goto done;
+ }
+
+ /* fields of primary importance */
+
+ ads_mod_str(ctx, &mods, "userPrincipalName", upn);
- ret = 0;
+ status = ads_gen_mod(ads_s, new_dn, mods);
done:
- if ( cli )
- cli_shutdown(cli);
-
- return ret;
+ ads_msgfree(ads_s, res);
+
+ return status;
}
/*******************************************************************
Set a machines dNSHostName and servicePrincipalName attributes
********************************************************************/
-static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
+static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s,
+ const char *os_name, const char *os_version )
{
ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
- char *host_upn, *new_dn;
+ char *new_dn;
ADS_MODLIST mods;
- const char *servicePrincipalName[3] = {NULL, NULL, NULL};
- char *psp;
- fstring my_fqdn;
LDAPMessage *res = NULL;
char *dn_string = NULL;
const char *machine_name = global_myname();
int count;
+ char *os_sp = NULL;
- if ( !machine_name ) {
+ if ( !os_name || !os_version ) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
/* Find our DN */
- status = ads_find_machine_acct(ads_s, (void **)(void *)&res, machine_name);
+ status = ads_find_machine_acct(ads_s, &res, machine_name);
if (!ADS_ERR_OK(status))
return status;
if (!new_dn) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
+
+ /* now do the mods */
+
+ if (!(mods = ads_init_mods(ctx))) {
+ goto done;
+ }
+
+ os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING );
+
+ /* fields of primary importance */
+
+ ads_mod_str(ctx, &mods, "operatingSystem", os_name);
+ ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version);
+ if ( os_sp )
+ ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp);
+
+ status = ads_gen_mod(ads_s, new_dn, mods);
+
+done:
+ ads_msgfree(ads_s, res);
+ TALLOC_FREE( os_sp );
+
+ return status;
+}
+
+/*******************************************************************
+ join a domain using ADS (LDAP mods)
+ ********************************************************************/
+
+static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
+{
+ ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
+ char *ou_str = NULL;
+ char *dn = NULL;
+ LDAPMessage *res = NULL;
+ BOOL moved;
+
+ ou_str = ads_ou_string(ads, ou);
+ if (asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path) == -1) {
+ rc = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ rc = ads_search_dn(ads, &res, dn, NULL);
+ if (!ADS_ERR_OK(rc)) {
+ d_fprintf(stderr, "The specified OU does not exist.\n");
+ goto done;
+ }
+
+ /* Attempt to create the machine account and bail if this fails.
+ Assume that the admin wants exactly what they requested */
+
+ rc = ads_create_machine_acct( ads, global_myname(), dn );
+ if (ADS_ERR_OK(rc)) {
+ DEBUG(1, ("machine account created\n"));
+ goto done;
+ }
+ if ( !(rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS) ) {
+ DEBUG(1, ("machine account creation failed\n"));
+ goto done;
+ }
+
+ rc = ads_move_machine_acct(ads, global_myname(), dn, &moved);
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1, ("failure to locate/move pre-existing machine account\n"));
+ goto done;
+ }
+
+ if (moved) {
+ d_printf("The machine account was moved into the specified OU.\n");
+ } else {
+ d_printf("The machine account already exists in the specified OU.\n");
+ }
+
+done:
+ ads_msgfree(ads, res);
+ SAFE_FREE( ou_str );
+ SAFE_FREE( dn );
+
+ return rc;
+}
+
+/************************************************************************
+ ************************************************************************/
+
+static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
+{
+ uint32 domain_func;
+ ADS_STATUS status;
+ fstring salt;
+ char *std_salt;
+ LDAPMessage *res = NULL;
+ const char *machine_name = global_myname();
+
+ status = ads_domain_func_level( ads, &domain_func );
+ if ( !ADS_ERR_OK(status) ) {
+ DEBUG(2,("Failed to determine domain functional level!\n"));
+ return False;
+ }
+
+ /* go ahead and setup the default salt */
+
+ if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
+ d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
+ return False;
+ }
+
+ fstrcpy( salt, std_salt );
+ SAFE_FREE( std_salt );
+
+ /* if it's a Windows functional domain, we have to look for the UPN */
+
+ if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
+ char *upn;
+ int count;
+
+ status = ads_find_machine_acct(ads, &res, machine_name);
+ if (!ADS_ERR_OK(status)) {
+ return False;
+ }
+
+ if ( (count = ads_count_replies(ads, res)) != 1 ) {
+ DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
+ return False;
+ }
+
+ upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
+ if ( upn ) {
+ fstrcpy( salt, upn );
+ }
+
+ ads_msgfree(ads, res);
+ }
- /* Windows only creates HOST/shortname & HOST/fqdn. We create
- the UPN as well so that 'kinit -k' will work. You can only
- request a TGT for entries with a UPN in AD. */
-
- if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
- goto done;
- strupper_m(psp);
- servicePrincipalName[0] = psp;
+ return kerberos_secrets_store_des_salt( salt );
+}
- name_to_fqdn(my_fqdn, machine_name);
- strlower_m(my_fqdn);
- if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
- goto done;
- servicePrincipalName[1] = psp;
-
- if (!(host_upn = talloc_asprintf(ctx, "%s@%s", servicePrincipalName[0], ads_s->config.realm)))
- goto done;
+/*******************************************************************
+ Send a DNS update request
+*******************************************************************/
- /* now do the mods */
-
- if (!(mods = ads_init_mods(ctx))) {
+#if defined(WITH_DNS_UPDATES)
+#include "dns.h"
+DNS_ERROR DoDNSUpdate(char *pszServerName,
+ const char *pszDomainName,
+ const char *pszHostName,
+ const struct in_addr *iplist, int num_addrs );
+
+
+static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
+ const char *machine_name,
+ const struct in_addr *addrs,
+ int num_addrs)
+{
+ struct dns_rr_ns *nameservers = NULL;
+ int ns_count = 0;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ DNS_ERROR dns_err;
+ fstring dns_server;
+ const char *dnsdomain = NULL;
+ char *root_domain = NULL;
+
+ if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
+ d_printf("No DNS domain configured for %s. "
+ "Unable to perform DNS Update.\n", machine_name);
+ status = NT_STATUS_INVALID_PARAMETER;
goto done;
}
-
- /* fields of primary importance */
-
- ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
- ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+ dnsdomain++;
- status = ads_gen_mod(ads_s, new_dn, mods);
+ status = ads_dns_lookup_ns( ctx, 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
+ (rootDomainNamingContext in therootDSE) */
+
+ const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
+ LDAPMessage *msg = NULL;
+ char *root_dn;
+ ADS_STATUS ads_status;
+
+ if ( !ads->ld ) {
+ ads_status = ads_connect( ads );
+ if ( !ADS_ERR_OK(ads_status) ) {
+ DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
+ goto done;
+ }
+ }
+
+ ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", rootname_attrs, &msg);
+ if (!ADS_ERR_OK(ads_status)) {
+ goto done;
+ }
+
+ root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
+ if ( !root_dn ) {
+ ads_msgfree( ads, msg );
+ goto done;
+ }
+
+ root_domain = ads_build_domain( root_dn );
+
+ /* cleanup */
+ ads_msgfree( ads, msg );
+
+ /* try again for NS servers */
+
+ status = ads_dns_lookup_ns( ctx, 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 "
+ "realm\n", ads->config.realm));
+ goto done;
+ }
+
+ dnsdomain = root_domain;
+
+ }
+
+ /* Now perform the dns update - we'll try non-secure and if we fail,
+ we'll follow it up with a secure update */
+
+ fstrcpy( dns_server, nameservers[0].hostname );
+
+ dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
+ if (!ERR_DNS_IS_OK(dns_err)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
done:
- ads_msgfree(ads_s, res);
+
+ SAFE_FREE( root_domain );
return status;
}
+static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
+{
+ int num_addrs;
+ struct in_addr *iplist = NULL;
+ fstring machine_name;
+ NTSTATUS status;
-/*******************************************************************
- join a domain using ADS (LDAP mods)
- ********************************************************************/
+ name_to_fqdn( machine_name, global_myname() );
+ strlower_m( machine_name );
-static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
-{
- ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
- char *dn, *ou_str;
- LDAPMessage *res = NULL;
+ /* Get our ip address (not the 127.0.0.x address but a real ip
+ * address) */
- ou_str = ads_ou_string(ads, ou);
- asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
- free(ou_str);
+ num_addrs = get_my_ip_address( &iplist );
+ if ( num_addrs <= 0 ) {
+ DEBUG(4,("net_ads_join: Failed to find my non-loopback IP "
+ "addresses!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
- rc = ads_search_dn(ads, (void**)&res, dn, NULL);
- ads_msgfree(ads, res);
+ status = net_update_dns_internal(mem_ctx, ads, machine_name,
+ iplist, num_addrs);
+ SAFE_FREE( iplist );
+ return status;
+}
+#endif
- if (ADS_ERR_OK(rc)) {
- /* Attempt to create the machine account and bail if this fails.
- Assume that the admin wants exactly what they requested */
- rc = ads_create_machine_acct( ads, global_myname(), dn );
- if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
- rc = ADS_SUCCESS;
- }
- }
+/*******************************************************************
+ utility function to parse an integer parameter from
+ "parameter = value"
+**********************************************************/
+static char* get_string_param( const char* param )
+{
+ char *p;
+
+ if ( (p = strchr( param, '=' )) == NULL )
+ return NULL;
+
+ return (p+1);
+}
- SAFE_FREE( dn );
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_join_usage(int argc, const char **argv)
+{
+ d_printf("net ads join [options]\n");
+ d_printf("Valid options:\n");
+ d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
+ d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
+ d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
+ d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
+ d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
+ d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
+ d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\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");
+ d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
+ d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
+ d_printf(" the two other attributes.\n");
- return rc;
+ return -1;
}
/*******************************************************************
- join a domain using ADS (LDAP mods)
********************************************************************/
int net_ads_join(int argc, const char **argv)
{
- ADS_STRUCT *ads;
+ ADS_STRUCT *ads = NULL;
ADS_STATUS status;
+ NTSTATUS nt_status;
char *machine_account = NULL;
- const char *short_domain_name = NULL;
+ char *short_domain_name = NULL;
char *tmp_password, *password;
- struct cldap_netlogon_reply cldap_reply;
- TALLOC_CTX *ctx;
+ TALLOC_CTX *ctx = NULL;
DOM_SID *domain_sid = NULL;
+ BOOL createupn = False;
+ const char *machineupn = NULL;
+ const char *create_in_ou = NULL;
+ int i;
+ fstring dc_name;
+ struct in_addr dcip;
+ const char *os_name = NULL;
+ const char *os_version = NULL;
- if ( check_ads_config() != 0 ) {
+ nt_status = check_ads_config();
+ if (!NT_STATUS_IS_OK(nt_status)) {
d_fprintf(stderr, "Invalid configuration. Exiting....\n");
- return -1;
+ goto fail;
}
- if ( (ads = ads_startup()) == NULL ) {
- return -1;
+ /* find a DC to initialize the server affinity cache */
+
+ get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcip );
+
+ status = ads_startup(True, &ads);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
+ nt_status = ads_ntstatus(status);
+ goto fail;
}
if (strcmp(ads->config.realm, lp_realm()) != 0) {
- d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
+ d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
"(%s) DO NOT match. Aborting join\n", ads->config.realm,
- lp_realm());
- ads_destroy(&ads);
- return -1;
+ dyn_CONFIGFILE, lp_realm());
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
}
if (!(ctx = talloc_init("net_ads_join"))) {
- DEBUG(0, ("Could not initialise talloc context\n"));
- return -1;
+ d_fprintf(stderr, "Could not initialise talloc context.\n");
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ /* process additional command line args */
+
+ for ( i=0; i<argc; i++ ) {
+ if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
+ createupn = True;
+ machineupn = get_string_param(argv[i]);
+ }
+ else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
+ if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a valid OU path.\n");
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
+ if ( (os_name = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a operating system name.\n");
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+ else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
+ if ( (os_version = get_string_param(argv[i])) == NULL ) {
+ d_fprintf(stderr, "Please supply a valid operating system version.\n");
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+ else {
+ d_fprintf(stderr, "Bad option: %s\n", argv[i]);
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
}
- /* If we were given an OU, try to create the machine in the OU account
- first and then do the normal RPC join */
+ /* If we were given an OU, try to create the machine in
+ the OU account first and then do the normal RPC join */
- if ( argc > 0 ) {
- status = net_precreate_machine_acct( ads, argv[0] );
+ if ( create_in_ou ) {
+ status = net_precreate_machine_acct( ads, create_in_ou );
if ( !ADS_ERR_OK(status) ) {
d_fprintf( stderr, "Failed to pre-create the machine object "
- "in OU %s.\n", argv[0]);
- ads_destroy( &ads );
- return -1;
+ "in OU %s.\n", create_in_ou);
+ DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
+ ads_errstr(status)));
+ nt_status = ads_ntstatus(status);
+ goto fail;
}
}
tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
password = talloc_strdup(ctx, tmp_password);
- if ( net_join_domain( ctx, ads->config.ldap_server_name, &ads->ldap_ip, &domain_sid, password ) != 0 ) {
- d_fprintf(stderr, "Failed to join domain!\n");
- return -1;
+ nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
+ &ads->ldap_ip, &short_domain_name, &domain_sid, password);
+ if ( !NT_STATUS_IS_OK(nt_status) ) {
+ DEBUG(1, ("call of net_join_domain failed: %s\n",
+ get_friendly_nt_error_msg(nt_status)));
+ goto fail;
}
-
+
/* Check the short name of the domain */
- ZERO_STRUCT( cldap_reply );
-
- if ( ads_cldap_netlogon( ads->config.ldap_server_name,
- ads->server.realm, &cldap_reply ) )
- {
- short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
- if ( !strequal(lp_workgroup(), short_domain_name) ) {
- d_printf("The workgroup in smb.conf does not match the short\n");
- d_printf("domain name obtained from the server.\n");
- d_printf("Using the name [%s] from the server.\n", short_domain_name);
- d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
- }
- } else {
- short_domain_name = lp_workgroup();
+ if ( !strequal(lp_workgroup(), short_domain_name) ) {
+ d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
+ d_printf("domain name obtained from the server.\n");
+ d_printf("Using the name [%s] from the server.\n", short_domain_name);
+ d_printf("You should set \"workgroup = %s\" in %s.\n",
+ short_domain_name, dyn_CONFIGFILE);
}
d_printf("Using short domain name -- %s\n", short_domain_name);
neede to bootstrap winbindd's first connection to the DC to get the real
short domain name --jerry */
- if ( (store_domain_account( lp_workgroup(), domain_sid, password ) == -1)
- || (store_domain_account( short_domain_name, domain_sid, password ) == -1) )
+ if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
+ || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
{
- ads_destroy(&ads);
- return -1;
+ /* issue an internal error here for now.
+ * everything else would mean changing tdb routines. */
+ nt_status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
}
/* Verify that everything is ok */
if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
d_fprintf(stderr, "Failed to verify membership in domain!\n");
- return -1;
+ goto fail;
}
/* create the dNSHostName & servicePrincipalName values */
status = net_set_machine_spn( ctx, ads );
if ( !ADS_ERR_OK(status) ) {
- d_fprintf(stderr, "Failed to set servicePrincipalNames. Only NTLM authentication will be possible.\n");
- d_fprintf(stderr, "Please ensure that the DNS domain of this server matches the AD domain,\n");
- d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
- /* don't fail */
+ d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
+ d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
+ d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
+
+ /* Disable the machine account in AD. Better to fail than to leave
+ a confused admin. */
+
+ if ( net_ads_leave( 0, NULL ) != 0 ) {
+ d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
+ }
+
+ /* clear out the machine password */
+
+ netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
+ netdom_store_machine_account( short_domain_name, domain_sid, "" );
+
+ nt_status = ads_ntstatus(status);
+ goto fail;
}
-#if defined(HAVE_KRB5)
- if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
- d_fprintf(stderr, "asprintf failed\n");
- ads_destroy(&ads);
- return -1;
+ if ( !net_derive_salting_principal( ctx, ads ) ) {
+ DEBUG(1,("Failed to determine salting principal\n"));
+ goto fail;
}
- if (!kerberos_derive_salting_principal(machine_account)) {
- DEBUG(1,("Failed to determine salting principal\n"));
- ads_destroy(&ads);
- return -1;
+ if ( createupn ) {
+ pstring upn;
+
+ /* default to using the short UPN name */
+ if ( !machineupn ) {
+ snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
+ ads->config.realm );
+ machineupn = upn;
+ }
+
+ status = net_set_machine_upn( ctx, ads, machineupn );
+ if ( !ADS_ERR_OK(status) ) {
+ d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
+ }
}
- if (!kerberos_derive_cifs_salting_principals()) {
- DEBUG(1,("Failed to determine salting principals\n"));
- ads_destroy(&ads);
- return -1;
+ /* Try to set the operatingSystem attributes if asked */
+
+ if ( os_name && os_version ) {
+ status = net_set_os_attributes( ctx, ads, os_name, os_version );
+ if ( !ADS_ERR_OK(status) ) {
+ d_fprintf(stderr, "Failed to set operatingSystem attributes. "
+ "Are you a Domain Admin?\n");
+ }
}
-
+
/* Now build the keytab, using the same ADS connection */
+
if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
DEBUG(1,("Error creating host keytab!\n"));
}
+
+#if defined(WITH_DNS_UPDATES)
+ /* We enter this block with user creds */
+ ads_kdestroy( NULL );
+ ads_destroy(&ads);
+ ads = NULL;
+
+ if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
+ /* kinit with the machine password */
+
+ use_in_memory_ccache();
+ asprintf( &ads->auth.user_name, "%s$", global_myname() );
+ ads->auth.password = secrets_fetch_machine_password(
+ lp_workgroup(), NULL, NULL );
+ ads->auth.realm = SMB_STRDUP( lp_realm() );
+ ads_kinit_password( ads );
+ }
+
+ if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
+ d_fprintf( stderr, "DNS update failed!\n" );
+ }
+
+ /* exit from this block using machine creds */
#endif
- d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
+ d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
+
+ SAFE_FREE(machine_account);
+ TALLOC_FREE( ctx );
+ ads_destroy(&ads);
+
+ return 0;
+
+fail:
+ /* issue an overall failure message at the end. */
+ d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
SAFE_FREE(machine_account);
TALLOC_FREE( ctx );
+ ads_destroy(&ads);
+
+ return -1;
+
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_dns_usage(int argc, const char **argv)
+{
+#if defined(WITH_DNS_UPDATES)
+ d_printf("net ads dns <command>\n");
+ d_printf("Valid commands:\n");
+ d_printf(" register Issue a dynamic DNS update request for our hostname\n");
+
+ return 0;
+#else
+ d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
+ return -1;
+#endif
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static int net_ads_dns_register(int argc, const char **argv)
+{
+#if defined(WITH_DNS_UPDATES)
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ TALLOC_CTX *ctx;
+
+#ifdef DEVELOPER
+ talloc_enable_leak_report();
+#endif
+
+ if (argc > 0) {
+ d_fprintf(stderr, "net ads dns register <name> <ip>\n");
+ return -1;
+ }
+
+ if (!(ctx = talloc_init("net_ads_dns"))) {
+ d_fprintf(stderr, "Could not initialise talloc context\n");
+ return -1;
+ }
+
+ status = ads_startup(True, &ads);
+ if ( !ADS_ERR_OK(status) ) {
+ DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
+ TALLOC_FREE(ctx);
+ return -1;
+ }
+
+ if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
+ d_fprintf( stderr, "DNS update failed!\n" );
+ ads_destroy( &ads );
+ TALLOC_FREE( ctx );
+ return -1;
+ }
+
+ d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
+
ads_destroy(&ads);
+ TALLOC_FREE( ctx );
+
+ return 0;
+#else
+ d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
+ return -1;
+#endif
+}
+
+#if defined(WITH_DNS_UPDATES)
+DNS_ERROR do_gethostbyname(const char *server, const char *host);
+#endif
+
+static int net_ads_dns_gethostbyname(int argc, const char **argv)
+{
+#if defined(WITH_DNS_UPDATES)
+ DNS_ERROR err;
+#ifdef DEVELOPER
+ talloc_enable_leak_report();
+#endif
+
+ if (argc != 2) {
+ d_fprintf(stderr, "net ads dns gethostbyname <server> "
+ "<name>\n");
+ return -1;
+ }
+
+ err = do_gethostbyname(argv[0], argv[1]);
+
+ d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
+#endif
return 0;
}
+static int net_ads_dns(int argc, const char *argv[])
+{
+ struct functable func[] = {
+ {"REGISTER", net_ads_dns_register},
+ {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
+ {NULL, NULL}
+ };
+
+ return net_run_function(argc, argv, func, net_ads_dns_usage);
+}
+
/*******************************************************************
********************************************************************/
{
ADS_STRUCT *ads;
ADS_STATUS rc;
- void *res = NULL;
+ LDAPMessage *res = NULL;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
ADS_STRUCT *ads;
ADS_STATUS rc;
const char *servername, *printername;
- void *res = NULL;
+ LDAPMessage *res = NULL;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
rc = ads_find_printer_on_server(ads, &res, printername, servername);
if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
+ d_fprintf(stderr, "Server '%s' not found: %s\n",
+ servername, ads_errstr(rc));
ads_msgfree(ads, res);
ads_destroy(&ads);
return -1;
return 0;
}
-void do_drv_upgrade_printer(int msg_type, struct process_id src,
- void *buf, size_t len)
-{
- return;
-}
-
static int net_ads_printer_publish(int argc, const char **argv)
{
ADS_STRUCT *ads;
TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
ADS_MODLIST mods = ads_init_mods(mem_ctx);
char *prt_dn, *srv_dn, **srv_cn;
- void *res = NULL;
+ char *srv_cn_escaped = NULL, *printername_escaped = NULL;
+ LDAPMessage *res = NULL;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+ talloc_destroy(mem_ctx);
return -1;
}
if (argc < 1) {
+ talloc_destroy(mem_ctx);
return net_ads_printer_usage(argc, argv);
}
d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
"for %s\n", servername, printername);
ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
return -1;
}
d_fprintf(stderr, "Could not find machine account for server %s\n",
servername);
ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
return -1;
}
- srv_dn = ldap_get_dn(ads->ld, res);
+ srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
srv_cn = ldap_explode_dn(srv_dn, 1);
- asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
+ srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
+ printername_escaped = escape_rdn_val_string_alloc(printername);
+ if (!srv_cn_escaped || !printername_escaped) {
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(printername_escaped);
+ d_fprintf(stderr, "Internal error, out of memory!");
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
+
+ asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
+
+ SAFE_FREE(srv_cn_escaped);
+ SAFE_FREE(printername_escaped);
pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
if (!pipe_hnd) {
d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
servername);
+ SAFE_FREE(prt_dn);
ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
return -1;
}
- get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
- printername);
+ if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
+ printername))) {
+ SAFE_FREE(prt_dn);
+ ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
+ return -1;
+ }
rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
if (!ADS_ERR_OK(rc)) {
d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
+ SAFE_FREE(prt_dn);
ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
return -1;
}
d_printf("published printer\n");
+ SAFE_FREE(prt_dn);
ads_destroy(&ads);
+ talloc_destroy(mem_ctx);
return 0;
}
ADS_STATUS rc;
const char *servername;
char *prt_dn;
- void *res = NULL;
+ LDAPMessage *res = NULL;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
/* use the realm so we can eventually change passwords for users
in realms other than default */
- if (!(ads = ads_init(realm, NULL, NULL))) {
+ if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
return -1;
}
ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
auth_password, user, new_password, ads->auth.time_offset);
if (!ADS_ERR_OK(ret)) {
- d_fprintf(stderr, "Password change failed :-( ...\n");
+ d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
ads_destroy(&ads);
return -1;
}
use_in_memory_ccache();
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
fstrcpy(my_name, global_myname());
strlower_m(my_name);
- asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
- d_printf("Changing password for principal: HOST/%s\n", host_principal);
+ asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
+ d_printf("Changing password for principal: %s\n", host_principal);
ret = ads_change_trust_account_password(ads, host_principal);
if (!ADS_ERR_OK(ret)) {
- d_fprintf(stderr, "Password change failed :-( ...\n");
+ d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
ads_destroy(&ads);
SAFE_FREE(host_principal);
return -1;
}
- d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
+ d_printf("Password change for principal %s succeeded.\n", host_principal);
if (lp_use_kerberos_keytab()) {
d_printf("Attempting to update system keytab with new password.\n");
ADS_STATUS rc;
const char *ldap_exp;
const char **attrs;
- void *res = NULL;
+ LDAPMessage *res = NULL;
if (argc < 1) {
return net_ads_search_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
"The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
"to show in the results\n\n"\
"Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
+ "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
);
net_common_flags_usage(argc, argv);
return -1;
ADS_STATUS rc;
const char *dn;
const char **attrs;
- void *res = NULL;
+ LDAPMessage *res = NULL;
if (argc < 1) {
return net_ads_dn_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
ADS_STATUS rc;
const char *sid_string;
const char **attrs;
- void *res = NULL;
+ LDAPMessage *res = NULL;
DOM_SID sid;
if (argc < 1) {
return net_ads_sid_usage(argc, argv);
}
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(False, &ads))) {
return -1;
}
d_printf(
"net ads keytab <COMMAND>\n"\
"<COMMAND> can be either:\n"\
-" CREATE Creates a fresh keytab\n"\
" ADD Adds new service principal\n"\
+" CREATE Creates a fresh keytab\n"\
" FLUSH Flushes out all keytab entries\n"\
" HELP Prints this help message\n"\
-"The ADD command will take arguments, the other commands\n"\
+" LIST List the keytab\n"\
+"The ADD and LIST command will take arguments, the other commands\n"\
"will not take any arguments. The arguments given to ADD\n"\
"should be a list of principals to add. For example, \n"\
" net ads keytab add srv1 srv2\n"\
"will add principals for the services srv1 and srv2 to the\n"\
"system's keytab.\n"\
+"The LIST command takes a keytabname.\n"\
"\n"
);
return -1;
int ret;
ADS_STRUCT *ads;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
ret = ads_keytab_flush(ads);
ADS_STRUCT *ads;
d_printf("Processing principals to add...\n");
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
for (i = 0; i < argc; i++) {
ADS_STRUCT *ads;
int ret;
- if (!(ads = ads_startup())) {
+ if (!ADS_ERR_OK(ads_startup(True, &ads))) {
return -1;
}
ret = ads_keytab_create_default(ads);
return ret;
}
+static int net_ads_keytab_list(int argc, const char **argv)
+{
+ const char *keytab = NULL;
+
+ if (argc >= 1) {
+ keytab = argv[0];
+ }
+
+ return ads_keytab_list(keytab);
+}
+
+
int net_ads_keytab(int argc, const char **argv)
{
struct functable func[] = {
- {"CREATE", net_ads_keytab_create},
{"ADD", net_ads_keytab_add},
+ {"CREATE", net_ads_keytab_create},
{"FLUSH", net_ads_keytab_flush},
{"HELP", net_ads_keytab_usage},
+ {"LIST", net_ads_keytab_list},
{NULL, NULL}
};
{"GROUP", net_ads_group_usage},
{"PRINTER", net_ads_printer_usage},
{"SEARCH", net_ads_search_usage},
-#if 0
{"INFO", net_ads_info},
- {"JOIN", net_ads_join},
- {"JOIN2", net_ads_join2},
+ {"JOIN", net_ads_join_usage},
+ {"DNS", net_ads_dns_usage},
{"LEAVE", net_ads_leave},
{"STATUS", net_ads_status},
{"PASSWORD", net_ads_password},
{"CHANGETRUSTPW", net_ads_changetrustpw},
-#endif
{NULL, NULL}
};
{"STATUS", net_ads_status},
{"USER", net_ads_user},
{"GROUP", net_ads_group},
+ {"DNS", net_ads_dns},
{"PASSWORD", net_ads_password},
{"CHANGETRUSTPW", net_ads_changetrustpw},
{"PRINTER", net_ads_printer},
{"WORKGROUP", net_ads_workgroup},
{"LOOKUP", net_ads_lookup},
{"KEYTAB", net_ads_keytab},
+ {"GPO", net_ads_gpo},
{"HELP", net_ads_help},
{NULL, NULL}
};
return -1;
}
+int net_ads_check_our_domain(void)
+{
+ return -1;
+}
+
int net_ads(int argc, const char **argv)
{
return net_ads_usage(argc, argv);
}
-#endif
+#endif /* WITH_ADS */