📄 ldap.c
字号:
if (!val) return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL); return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES, name, (const void **) values);}/** * Perform an ldap modify * @param ads connection to ads server * @param mod_dn DistinguishedName to modify * @param mods list of modifications to perform * @return status of modify **/ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods){ int ret,i; char *utf8_dn = NULL; /* this control is needed to modify that contains a currently non-existent attribute (but allowable for the object) to run */ LDAPControl PermitModify = { CONST_DISCARD(char *, ADS_PERMIT_MODIFY_OID), {0, NULL}, (char) 1}; LDAPControl *controls[2]; controls[0] = &PermitModify; controls[1] = NULL; if (push_utf8_allocate(&utf8_dn, mod_dn) == -1) { return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } /* find the end of the list, marked by NULL or -1 */ for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++); /* make sure the end of the list is NULL */ mods[i] = NULL; ret = ldap_modify_ext_s(ads->ld, utf8_dn, (LDAPMod **) mods, controls, NULL); SAFE_FREE(utf8_dn); return ADS_ERROR(ret);}/** * Perform an ldap add * @param ads connection to ads server * @param new_dn DistinguishedName to add * @param mods list of attributes and values for DN * @return status of add **/ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods){ int ret, i; char *utf8_dn = NULL; if (push_utf8_allocate(&utf8_dn, new_dn) == -1) { DEBUG(1, ("ads_gen_add: push_utf8_allocate failed!")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } /* find the end of the list, marked by NULL or -1 */ for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++); /* make sure the end of the list is NULL */ mods[i] = NULL; ret = ldap_add_s(ads->ld, utf8_dn, (LDAPMod**)mods); SAFE_FREE(utf8_dn); return ADS_ERROR(ret);}/** * Delete a DistinguishedName * @param ads connection to ads server * @param new_dn DistinguishedName to delete * @return status of delete **/ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn){ int ret; char *utf8_dn = NULL; if (push_utf8_allocate(&utf8_dn, del_dn) == -1) { DEBUG(1, ("ads_del_dn: push_utf8_allocate failed!")); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } ret = ldap_delete_s(ads->ld, utf8_dn); return ADS_ERROR(ret);}/** * Build an org unit string * if org unit is Computers or blank then assume a container, otherwise * assume a \ separated list of organisational units * @param ads connection to ads server * @param org_unit Organizational unit * @return org unit string - caller must free **/char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit){ char *ret = NULL; if (!org_unit || !*org_unit) { ret = ads_default_ou_string(ads, WELL_KNOWN_GUID_COMPUTERS); /* samba4 might not yet respond to a wellknownobject-query */ return ret ? ret : SMB_STRDUP("cn=Computers"); } if (strequal(org_unit, "Computers")) { return SMB_STRDUP("cn=Computers"); } return ads_build_path(org_unit, "\\/", "ou=", 1);}/** * Get a org unit string for a well-known GUID * @param ads connection to ads server * @param wknguid Well known GUID * @return org unit string - caller must free **/char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid){ ADS_STATUS status; void *res; char *base, *wkn_dn, *ret, **wkn_dn_exp, **bind_dn_exp; const char *attrs[] = {"distinguishedName", NULL}; int new_ln, wkn_ln, bind_ln, i; if (wknguid == NULL) { return NULL; } if (asprintf(&base, "<WKGUID=%s,%s>", wknguid, ads->config.bind_path ) == -1) { DEBUG(1, ("asprintf failed!\n")); return NULL; } status = ads_search_dn(ads, &res, base, attrs); if (!ADS_ERR_OK(status)) { DEBUG(1,("Failed while searching for: %s\n", base)); return NULL; } free(base); if (ads_count_replies(ads, res) != 1) { return NULL; } /* substitute the bind-path from the well-known-guid-search result */ wkn_dn = ads_get_dn(ads, res); wkn_dn_exp = ldap_explode_dn(wkn_dn, 0); bind_dn_exp = ldap_explode_dn(ads->config.bind_path, 0); for (wkn_ln=0; wkn_dn_exp[wkn_ln]; wkn_ln++) ; for (bind_ln=0; bind_dn_exp[bind_ln]; bind_ln++) ; new_ln = wkn_ln - bind_ln; ret = wkn_dn_exp[0]; for (i=1; i < new_ln; i++) { char *s; asprintf(&s, "%s,%s", ret, wkn_dn_exp[i]); ret = SMB_STRDUP(s); free(s); } return ret;}/** * Adds (appends) an item to an attribute array, rather then * replacing the whole list * @param ctx An initialized TALLOC_CTX * @param mods An initialized ADS_MODLIST * @param name name of the ldap attribute to append to * @param vals an array of values to add * @return status of addition **/ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, const char *name, const char **vals){ return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, (const void **) vals);}/** * Determines the computer account's current KVNO via an LDAP lookup * @param ads An initialized ADS_STRUCT * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account. * @return the kvno for the computer account, or -1 in case of a failure. **/uint32 ads_get_kvno(ADS_STRUCT *ads, const char *machine_name){ LDAPMessage *res = NULL; uint32 kvno = (uint32)-1; /* -1 indicates a failure */ char *filter; const char *attrs[] = {"msDS-KeyVersionNumber", NULL}; char *dn_string = NULL; ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS); DEBUG(5,("ads_get_kvno: Searching for host %s\n", machine_name)); if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) { return kvno; } ret = ads_search(ads, (void**)(void *)&res, filter, attrs); SAFE_FREE(filter); if (!ADS_ERR_OK(ret) && ads_count_replies(ads, res)) { DEBUG(1,("ads_get_kvno: Computer Account For %s not found.\n", machine_name)); ads_msgfree(ads, res); return kvno; } dn_string = ads_get_dn(ads, res); if (!dn_string) { DEBUG(0,("ads_get_kvno: out of memory.\n")); ads_msgfree(ads, res); return kvno; } DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string)); ads_memfree(ads, dn_string); /* --------------------------------------------------------- * 0 is returned as a default KVNO from this point on... * This is done because Windows 2000 does not support key * version numbers. Chances are that a failure in the next * step is simply due to Windows 2000 being used for a * domain controller. */ kvno = 0; if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) { DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n")); DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n")); ads_msgfree(ads, res); return kvno; } /* Success */ DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno)); ads_msgfree(ads, res); return kvno;}/** * This clears out all registered spn's for a given hostname * @param ads An initilaized ADS_STRUCT * @param machine_name the NetBIOS name of the computer. * @return 0 upon success, non-zero otherwise. **/ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name){ TALLOC_CTX *ctx; LDAPMessage *res = NULL; ADS_MODLIST mods; const char *servicePrincipalName[1] = {NULL}; ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS); char *dn_string = NULL; ret = ads_find_machine_acct(ads, (void **)(void *)&res, machine_name); if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name)); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name)); ctx = talloc_init("ads_clear_service_principal_names"); if (!ctx) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } if (!(mods = ads_init_mods(ctx))) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n")); ads_msgfree(ads, res); talloc_destroy(ctx); return ret; } dn_string = ads_get_dn(ads, res); if (!dn_string) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } ret = ads_gen_mod(ads, dn_string, mods); ads_memfree(ads,dn_string); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n", machine_name)); ads_msgfree(ads, res); talloc_destroy(ctx); return ret; } ads_msgfree(ads, res); talloc_destroy(ctx); return ret;}/** * This adds a service principal name to an existing computer account * (found by hostname) in AD. * @param ads An initialized ADS_STRUCT * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account. * @param spn A string of the service principal to add, i.e. 'host' * @return 0 upon sucess, or non-zero if a failure occurs **/ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name, const char *spn){ ADS_STATUS ret; TALLOC_CTX *ctx; LDAPMessage *res = NULL; char *host_spn, *psp1, *psp2, *psp3; ADS_MODLIST mods; fstring my_fqdn; char *dn_string = NULL; const char *servicePrincipalName[4] = {NULL, NULL, NULL, NULL}; ret = ads_find_machine_acct(ads, (void **)(void *)&res, machine_name); if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n", spn, machine_name, ads->config.realm)); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name)); if (!(ctx = talloc_init("ads_add_service_principal_name"))) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } name_to_fqdn(my_fqdn, machine_name); strlower_m(my_fqdn); if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", my_fqdn))) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } /* Add the extra principal */ psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name); strupper_m(psp1); strlower_m(&psp1[strlen(spn)]); DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp1, machine_name)); servicePrincipalName[0] = psp1; psp2 = talloc_asprintf(ctx, "%s/%s.%s", spn, machine_name, ads->config.realm); strupper_m(psp2); strlower_m(&psp2[strlen(spn)]); DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp2, machine_name)); servicePrincipalName[1] = psp2; /* Add another principal in case the realm != the DNS domain, so that * the KDC doesn't send "server principal unknown" errors to clients * which use the DNS name in determining service principal names. */ psp3 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn); strupper_m(psp3); strlower_m(&psp3[strlen(spn)]); if (strcmp(psp2, psp3) != 0) { DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp3, machine_name)); servicePrincipalName[2] = psp3; } if (!(mods = ads_init_mods(ctx))) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); talloc_destroy(ctx); ads_msgfree(ads, res); return ret; } dn_string = ads_get_dn(ads, res); if (!dn_string) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } ret = ads_gen_mod(ads, dn_string, mods); ads_memfree(ads,dn_string); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); talloc_destroy(ctx); ads_msgfree(ads, res); return ret; } talloc_destroy(ctx); ads_msgfree(ads, res); return ret;}/** * adds a machine account to the ADS server * @param ads An intialized ADS_STRUCT * @param machine_name - the NetBIOS machine name of this account. * @param account_type A number indicating the type of account to create * @param org_unit The LDAP path in which to place this account * @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 ret, status; char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr; TALLOC_CTX *ctx; ADS_MODLIST mods; 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; if (!(ctx = talloc_init("ads_add_machine_acct"))) return ADS_ERROR(LDAP_NO_MEMORY); ret = ADS_ERROR(LDAP_NO_MEMORY); 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)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -