diff -Nurp samba.orig/source/libads/ldap.c samba.ads/source/libads/ldap.c --- samba.orig/source/libads/ldap.c Thu Jul 8 13:06:16 2004 +++ samba.ads/source/libads/ldap.c Tue Aug 31 11:54:08 2004 @@ -1237,6 +1237,46 @@ ADS_STATUS ads_add_service_principal_nam return ret; } +static const char **build_spn_names(TALLOC_CTX *ctx, ADS_STRUCT *ads, + const char *machine_name, const char **aliases) +{ + char **spn = NULL; + int i, spn_idx, num_aliases; + + for (num_aliases = 0; aliases && aliases[num_aliases]; ++num_aliases) + ; + /* + * We need to allocate four spn entries for base machine, plus two + * entries -- HOST and CIFS -- per alias, plus list terminating null + */ + spn = talloc(ctx, (4 + (num_aliases * 2) + 1) * sizeof(char *)); + if (!spn) + return NULL; + + spn_idx = 0; + spn[spn_idx++] = talloc_asprintf(ctx, "HOST/%s", machine_name); + spn[spn_idx++] = talloc_asprintf(ctx, "HOST/%s.%s", + machine_name, + ads->config.realm); + strlower_m(&spn[spn_idx-1][5]); + spn[spn_idx++] = talloc_asprintf(ctx, "CIFS/%s", machine_name); + spn[spn_idx++] = talloc_asprintf(ctx, "CIFS/%s.%s", + machine_name, + ads->config.realm); + strlower_m(&spn[spn_idx-1][5]); + + for (i = 0; aliases && (aliases[i] != NULL); ++i) { + DEBUG(9, ("Adding service principal %s (alias) for %s\n", aliases[i], machine_name)); + spn[spn_idx] = talloc_asprintf(ctx, "HOST/%s", aliases[i]); + strlower_m(&spn[spn_idx][5]); + spn[spn_idx+1] = talloc_asprintf(ctx, "CIFS/%s", aliases[i]); + strlower_m(&spn[spn_idx+1][5]); + spn_idx += 2; + } + spn[spn_idx] = NULL; + return (const char **)spn; +} + /** * adds a machine account to the ADS server * @param ads An intialized ADS_STRUCT @@ -1248,7 +1288,8 @@ ADS_STATUS ads_add_service_principal_nam static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name, uint32 account_type, - const char *org_unit) + const char *org_unit, + const char **aliases) { ADS_STATUS ret, status; char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr; @@ -1256,8 +1297,7 @@ static ADS_STATUS ads_add_machine_acct(A ADS_MODLIST mods; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", "computer", NULL}; - const char *servicePrincipalName[5] = {NULL, NULL, NULL, NULL, NULL}; - char *psp, *psp2; + const char **servicePrincipalName; unsigned acct_control; unsigned exists=0; fstring my_fqdn; @@ -1297,23 +1337,14 @@ static ADS_STATUS ads_add_machine_acct(A if (!new_dn) { goto done; } - + servicePrincipalName = build_spn_names(ctx, ads, machine_name, aliases); + if (!servicePrincipalName) + 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; if (!(samAccountName = talloc_asprintf(ctx, "%s$", machine_name))) { goto done; @@ -1581,15 +1612,88 @@ int ads_count_replies(ADS_STRUCT *ads, v } /** + * Update service principal information for machine account + * Add any netbios aliases to the servicePrincipalName attribute of + * the machine account so that client can request tickets using + * all names. + * @param ads connection to ads server + * @param machine name of host to add + * @param aliases netbios alias list (if any) + * @return status of update to account + */ +ADS_STATUS ads_update_join(ADS_STRUCT *ads, const char *machine_name, + const char **aliases) +{ + ADS_STATUS ret; + LDAPMessage *res = NULL; + TALLOC_CTX *ctx; + + if (!(ctx = talloc_init("ads_update_join"))) + return ADS_ERROR(LDAP_NO_MEMORY); + + ret = ADS_ERROR(LDAP_NO_MEMORY); + + do { + ADS_STATUS status; + char *machine_dn, *machine; + fstring my_fqdn; + ADS_MODLIST mods; + const char **spn; + + /* machine name must be lowercase */ + if ((machine = talloc_strdup(ctx,machine_name)) == NULL) { + DEBUG(0, ("ads_update_join: memory allocation failure\n")); + break; + } + strlower_m(machine); + + name_to_fqdn(my_fqdn, machine); + + /* require an existing machine account; hence ads_"update"_join */ + status = ads_find_machine_acct(ads, (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_update_join: ads_get_dn returned NULL (malloc failure?)\n")); + break; + } + machine_dn = talloc_strdup(ctx, dn_string); + ads_memfree(ads,dn_string); + } + else { + DEBUG(1, ("ads_update_join: failed to find %s acct\n", machine)); + ret = ADS_ERR_OK(status) ? ADS_ERROR(LDAP_OTHER) : status; + break; + } + /* + * We could be smart here and see if we need any changes to the service + * principal names -- but for now we'll simply add them all every time + */ + if (!(spn = build_spn_names(ctx, ads, machine, aliases))) + break; + + if (!(mods = ads_init_mods(ctx))) + break; + + ads_mod_strlist(ctx, &mods, "servicePrincipalName", spn); + ret = ads_gen_mod(ads, machine_dn, mods); + } while (False); + + ads_msgfree(ads, res); + return ret; +} + +/** * 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 + * @param aliases netbios alias list (if any) * @return status of join **/ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, - uint32 account_type, const char *org_unit) + uint32 account_type, const char *org_unit, const char **aliases) { ADS_STATUS status; LDAPMessage *res = NULL; @@ -1612,7 +1716,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ad } */ - status = ads_add_machine_acct(ads, machine, account_type, org_unit); + status = ads_add_machine_acct(ads, machine, account_type, org_unit, aliases); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_add_machine_acct (%s): %s\n", machine, ads_errstr(status))); SAFE_FREE(machine); diff -Nurp samba.orig/source/utils/net_ads.c samba.ads/source/utils/net_ads.c --- samba.orig/source/utils/net_ads.c Thu Jul 8 13:06:16 2004 +++ samba.ads/source/utils/net_ads.c Tue Aug 31 11:53:57 2004 @@ -34,6 +34,8 @@ int net_ads_usage(int argc, const char * "\n\tremoves the local machine from a ADS realm\n"\ "\nnet ads testjoin"\ "\n\ttests that an exiting join is OK\n"\ +"\nnet ads updatejoin"\ +"\n\tupdate service principal names with netbios aliases\n"\ "\nnet ads user"\ "\n\tlist, add, or delete users in the realm\n"\ "\nnet ads group"\ @@ -678,6 +680,39 @@ int net_ads_testjoin(int argc, const cha } /* + * update existing join servicePrincipalName(s) to netbios alias(es) + */ +int net_ads_updatejoin(int argc, const char **argv) +{ + ADS_STRUCT *ads = NULL; + int ret = -1; + + /* require that we have a valid join to begin with */ + do { + ADS_STATUS rc; + + use_in_memory_ccache(); + + if (!secrets_init()) { + DEBUG(1,("Failed to initialise secrets database\n")); + break; + } + net_use_machine_password(); + + if ((ads = ads_startup()) == NULL) { + fprintf(stderr, "'updatejoin' requires a valid join to domain\n"); + break; + } + rc = ads_update_join(ads, global_myname(), lp_netbios_aliases()); + if (ADS_ERR_OK(rc)) + ret = 0; + } while (False); + + if (ads != NULL) ads_destroy(&ads); + return ret; +} + +/* join a domain using ADS */ int net_ads_join(int argc, const char **argv) @@ -746,7 +781,7 @@ int net_ads_join(int argc, const char ** return -1; } - rc = ads_join_realm(ads, global_myname(), account_type, org_unit); + rc = ads_join_realm(ads, global_myname(), account_type, org_unit, lp_netbios_aliases()); if (!ADS_ERR_OK(rc)) { d_printf("ads_join_realm: %s\n", ads_errstr(rc)); ads_destroy(&ads); @@ -1435,6 +1470,7 @@ int net_ads(int argc, const char **argv) {"INFO", net_ads_info}, {"JOIN", net_ads_join}, {"TESTJOIN", net_ads_testjoin}, + {"UPDATEJOIN", net_ads_updatejoin}, {"LEAVE", net_ads_leave}, {"STATUS", net_ads_status}, {"USER", net_ads_user},