From 24b67730bf7bbf4414df99129a3cc20aa93dc0da Mon Sep 17 00:00:00 2001 From: Jim McDonough Date: Mon, 24 Jun 2002 17:50:02 +0000 Subject: Support utf8 on the wire for ads ldap. DN's are converted, as well as strings, though it is up to the calling function to decide whether values are strings or not. Attributes are not converted at this point, though support for it would be simple. I have tested it with users and groups using non-ascii chars, and if the check for alphanumeric user/domain names is removed form sesssetup.c, even a user with accented chars can connect, or even login (via winbind). I have also simplified the interfaces to ads_mod_*, though we will probably want to expand this by a few functions in the near future. We just had too many ways to do the same thing... (This used to be commit f924cb53580bc081ff34e45abba57629018c68d6) --- source3/libads/ldap.c | 532 +++++++++++++++++++----------------------- source3/libads/ldap_printer.c | 73 +++--- source3/libads/ldap_user.c | 29 +-- source3/utils/net_ads.c | 30 ++- 4 files changed, 315 insertions(+), 349 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index ab2828c23d..b898eec7a9 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -30,6 +30,11 @@ * * The routines contained here should do the necessary ldap calls for * ads setups. + * + * Important note: attribute names passed into ads_ routines must + * already be in UTF-8 format. We do not convert them because in almost + * all cases, they are just ascii (which is represented with the same + * codepoints in UTF-8). This may have to change at some point **/ /** @@ -112,8 +117,8 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads) * @param ads connection to ads server * @param bind_path Base dn for the search * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE) - * @param exp Search expression - * @param attrs Attributes to retrieve + * @param exp Search expression - specified in local charset + * @param attrs Attributes to retrieve - specified in utf8 or ascii * @param res ** which will contain results - free res* with ads_msgfree() * @param count Number of entries retrieved on this page * @param cookie The paged results cookie to be returned on subsequent calls @@ -124,23 +129,16 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path, const char **attrs, void **res, int *count, void **cookie) { - int rc; - int version; - LDAPControl PagedResults; - LDAPControl NoReferrals; + int rc, i, version; + char *utf8_exp, *utf8_path; + LDAPControl PagedResults, NoReferrals, *controls[3], **rcontrols; BerElement *cookie_be = NULL; struct berval *cookie_bv= NULL; - LDAPControl *controls[3]; - LDAPControl **rcontrols; - int i; *res = NULL; + /* Paged results only available on ldap v3 or later */ ldap_get_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version); - - /* Paged results only available on ldap v3 or later, so check - version first before using, since at connect time we're - only v2. Not sure exactly why... */ if (version < LDAP_VERSION3) return ADS_ERROR(LDAP_NOT_SUPPORTED); @@ -171,20 +169,29 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path, *res = NULL; /* we need to disable referrals as the openldap libs don't - seem to handle them correctly. They result in the result - record containing the server control being removed from the - result list (tridge) + handle them and paged results at the same time. Using them + together results in the result record containing the server + page control being removed from the result list (tridge/jmcd) leaving this in despite the control that says don't generate referrals, in case the server doesn't support it (jmcd) */ ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); - rc = ldap_search_ext_s(ads->ld, bind_path, scope, exp, + if (!push_utf8_allocate((void **) &utf8_exp, exp)) + utf8_exp = exp; + if (!push_utf8_allocate((void **) &utf8_path, bind_path)) + utf8_path = bind_path; + + rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_exp, (char **) attrs, 0, controls, NULL, NULL, LDAP_NO_LIMIT, (LDAPMessage **)res); + if (utf8_exp != exp) + SAFE_FREE(utf8_exp); + if (utf8_path != bind_path) + SAFE_FREE(utf8_path); ber_free(cookie_be, 1); ber_bvfree(cookie_bv); @@ -262,7 +269,6 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path, next = ads_next_entry(ads, msg); ldap_add_result_entry((LDAPMessage **)res, msg); } - /* note that we do not free res2, as the memory is now part of the main returned list */ } @@ -276,15 +282,15 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path, * @param ads connection to ads server * @param bind_path Base dn for the search * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE) - * @param exp Search expression - * @param attrs Attributes to retrieve + * @param exp Search expression - specified in local charset + * @param attrs Attributes to retrieve - specified in UTF-8 or ascii * @param fn Function which takes attr name, values list, and data_area * @param data_area Pointer which is passed to function on each call * @return status of search **/ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path, int scope, const char *exp, const char **attrs, - void(*fn)(char *, void **, void *), + BOOL(*fn)(char *, void **, void *), void *data_area) { void *cookie = NULL; @@ -329,16 +335,25 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope, { struct timeval timeout; int rc; + char *utf8_exp, *utf8_path; timeout.tv_sec = ADS_SEARCH_TIMEOUT; timeout.tv_usec = 0; *res = NULL; - rc = ldap_search_ext_s(ads->ld, - bind_path, scope, - exp, (char **) attrs, 0, NULL, NULL, + if (!push_utf8_allocate((void **) &utf8_exp, exp)) + utf8_exp = exp; + if (!push_utf8_allocate((void **) &utf8_path, bind_path)) + utf8_path = bind_path; + + rc = ldap_search_ext_s(ads->ld, utf8_path, scope, + utf8_exp, (char **) attrs, 0, NULL, NULL, &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res); + if (utf8_exp != exp) + SAFE_FREE(utf8_exp); + if (utf8_path != bind_path) + SAFE_FREE(utf8_path); if (rc == LDAP_SIZELIMIT_EXCEEDED) { DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n")); rc = 0; @@ -395,8 +410,7 @@ void ads_msgfree(ADS_STRUCT *ads, void *msg) **/ void ads_memfree(ADS_STRUCT *ads, void *mem) { - if (!mem) return; - ldap_memfree(mem); + SAFE_FREE(mem); } /** @@ -407,7 +421,12 @@ void ads_memfree(ADS_STRUCT *ads, void *mem) **/ char *ads_get_dn(ADS_STRUCT *ads, void *res) { - return ldap_get_dn(ads->ld, res); + char *utf8_dn, *unix_dn; + + utf8_dn = ldap_get_dn(ads->ld, res); + pull_utf8_allocate(&unix_dn, utf8_dn); + ldap_memfree(utf8_dn); + return unix_dn; } /** @@ -431,25 +450,6 @@ ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host) return status; } -/* - duplicate an already-assembled list of values so that it can be - freed as part of the standard msgfree call -*/ -static char **ads_dup_values(TALLOC_CTX *ctx, char **values) -{ - char **newvals; - int i; -#define ADS_MAX_NUM_VALUES 32 - - for (i=0; values[i] && ibv_len == 0) return value; + + value->bv_len = in_val->bv_len; + value->bv_val = talloc_memdup(ctx, in_val->bv_val, in_val->bv_len); + return value; +} + +/* + Make a values list out of an array of (struct berval *) + */ +static struct berval **ads_dup_values(TALLOC_CTX *ctx, struct berval **in_vals) +{ + void **values; + int i; + + if (!in_vals) return NULL; + for (i=0; in_vals[i]; i++); /* count values */ + values = talloc_zero(ctx, (i+1)*sizeof(struct berval *)); + if (!values) return NULL; + + for (i=0; in_vals[i]; i++) { + values[i] = dup_berval(ctx, in_vals[i]); + } + return values; +} + +/* + UTF8-encode a values list out of an array of (char *) + */ +static char **ads_push_strvals(TALLOC_CTX *ctx, char **in_vals) +{ + void **values; + int i; + + if (!in_vals) return NULL; + for (i=0; in_vals[i]; i++); /* count values */ + values = talloc_zero(ctx, (i+1)*sizeof(char *)); + if (!values) return NULL; + + for (i=0; in_vals[i]; i++) { + push_utf8_talloc(ctx, &values[i], in_vals[i]); + } + return values; +} + +/* + Pull a (char *) array out of a UTF8-encoded values list + */ +static char **ads_pull_strvals(TALLOC_CTX *ctx, char **in_vals) +{ + void **values; + int i; + + if (!in_vals) return NULL; + for (i=0; in_vals[i]; i++); /* count values */ + values = talloc_zero(ctx, (i+1)*sizeof(char *)); + if (!values) return NULL; + + for (i=0; in_vals[i]; i++) { + pull_utf8_talloc(ctx, &values[i], in_vals[i]); + } + return values; +} + /* add an attribute to the list, with values list already constructed */ static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, - int mod_op, const char *name, char **values) + int mod_op, const char *name, void **invals) { int curmod; LDAPMod **modlist = (LDAPMod **) *mods; + void **values; + + if (!invals) { + values = NULL; + mod_op = LDAP_MOD_DELETE; + } else { + if (mod_op & LDAP_MOD_BVALUES) + values = ads_dup_values(ctx, invals); + else + values = ads_push_strvals(ctx, invals); + } /* find the first empty slot */ for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1; @@ -497,213 +582,62 @@ static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, if (mod_op & LDAP_MOD_BVALUES) modlist[curmod]->mod_bvalues = (struct berval **) values; else - modlist[curmod]->mod_values = values; + modlist[curmod]->mod_values = (char **) values; modlist[curmod]->mod_op = mod_op; return ADS_ERROR(LDAP_SUCCESS); } /** - * Add an already-constructed list of values to a mod list for an ADD + * Add a single string value to a mod list * @param ctx An initialized TALLOC_CTX * @param mods An initialized ADS_MODLIST * @param name The attribute name to add - * @param values Constructed values list to add + * @param val The value to add - NULL means DELETE * @return ADS STATUS indicating success of add **/ -ADS_STATUS ads_mod_add_list(TALLOC_CTX *ctx, ADS_MODLIST *mods, - char *name, char **values) -{ - char **newvals = ads_dup_values(ctx, values); - if (newvals) - return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, newvals); - else - return ADS_ERROR(LDAP_NO_MEMORY); -} - -/** - * Add an already-constructed list of values to a mod list for a REPLACE - * @param ctx An initialized TALLOC_CTX - * @param mods An initialized ADS_MODLIST - * @param name The attribute name to add - * @param values Constructed values list to add - * @return ADS STATUS indicating success of add - **/ -ADS_STATUS ads_mod_repl_list(TALLOC_CTX *ctx, ADS_MODLIST *mods, - char *name, char **values) +ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods, + const char *name, const char *val) { - char **newvals; - if (values && *values) { - if (!(newvals = ads_dup_values(ctx, values))) - return ADS_ERROR(LDAP_NO_MEMORY); - else - return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, - name, newvals); - } - else + char *values[2] = {val, NULL}; + if (!val) return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL); + return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name, + (void **) values); } /** - * Add any number of string values to a mod list - for ADD or REPLACE - * @param ctx An initialized TALLOC_CTX - * @param mods An initialized ADS_MODLIST - * @param mod_op Operation to perform (LDAP_MOD_ADD | LDAP_MOD_REPLACE) - * @param name The attribute name to add - * @param ... Any number of values, in (char *) form - * @return ADS STATUS indicating success of add - **/ -ADS_STATUS ads_mod_add_var(TALLOC_CTX *ctx, ADS_MODLIST *mods, - int mod_op, const char *name, ...) -{ - va_list ap; - int num_vals, i, do_op; - char *value, **values; - - /* count the number of values */ - va_start(ap, name); - for (num_vals=0; va_arg(ap, char *); num_vals++); - va_end(ap); - - if (num_vals) { - if (!(values = talloc_zero(ctx, sizeof(char *)*(num_vals+1)))) - return ADS_ERROR(LDAP_NO_MEMORY); - va_start(ap, name); - for (i=0; (value = (char *) va_arg(ap, char *)) && - i < num_vals; i++) - values[i] = value; - va_end(ap); - values[i] = NULL; - do_op = mod_op; - } else { - do_op = LDAP_MOD_DELETE; - values = NULL; - } - return ads_modlist_add(ctx, mods, do_op, name, values); -} - -/** - * Add any number of ber values to a mod list - for ADD or REPLACE + * Add an array of string values to a mod list * @param ctx An initialized TALLOC_CTX * @param mods An initialized ADS_MODLIST - * @param mod_op Operation to perform (LDAP_MOD_ADD | LDAP_MOD_REPLACE) * @param name The attribute name to add - * @param ... Any number of values, in (struct berval *) form - * @return ADS STATUS indicating success of add - **/ -ADS_STATUS ads_mod_add_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, - int mod_op, const char *name, ...) -{ - va_list ap; - int num_vals, i, do_op; - char *value, **values; - - /* count the number of values */ - va_start(ap, name); - for (num_vals=0; va_arg(ap, struct berval *); num_vals++); - va_end(ap); - - if (num_vals) { - if (!(values = talloc_zero(ctx, sizeof(struct berval) * - (num_vals + 1)))) - return ADS_ERROR(LDAP_NO_MEMORY); - va_start(ap, name); - for (i=0; (value = (char *) va_arg(ap, char *)) && - i < num_vals; i++) - values[i] = value; - va_end(ap); - values[i] = NULL; - do_op = mod_op; - } else { - do_op = LDAP_MOD_DELETE; - values = NULL; - } - do_op |= LDAP_MOD_BVALUES; - return ads_modlist_add(ctx, mods, do_op, name, values); -} - -/** - * Add a single string value to a mod list - for REPLACE - * @param ctx An initialized TALLOC_CTX - * @param mods An initialized ADS_MODLIST - * @param name The attribute name to replace - * @param val The value to add + * @param vals The array of string values to add - NULL means DELETE * @return ADS STATUS indicating success of add **/ -ADS_STATUS ads_mod_repl(TALLOC_CTX *ctx, ADS_MODLIST *mods, - char *name, char *val) +ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, + const char *name, const char **vals) { - if (val) - return ads_mod_add_var(ctx, mods, LDAP_MOD_REPLACE, - name, val, NULL); - else - return ads_mod_add_var(ctx, mods, LDAP_MOD_DELETE, name, NULL); -} - -/** - * Add a single string value to a mod list - for ADD - * @param ctx An initialized TALLOC_CTX - * @param mods An initialized ADS_MODLIST - * @param name The attribute name to add - * @param val The value to add - * @return ADS STATUS indicating success of add - **/ -ADS_STATUS ads_mod_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, - const char *name, const char *val) -{ - return ads_mod_add_var(ctx, mods, LDAP_MOD_ADD, name, val, NULL); + if (!vals) + return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL); + return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name, + (void **) vals); } /** - * Add a single berval value to a mod list - for ADD + * Add a single ber-encoded value to a mod list * @param ctx An initialized TALLOC_CTX * @param mods An initialized ADS_MODLIST * @param name The attribute name to add - * @param size The size of of the value - * @param val The value to add - * @return ADS STATUS indicating success of add - **/ -ADS_STATUS ads_mod_add_len(TALLOC_CTX *ctx, ADS_MODLIST *mods, - char *name, size_t size, char *val) -{ - struct berval *bval = NULL; - - if (!(bval = talloc_zero(ctx, sizeof(struct berval *)))) - return ADS_ERROR(LDAP_NO_MEMORY); - if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *)))) - return ADS_ERROR(LDAP_NO_MEMORY); - - bval->bv_val = val; - bval->bv_len = size; - return ads_mod_add_ber(ctx, mods, LDAP_MOD_ADD, name, bval, NULL); -} - -/** - * Add a single berval value to a mod list - for REPLACE - * @param ctx An initialized TALLOC_CTX - * @param mods An initialized ADS_MODLIST - * @param name The attribute name to replace - * @param size The size of of the value - * @param val The value to add + * @param val The value to add - NULL means DELETE * @return ADS STATUS indicating success of add **/ -ADS_STATUS ads_mod_repl_len(TALLOC_CTX *ctx, ADS_MODLIST *mods, - const char *name, size_t size, char *val) +ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, + const char *name, const struct berval *val) { - struct berval *bval = NULL; - - if (!(bval = talloc_zero(ctx, sizeof(struct berval *)))) - return ADS_ERROR(LDAP_NO_MEMORY); - + struct berval *values[2] = {val, NULL}; if (!val) - return ads_mod_add_ber(ctx, mods, LDAP_MOD_DELETE, name, NULL); - else { - if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *)))) - return ADS_ERROR(LDAP_NO_MEMORY); - bval->bv_val = val; - bval->bv_len = size; - return ads_mod_add_ber(ctx, mods, LDAP_MOD_REPLACE, name, - bval, NULL); - } + return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL); + return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES, + name, (void **) values); } /** @@ -716,6 +650,7 @@ ADS_STATUS ads_mod_repl_len(TALLOC_CTX *ctx, ADS_MODLIST *mods, 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 @@ -729,12 +664,15 @@ ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods) controls[0] = &PermitModify; controls[1] = NULL; + push_utf8_allocate(&utf8_dn, mod_dn); + /* 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, mod_dn, (LDAPMod **) mods, - controls, NULL); + ret = ldap_modify_ext_s(ads->ld, utf8_dn ? utf8_dn : mod_dn, + (LDAPMod **) mods, controls, NULL); + SAFE_FREE(utf8_dn); return ADS_ERROR(ret); } @@ -747,14 +685,19 @@ ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods) **/ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods) { - int i; + int ret, i; + char *utf8_dn = NULL; + push_utf8_allocate(&utf8_dn, new_dn); + /* 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; - return ADS_ERROR(ldap_add_s(ads->ld, new_dn, mods)); + ret = ldap_add_s(ads->ld, utf8_dn ? utf8_dn : new_dn, mods); + SAFE_FREE(utf8_dn); + return ADS_ERROR(ret); } /** @@ -765,7 +708,11 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods) **/ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn) { - return ADS_ERROR(ldap_delete(ads->ld, del_dn)); + int ret; + char *utf8_dn = NULL; + push_utf8_allocate(&utf8_dn, del_dn); + ret = ldap_delete(ads->ld, utf8_dn ? utf8_dn : del_dn); + return ADS_ERROR(ret); } /** @@ -797,6 +744,8 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, char *ou_str; TALLOC_CTX *ctx; ADS_MODLIST mods; + const char *objectClass[] = {"top", "person", "organizationalPerson", + "user", "computer", NULL}; if (!(ctx = talloc_init_named("machine_account"))) return ADS_ERROR(LDAP_NO_MEMORY); @@ -824,17 +773,15 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, if (!(mods = ads_init_mods(ctx))) goto done; - ads_mod_add(ctx, &mods, "cn", hostname); - ads_mod_add(ctx, &mods, "sAMAccountName", samAccountName); - ads_mod_add_var(ctx, &mods, LDAP_MOD_ADD, "objectClass", - "top", "person", "organizationalPerson", - "user", "computer", NULL); - ads_mod_add(ctx, &mods, "userPrincipalName", host_upn); - ads_mod_add(ctx, &mods, "servicePrincipalName", host_spn); - ads_mod_add(ctx, &mods, "dNSHostName", hostname); - ads_mod_add(ctx, &mods, "userAccountControl", controlstr); - ads_mod_add(ctx, &mods, "operatingSystem", "Samba"); - ads_mod_add(ctx, &mods, "operatingSystemVersion", VERSION); + ads_mod_str(ctx, &mods, "cn", hostname); + ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName); + ads_mod_strlist(ctx, &mods, "objectClass", objectClass); + ads_mod_str(ctx, &mods, "userPrincipalName", host_upn); + ads_mod_str(ctx, &mods, "servicePrincipalName", host_spn); + ads_mod_str(ctx, &mods, "dNSHostName", hostname); + ads_mod_str(ctx, &mods, "userAccountControl", controlstr); + ads_mod_str(ctx, &mods, "operatingSystem", "Samba"); + ads_mod_str(ctx, &mods, "operatingSystemVersion", VERSION); ads_gen_add(ads, new_dn, mods); ret = ads_set_machine_sd(ads, hostname, new_dn); @@ -918,33 +865,39 @@ static void dump_string(const char *field, struct berval **values) used for debugging */ -static void ads_dump_field(char *field, void **values, void *data_area) +static BOOL ads_dump_field(char *field, void **values, void *data_area) { struct { char *name; + BOOL string; void (*handler)(const char *, struct berval **); } handlers[] = { - {"objectGUID", dump_binary}, - {"nTSecurityDescriptor", dump_sd}, - {"objectSid", dump_sid}, - {NULL, NULL} + {"objectGUID", False, dump_binary}, + {"nTSecurityDescriptor", False, dump_sd}, + {"objectSid", False, dump_sid}, + {NULL, True, NULL} }; int i; if (!field) { /* must be end of an entry */ printf("\n"); - return; + return False; } for (i=0; handlers[i].name; i++) { if (StrCaseCmp(handlers[i].name, field) == 0) { + if (!values) /* first time, indicate string or not */ + return handlers[i].string; handlers[i].handler(field, (struct berval **) values); break; } } if (!handlers[i].name) { + if (!values) /* first time, indicate string conversion */ + return True; dump_string(field, (struct berval **) values); } + return False; } /** @@ -971,62 +924,56 @@ void ads_dump(ADS_STRUCT *ads, void *res) * @param data_area user-defined area to pass to function **/ void ads_process_results(ADS_STRUCT *ads, void *res, - void(*fn)(char *, void **, void *), + BOOL(*fn)(char *, void **, void *), void *data_area) { void *msg; + TALLOC_CTX *ctx; + + if (!(ctx = talloc_init())) + return; for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { - char *field; + char *utf8_field; BerElement *b; - for (field = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &b); - field; - field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) { - struct berval **values; - - values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field); - fn(field, (void **) values, data_area); - - ldap_value_free_len(values); - ldap_memfree(field); + for (utf8_field=ldap_first_attribute(ads->ld, + (LDAPMessage *)msg,&b); + utf8_field; + utf8_field=ldap_next_attribute(ads->ld, + (LDAPMessage *)msg,b)) { + struct berval **ber_vals; + char **str_vals, **utf8_vals; + char *field; + BOOL string; + + pull_utf8_talloc(ctx, (void **) &field, utf8_field); + string = fn(field, NULL, data_area); + + if (string) { + utf8_vals = ldap_get_values(ads->ld, + (LDAPMessage *)msg, field); + str_vals = ads_pull_strvals(ctx, utf8_vals); + fn(field, (void **) str_vals, data_area); + ldap_value_free(utf8_vals); + } else { + ber_vals = ldap_get_values_len(ads->ld, + (LDAPMessage *)msg, field); + fn(field, (void **) ber_vals, data_area); + + ldap_value_free_len(ber_vals); + } + ldap_memfree(utf8_field); } ber_free(b, 0); + talloc_destroy_pool(ctx); fn(NULL, NULL, data_area); /* completed an entry */ } + talloc_destroy(ctx); } -/** - * Walk through an entry, calling a function for each attribute found. - * The function receives a field name, a berval * array of values, - * and a data area passed through from the start. - * @param ads connection to ads server - * @param res Results to process - * @param fn Function for processing each result - * @param data_area user-defined area to pass to function - **/ -void ads_process_entry(ADS_STRUCT *ads, void *msg, - void(*fn)(ADS_STRUCT *, char *, void **, void *), - void *data_area) -{ - char *field; - BerElement *b; - - for (field = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &b); - field; - field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) { - struct berval **values; - - values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field); - fn(ads, field, (void **) values, data_area); - - ldap_value_free_len(values); - ldap_memfree(field); - } - ber_free(b, 0); -} /** * count how many replies are in a LDAPMessage * @param ads connection to ads server @@ -1138,6 +1085,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn) char *exp = 0; size_t sd_size = 0; struct berval **bvals = 0; + struct berval bval = {0, NULL}; prs_struct ps; prs_struct ps_wire; @@ -1192,7 +1140,9 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn) #endif if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY); - ads_mod_repl_len(ctx, &mods, attrs[0], sd_size, prs_data_p(&ps_wire)); + bval.bv_len = sd_size; + bval.bv_val = prs_data_p(&ps_wire); + ads_mod_ber(ctx, &mods, attrs[0], &bval); ret = ads_gen_mod(ads, dn, mods); prs_mem_free(&ps); @@ -1274,12 +1224,18 @@ char *ads_pull_string(ADS_STRUCT *ads, { char **values; char *ret = NULL; + char *ux_string; + int rc; values = ldap_get_values(ads->ld, msg, field); if (!values) return NULL; if (values[0]) { - ret = talloc_strdup(mem_ctx, values[0]); + rc = pull_utf8_talloc(mem_ctx, (void **)&ux_string, + values[0]); + if (rc != -1) + ret = ux_string; + } ldap_value_free(values); return ret; diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c index 52771ba39a..64ae8252c8 100644 --- a/source3/libads/ldap_printer.c +++ b/source3/libads/ldap_printer.c @@ -31,7 +31,7 @@ ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res, char *printer, char *servername) { ADS_STATUS status; - char *srv_dn, *exp; + char *srv_dn, **srv_cn, *exp; const char *attrs[] = {"*", "nTSecurityDescriptor", NULL}; status = ads_find_machine_acct(ads, res, servername); @@ -41,12 +41,14 @@ ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res, return status; } srv_dn = ldap_get_dn(ads->ld, *res); + srv_cn = ldap_explode_dn(srv_dn, 1); ads_msgfree(ads, *res); - asprintf(&exp, "(printerName=%s)", printer); - status = ads_do_search(ads, srv_dn, LDAP_SCOPE_SUBTREE, - exp, attrs, res); + asprintf(&exp, "(cn=%s-%s)", srv_cn[0], printer); + status = ads_search(ads, res, exp, attrs); + ldap_memfree(srv_dn); + ldap_value_free(srv_cn); free(exp); return status; } @@ -68,33 +70,33 @@ ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn, mods = ads_init_mods(ctx); /* add the attributes to the list - required ones first */ - ads_mod_repl(ctx, &mods, "printerName", prt->printerName); - ads_mod_repl(ctx, &mods, "serverName", prt->serverName); - ads_mod_repl(ctx, &mods, "shortServerName", prt->shortServerName); - ads_mod_repl(ctx, &mods, "uNCName", prt->uNCName); - ads_mod_repl(ctx, &mods, "versionNumber", prt->versionNumber); + ads_mod_str(ctx, &mods, "printerName", prt->printerName); + ads_mod_str(ctx, &mods, "serverName", prt->serverName); + ads_mod_str(ctx, &mods, "shortServerName", prt->shortServerName); + ads_mod_str(ctx, &mods, "uNCName", prt->uNCName); + ads_mod_str(ctx, &mods, "versionNumber", prt->versionNumber); /* now the optional ones */ - ads_mod_repl_list(ctx, &mods, "description", prt->description); - ads_mod_repl(ctx, &mods, "assetNumber",prt->assetNumber); - ads_mod_repl(ctx, &mods, "bytesPerMinute",prt->bytesPerMinute); - ads_mod_repl(ctx, &mods, "defaultPriority",prt->defaultPriority); - ads_mod_repl(ctx, &mods, "driverName", prt->driverName); - ads_mod_repl(ctx, &mods, "driverVersion",prt->driverVersion); - ads_mod_repl(ctx, &mods, "location", prt->location); - ads_mod_repl(ctx, &mods, "operatingSystem",prt->operatingSystem); - ads_mod_repl(ctx, &mods, "operatingSystemHotfix", + ads_mod_strlist(ctx, &mods, "description", prt->description); + ads_mod_str(ctx, &mods, "assetNumber",prt->assetNumber); + ads_mod_str(ctx, &mods, "bytesPerMinute",prt->bytesPerMinute); + ads_mod_str(ctx, &mods, "defaultPriority",prt->defaultPriority); + ads_mod_str(ctx, &mods, "driverName", prt->driverName); + ads_mod_str(ctx, &mods, "driverVersion",prt->driverVersion); + ads_mod_str(ctx, &mods, "location", prt->location); + ads_mod_str(ctx, &mods, "operatingSystem",prt->operatingSystem); + ads_mod_str(ctx, &mods, "operatingSystemHotfix", prt->operatingSystemHotfix); - ads_mod_repl(ctx, &mods, "operatingSystemServicePack", + ads_mod_str(ctx, &mods, "operatingSystemServicePack", prt->operatingSystemServicePack); - ads_mod_repl(ctx, &mods, "operatingSystemVersion", + ads_mod_str(ctx, &mods, "operatingSystemVersion", prt->operatingSystemVersion); - ads_mod_repl(ctx, &mods, "physicalLocationObject", + ads_mod_str(ctx, &mods, "physicalLocationObject", prt->physicalLocationObject); - ads_mod_repl_list(ctx, &mods, "portName", prt->portName); - ads_mod_repl(ctx, &mods, "printStartTime", prt->printStartTime); - ads_mod_repl(ctx, &mods, "printEndTime", prt->printEndTime); - ads_mod_repl_list(ctx, &mods, "printBinNames", prt->printBinNames); + ads_mod_strlist(ctx, &mods, "portName", prt->portName); + ads_mod_str(ctx, &mods, "printStartTime", prt->printStartTime); + ads_mod_str(ctx, &mods, "printEndTime", prt->printEndTime); + ads_mod_strlist(ctx, &mods, "printBinNames", prt->printBinNames); /*... and many others */ /* do the ldap modify */ @@ -124,12 +126,12 @@ static ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn, return ADS_ERROR(LDAP_NO_MEMORY); /* These are the fields a printQueue must contain */ - ads_mod_add(ctx, &mods, "uNCName", prt->uNCName); - ads_mod_add(ctx, &mods, "versionNumber", prt->versionNumber); - ads_mod_add(ctx, &mods, "serverName", prt->serverName); - ads_mod_add(ctx, &mods, "shortServerName", prt->shortServerName); - ads_mod_add(ctx, &mods, "printerName", prt->printerName); - ads_mod_add(ctx, &mods, "objectClass", "printQueue"); + ads_mod_str(ctx, &mods, "uNCName", prt->uNCName); + ads_mod_str(ctx, &mods, "versionNumber", prt->versionNumber); + ads_mod_str(ctx, &mods, "serverName", prt->serverName); + ads_mod_str(ctx, &mods, "shortServerName", prt->shortServerName); + ads_mod_str(ctx, &mods, "printerName", prt->printerName); + ads_mod_str(ctx, &mods, "objectClass", "printQueue"); status = ads_gen_add(ads, prt_dn, mods); @@ -157,14 +159,11 @@ ADS_STATUS ads_add_printer(ADS_STRUCT *ads, const ADS_PRINTER_ENTRY *prt) prt->shortServerName)); return status; } - host_dn = ldap_get_dn(ads->ld, res); + host_dn = ads_get_dn(ads, res); ads_msgfree(ads, res); - /* printer dn is cn=server-printer followed by host dn */ - asprintf(&prt_dn, "cn=%s-%s,%s", prt->shortServerName, - prt->printerName, host_dn); - - status = ads_search_dn(ads, &res, prt_dn, attrs); + ads_find_printer_on_server(ads, &res, prt->printerName, + prt->shortServerName); if (ADS_ERR_OK(status) && ads_count_replies(ads, res)) { DEBUG(1, ("ads_add_printer: printer %s already exists\n", diff --git a/source3/libads/ldap_user.c b/source3/libads/ldap_user.c index c1a9a89e46..d0b6c2ca8c 100644 --- a/source3/libads/ldap_user.c +++ b/source3/libads/ldap_user.c @@ -44,6 +44,8 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, ADS_MODLIST mods; ADS_STATUS status; char *upn, *new_dn, *name, *controlstr; + const char *objectClass[] = {"top", "person", "organizationalPerson", + "user", NULL}; if (fullname && *fullname) name = fullname; else name = user; @@ -63,14 +65,13 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user, if (!(mods = ads_init_mods(ctx))) goto done; - ads_mod_add(ctx, &mods, "cn", name); - ads_mod_add_var(ctx, &mods, LDAP_MOD_ADD, "objectClass", "top", - "person", "organizationalPerson", "user", NULL); - ads_mod_add(ctx, &mods, "userPrincipalName", upn); - ads_mod_add(ctx, &mods, "name", name); - ads_mod_add(ctx, &mods, "displayName", name); - ads_mod_add(ctx, &mods, "sAMAccountName", user); - ads_mod_add(ctx, &mods, "userAccountControl", controlstr); + ads_mod_str(ctx, &mods, "cn", name); + ads_mod_strlist(ctx, &mods, "objectClass", objectClass); + ads_mod_str(ctx, &mods, "userPrincipalName", upn); + ads_mod_str(ctx, &mods, "name", name); + ads_mod_str(ctx, &mods, "displayName", name); + ads_mod_str(ctx, &mods, "sAMAccountName", user); + ads_mod_str(ctx, &mods, "userAccountControl", controlstr); status = ads_gen_add(ads, new_dn, mods); done: @@ -85,6 +86,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, ADS_MODLIST mods; ADS_STATUS status; char *new_dn; + const char *objectClass[] = {"top", "group", NULL}; if (!(ctx = talloc_init_named("ads_add_group_acct"))) return ADS_ERROR(LDAP_NO_MEMORY); @@ -97,13 +99,12 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group, if (!(mods = ads_init_mods(ctx))) goto done; - ads_mod_add(ctx, &mods, "cn", group); - ads_mod_add_var(ctx, &mods, LDAP_MOD_ADD, "objectClass", "top", - "group", NULL); - ads_mod_add(ctx, &mods, "name", group); + ads_mod_str(ctx, &mods, "cn", group); + ads_mod_strlist(ctx, &mods, "objectClass",objectClass); + ads_mod_str(ctx, &mods, "name", group); if (comment) - ads_mod_add(ctx, &mods, "description", comment); - ads_mod_add(ctx, &mods, "sAMAccountName", group); + ads_mod_str(ctx, &mods, "description", comment); + ads_mod_str(ctx, &mods, "sAMAccountName", group); status = ads_gen_add(ads, new_dn, mods); done: diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 6a3ae52d85..fa3eac6bd3 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -137,27 +137,30 @@ int net_ads_check(void) } -static void usergrp_display(char *field, void **values, void *data_area) +static BOOL usergrp_display(char *field, void **values, void *data_area) { char **disp_fields = (char **) data_area; if (!field) { /* must be end of record */ if (!strchr_m(disp_fields[0], '$')) { if (disp_fields[1]) - printf("%-21.21s %-50.50s\n", + d_printf("%-21.21s %-50.50s\n", disp_fields[0], disp_fields[1]); else - printf("%s\n", disp_fields[0]); + d_printf("%s\n", disp_fields[0]); } SAFE_FREE(disp_fields[0]); SAFE_FREE(disp_fields[1]); - return; + return True; } + if (!values) /* must be new field, indicate string field */ + return True; if (StrCaseCmp(field, "sAMAccountName") == 0) { - disp_fields[0] = strdup(((struct berval *) values[0])->bv_val); + disp_fields[0] = strdup((char *) values[0]); } if (StrCaseCmp(field, "description") == 0) - disp_fields[1] = strdup(((struct berval *) values[0])->bv_val); + disp_fields[1] = strdup((char *) values[0]); + return True; /* always strings here */ } static int net_ads_user_usage(int argc, const char **argv) @@ -186,7 +189,6 @@ static int ads_user_add(int argc, const char **argv) if (ads_count_replies(ads, res)) { d_printf("ads_user_add: User %s already exists\n", argv[0]); - ads_msgfree(ads, res); goto done; } @@ -262,7 +264,7 @@ static int ads_user_info(int argc, const char **argv) char **groupname; for (i=0;grouplist[i];i++) { groupname = ldap_explode_dn(grouplist[i], 1); - printf("%s\n", groupname[0]); + d_printf("%s\n", groupname[0]); ldap_value_free(groupname); } ldap_value_free(grouplist); @@ -635,6 +637,11 @@ static int net_ads_printer_info(int argc, const char **argv) return 0; } +void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len) +{ + return; +} + static int net_ads_printer_publish(int argc, const char **argv) { ADS_STRUCT *ads; @@ -642,6 +649,7 @@ static int net_ads_printer_publish(int argc, const char **argv) char *uncname, *servername; ADS_PRINTER_ENTRY prt; extern pstring global_myname; + char *ports[2] = {"Samba", NULL}; /* these const strings are only here as an example. The attributes @@ -650,7 +658,6 @@ static int net_ads_printer_publish(int argc, const char **argv) const char *bins[] = {"Tray 21", NULL}; const char *media[] = {"Letter", NULL}; const char *orients[] = {"PORTRAIT", NULL}; - const char *ports[] = {"Samba", NULL}; if (!(ads = ads_startup())) return -1; @@ -659,6 +666,9 @@ static int net_ads_printer_publish(int argc, const char **argv) memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY)); + /* we don't sue the servername or unc name provided by + get_a_printer, because the server name might be + localhost or an ip address */ prt.printerName = argv[0]; asprintf(&servername, "%s.%s", global_myname, ads->realm); prt.serverName = servername; @@ -671,7 +681,7 @@ static int net_ads_printer_publish(int argc, const char **argv) prt.printOrientationsSupported = (char **) orients; prt.portName = (char **) ports; prt.printSpooling = "PrintAfterSpooled"; - + rc = ads_add_printer(ads, &prt); if (!ADS_ERR_OK(rc)) { d_printf("ads_publish_printer: %s\n", ads_errstr(rc)); -- cgit