r15560: Since the hotel doesn't have Sci-Fi and no "Doctor Who"....
authorGerald Carter <jerry@samba.org>
Sat, 13 May 2006 04:39:19 +0000 (04:39 +0000)
committerGerald Carter <jerry@samba.org>
Sat, 13 May 2006 04:39:19 +0000 (04:39 +0000)
Re-add the capability to specify an OU in which to create
the machine account.  Done via LDAP prior to the RPC join.

source/libads/ldap.c
source/utils/net_ads.c

index 6f698dc3a937fa6c76032b298e3030bbb8fb83e0..63056645cdda31f991476233cbf76e5ce402aa56 100644 (file)
@@ -980,6 +980,7 @@ ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
                               name, (const void **) vals);
 }
 
+#if 0
 /**
  * Add a single ber-encoded value to a mod list
  * @param ctx An initialized TALLOC_CTX
@@ -1000,6 +1001,7 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
        return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
                               name, (const void **) values);
 }
+#endif
 
 /**
  * Perform an ldap modify
@@ -1421,105 +1423,33 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n
  * @return 0 upon success, or non-zero otherwise
 **/
 
-static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name, 
-                                      uint32 account_type,
-                                      const char *org_unit)
+ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, 
+                                   const char *org_unit)
 {
-       ADS_STATUS ret, status;
-       char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
+       ADS_STATUS ret;
+       char *samAccountName, *controlstr;
        TALLOC_CTX *ctx;
        ADS_MODLIST mods;
+       char *new_dn;
        const char *objectClass[] = {"top", "person", "organizationalPerson",
                                     "user", "computer", NULL};
-       const char *servicePrincipalName[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
-       char *psp, *psp2, *psp3, *psp4;
-       unsigned acct_control;
-       unsigned exists=0;
-       fstring my_fqdn;
        LDAPMessage *res = NULL;
-       int i, next_spn;
-
+       uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
+                               UF_DONT_EXPIRE_PASSWD |\
+                               UF_ACCOUNTDISABLE );
+                             
        if (!(ctx = talloc_init("ads_add_machine_acct")))
                return ADS_ERROR(LDAP_NO_MEMORY);
 
        ret = ADS_ERROR(LDAP_NO_MEMORY);
+               
+       new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_name, org_unit);
+       samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
 
-       name_to_fqdn(my_fqdn, machine_name);
-
-       status = ads_find_machine_acct(ads, (void **)(void *)&res, machine_name);
-       if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
-               char *dn_string = ads_get_dn(ads, res);
-               if (!dn_string) {
-                       DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
-                       goto done;
-               }
-               new_dn = talloc_strdup(ctx, dn_string);
-               ads_memfree(ads,dn_string);
-               DEBUG(0, ("ads_add_machine_acct: Host account for %s already exists - modifying old account\n",
-                       machine_name));
-               exists=1;
-       } else {
-               char *ou_str = ads_ou_string(ads,org_unit);
-               if (!ou_str) {
-                       DEBUG(1, ("ads_add_machine_acct: ads_ou_string returned NULL (malloc failure?)\n"));
-                       goto done;
-               }
-               new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", machine_name, ou_str, 
-                               ads->config.bind_path);
-
-               SAFE_FREE(ou_str);
-       }
-
-       if (!new_dn) {
-               goto done;
-       }
-
-       if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", machine_name)))
-               goto done;
-       if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))
-               goto done;
-       servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", machine_name);
-       psp = talloc_asprintf(ctx, "HOST/%s.%s", 
-                               machine_name, 
-                               ads->config.realm);
-       strlower_m(&psp[5]);
-       servicePrincipalName[1] = psp;
-       servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", machine_name);
-       psp2 = talloc_asprintf(ctx, "CIFS/%s.%s", 
-                              machine_name, 
-                              ads->config.realm);
-       strlower_m(&psp2[5]);
-       servicePrincipalName[3] = psp2;
-
-       /* Ensure servicePrincipalName[4] and [5] are unique. */
-       strlower_m(my_fqdn);
-       psp3 = talloc_asprintf(ctx, "CIFS/%s", my_fqdn);
-       strlower_m(&psp3[5]);
-
-       next_spn = 4;
-       for (i = 0; i < next_spn; i++) {
-               if (strequal(servicePrincipalName[i], psp3))
-                       break;
-       }
-       if (i == next_spn) {
-               servicePrincipalName[next_spn++] = psp3;
-       }
-
-       psp4 = talloc_asprintf(ctx, "HOST/%s", my_fqdn);
-       strlower_m(&psp4[5]);
-       for (i = 0; i < next_spn; i++) {
-               if (strequal(servicePrincipalName[i], psp4))
-                       break;
-       }
-       if (i == next_spn) {
-               servicePrincipalName[next_spn++] = psp4;
-       }
-
-       if (!(samAccountName = talloc_asprintf(ctx, "%s$", machine_name))) {
+       if ( !new_dn || !samAccountName ) {
                goto done;
        }
-
-       acct_control = account_type | UF_DONT_EXPIRE_PASSWD;
+       
 #ifndef ENCTYPE_ARCFOUR_HMAC
        acct_control |= UF_USE_DES_KEY_ONLY;
 #endif
@@ -1531,44 +1461,18 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name
        if (!(mods = ads_init_mods(ctx))) {
                goto done;
        }
-
-       if (!exists) {
-               ads_mod_str(ctx, &mods, "cn", machine_name);
-               ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
-               ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
-       }
+       
+       ads_mod_str(ctx, &mods, "cn", machine_name);
+       ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
+       ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
        ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
-       ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
-       ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
-       ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
-       ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
-       ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING);
-
-       if (!exists)  {
-               ret = ads_gen_add(ads, new_dn, mods);
-       } else {
-               ret = ads_gen_mod(ads, new_dn, mods);
-       }
 
-       if (!ADS_ERR_OK(ret)) {
-               goto done;
-       }
+       ret = ads_gen_add(ads, new_dn, mods);
 
-       /* Do not fail if we can't set security descriptor
-        * it shouldn't be mandatory and probably we just 
-        * don't have enough rights to do it.
-        */
-       if (!exists) {
-               status = ads_set_machine_sd(ads, machine_name, new_dn);
-       
-               if (!ADS_ERR_OK(status)) {
-                       DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
-                                       ads_errstr(status)));
-               }
-       }
 done:
        ads_msgfree(ads, res);
        talloc_destroy(ctx);
+       
        return ret;
 }
 
@@ -1783,58 +1687,6 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
        return ldap_count_entries(ads->ld, (LDAPMessage *)res);
 }
 
-/**
- * Join a machine to a realm
- *  Creates the machine account and sets the machine password
- * @param ads connection to ads server
- * @param machine name of host to add
- * @param org_unit Organizational unit to place machine in
- * @return status of join
- **/
-ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, 
-                         uint32 account_type, const char *org_unit)
-{
-       ADS_STATUS status;
-       LDAPMessage *res = NULL;
-       char *machine;
-
-       /* machine name must be lowercase */
-       machine = SMB_STRDUP(machine_name);
-       strlower_m(machine);
-
-       /*
-       status = ads_find_machine_acct(ads, (void **)&res, machine);
-       if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
-               DEBUG(0, ("Host account for %s already exists - deleting old account\n", machine));
-               status = ads_leave_realm(ads, machine);
-               if (!ADS_ERR_OK(status)) {
-                       DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n", 
-                                 machine, ads->config.realm));
-                       return status;
-               }
-       }
-       */
-
-       status = ads_add_machine_acct(ads, machine, account_type, org_unit);
-       if (!ADS_ERR_OK(status)) {
-               DEBUG(0, ("ads_join_realm: ads_add_machine_acct failed (%s): %s\n", machine, ads_errstr(status)));
-               SAFE_FREE(machine);
-               return status;
-       }
-
-       status = ads_find_machine_acct(ads, (void **)(void *)&res, machine);
-       if (!ADS_ERR_OK(status)) {
-               DEBUG(0, ("ads_join_realm: Host account test failed for machine %s\n", machine));
-               SAFE_FREE(machine);
-               return status;
-       }
-
-       SAFE_FREE(machine);
-       ads_msgfree(ads, res);
-
-       return status;
-}
-
 /**
  * Delete a machine from the realm
  * @param ads connection to ads server
@@ -1895,6 +1747,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
        return status;
 }
 
+#if 0 
 /**
  * add machine account to existing security descriptor 
  * @param ads connection to ads server
@@ -1902,7 +1755,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
  * @param dn DN of security descriptor
  * @return status
  **/
-ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
+static ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 {
        const char     *attrs[] = {"nTSecurityDescriptor", "objectSid", 0};
        char           *expr     = 0;
@@ -2016,6 +1869,7 @@ ads_set_sd_error:
        talloc_destroy(ctx);
        return ret;
 }
+#endif
 
 /**
  * pull the first entry from a ADS result
index e75090449d46a40460ca0910b1b127eecfe630cb..e913437ef1de650e78500435b5e68b5df66baf01 100644 (file)
@@ -4,6 +4,7 @@
    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+   Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
 
    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
@@ -1163,6 +1164,61 @@ done:
        return status;
 }
 
+
+/*******************************************************************
+  join a domain using ADS (LDAP mods)
+ ********************************************************************/
+
+static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
+{
+       ADS_STRUCT *ads_s = ads;
+       ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
+       char *dn, *ou_str;
+       LDAPMessage *res = NULL;
+
+       ou_str = ads_ou_string(ads, ou);
+       asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
+       free(ou_str);
+
+       if ( !ads->ld ) {
+               ads_s = ads_init( ads->config.realm, NULL, ads->config.ldap_server_name );
+
+               if ( ads_s ) {
+                       rc = ads_connect( ads_s );
+               }
+
+               if ( !ADS_ERR_OK(rc) ) {
+                       goto done;
+               }
+       }
+
+       rc = ads_search_dn(ads, (void**)&res, dn, NULL);
+       ads_msgfree(ads, res);
+
+       if (!ADS_ERR_OK(rc)) {
+               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 ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
+               rc = ADS_SUCCESS;
+               goto done;
+       }
+       if ( !ADS_ERR_OK(rc) ) {
+               goto done;
+       }
+
+done:
+       if ( ads_s != ads )
+               ads_destroy( &ads_s );
+       SAFE_FREE( dn );
+
+       return rc;
+}
+
 /*******************************************************************
   join a domain using ADS (LDAP mods)
  ********************************************************************/
@@ -1183,11 +1239,9 @@ int net_ads_join(int argc, const char **argv)
                return -1;
        }
 
-       if (!(ads = ads_init(lp_realm(), NULL, NULL ))) {
+       if ( (ads = ads_startup()) == NULL ) {
                return -1;
        }
-       ads->auth.flags = ADS_AUTH_NO_BIND;
-       status = ads_connect(ads);
 
        if (strcmp(ads->config.realm, lp_realm()) != 0) {
                d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
@@ -1197,12 +1251,24 @@ int net_ads_join(int argc, const char **argv)
                return -1;
        }
 
-
-       if (!(ctx = talloc_init("net_join_domain"))) {
+       if (!(ctx = talloc_init("net_ads_join"))) {
                DEBUG(0, ("Could not initialise talloc context\n"));
                return -1;
        }
 
+       /* 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 ( !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;
+               }
+       }
+
        /* Do the domain join here */
 
        tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);