/* * Copyright (c) 1993, 1994 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. * */ #include #include #include #include #include #include #include "ud.h" extern LDAPMessage * find(); #ifdef DEBUG extern int debug; #endif extern char *bound_dn, *group_base; extern int verbose, bind_status; extern struct entry Entry; extern LDAP *ld; extern void Free(); void add_group(name) char *name; { register int i, idx = 0, prompt = 0; char tmp[BUFSIZ], dn[BUFSIZ]; static LDAPMod *attrs[9]; LDAPMod init_rdn, init_owner, init_domain, init_errors, init_request, init_joinable; char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2], *init_errors_value[MAX_VALUES], *init_joinable_value[2], *init_request_value[MAX_VALUES]; extern void ldap_flush_cache(); extern char * strip_ignore_chars(); #ifdef DEBUG if (debug & D_TRACE) { if (name == NULL) printf("->add_group(NULL)\n"); else printf("->add_group(%s)\n", name); } #endif if (bind_status == UD_NOT_BOUND) { if (auth((char *) NULL, 1) < 0) { return; } } /* * If the user did not supply us with a name, prompt them for * a name. */ if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) { ++prompt; printf(" Group to create? "); fflush(stdout); fetch_buffer(tmp, sizeof(tmp), stdin); if (tmp[0] == '\0') return; name = strdup(tmp); } /* remove quotes, dots, and underscores. */ name = strip_ignore_chars(name); #ifdef UOFM if (isauniqname(name)) { printf(" '%s' could be confused with a U-M uniqname.\n", name); printf(" You can create the group, but you need to make sure that\n"); printf(" you reserve the uniqname for use as your groupname\n\n"); printf(" Are you sure that you want to do this? "); fflush(stdout); fetch_buffer(tmp, sizeof(tmp), stdin); if (!(tmp[0] == 'y' || tmp[0] == 'Y')) return; printf("\n Be sure to contact your uniqname administrator to reserve\n"); printf(" the uniqname '%s' for use as your group name.\n", name); } #endif sprintf(dn, "cn=%s, %s", name, group_base); /* * Make sure that this group does not already exist. */ if (vrfy(dn) == TRUE) { printf(" The group \"%s\" already exists.\n", name); return; } /* * Take the easy way out: Fill in some reasonable values for * the most important fields, and make the user use the modify * command to change them, or to give values to other fields. */ init_rdn_value[0] = name; init_rdn_value[1] = NULL; init_rdn.mod_op = LDAP_MOD_ADD; init_rdn.mod_type = "cn"; init_rdn.mod_values = init_rdn_value; attrs[idx++] = &init_rdn; init_owner_value[0] = bound_dn; init_owner_value[1] = NULL; init_owner.mod_op = LDAP_MOD_ADD; init_owner.mod_type = "owner"; init_owner.mod_values = init_owner_value; attrs[idx++] = &init_owner; #ifdef UOFM init_domain_value[0] = "umich.edu"; #else init_domain_value[0] = "."; #endif init_domain_value[1] = NULL; init_domain.mod_op = LDAP_MOD_ADD; init_domain.mod_type = "associatedDomain"; init_domain.mod_values = init_domain_value; attrs[idx++] = &init_domain; init_errors_value[0] = bound_dn; init_errors_value[1] = NULL; init_errors.mod_op = LDAP_MOD_ADD; init_errors.mod_type = "ErrorsTo"; init_errors.mod_values = init_errors_value; attrs[idx++] = &init_errors; init_request_value[0] = bound_dn; init_request_value[1] = NULL; init_request.mod_op = LDAP_MOD_ADD; init_request.mod_type = "RequestsTo"; init_request.mod_values = init_request_value; attrs[idx++] = &init_request; init_joinable_value[0] = "FALSE"; init_joinable_value[1] = NULL; init_joinable.mod_op = LDAP_MOD_ADD; init_joinable.mod_type = "joinable"; init_joinable.mod_values = init_joinable_value; attrs[idx++] = &init_joinable; /* end it with a NULL */ attrs[idx] = NULL; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cpp; register int j; extern char * code_to_str(); printf(" About to call ldap_add()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", dn); for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) { printf(" attrs[%1d] code = %s type = %s\n", i, code_to_str((*lpp)->mod_op), (*lpp)->mod_type); for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++) printf(" value #%1d = %s\n", j, *cpp); printf(" value #%1d = NULL\n", j); } } #endif /* * Now add this to the X.500 Directory. */ if (ldap_add_s(ld, dn, attrs) != 0) { ldap_perror(ld, " ldap_add_s"); printf(" Group not added.\n"); if (prompt) Free(name); return; } if (verbose) printf(" Group \"%s\" has been added to the Directory\n", name); /* * We need to blow away the cache here. * * Since we first looked up the name before trying to create it, * and that look-up failed, the cache will falsely claim that this * entry does not exist. */ (void) ldap_flush_cache(ld); if (prompt) Free(name); return; } void remove_group(name) char *name; { char *dn, tmp[BUFSIZ]; static char * bind_and_fetch(); #ifdef DEBUG if (debug & D_TRACE) { if (name == NULL) printf("->remove_group(NULL)\n"); else printf("->remove_group(%s)\n", name); } #endif if ((dn = bind_and_fetch(name)) == NULL) return; printf("\n The group '%s' will be permanently removed from\n", name); printf(" the Directory. Are you absolutely sure that you want to\n" ); printf(" remove this entire group? "); fflush(stdout); fetch_buffer(tmp, sizeof(tmp), stdin); if (!(tmp[0] == 'y' || tmp[0] == 'Y')) return; /* * Now remove this from the X.500 Directory. */ if (ldap_delete_s(ld, dn) != 0) { if (ld->ld_errno == LDAP_INSUFFICIENT_ACCESS) printf(" You do not own the group \"%s\".\n", name); else ldap_perror(ld, " ldap_delete_s"); printf(" Group not removed.\n"); Free(dn); return; } ldap_uncache_entry(ld, dn); if (verbose) if (name == NULL) printf(" The group has been removed.\n"); else printf(" The group \"%s\" has been removed.\n", name); Free(dn); return; } void x_group(action, name) int action; char *name; { char **vp; char *values[2], *group_name; LDAPMod mod, *mods[2]; static char *actions[] = { "join", "resign from", NULL }; static char * bind_and_fetch(); #ifdef DEBUG if (debug & D_TRACE) { if (name == NULL) printf("->x_group(%d, NULL)\n", action); else printf("->x_group(%d, %s)\n", action, name); } #endif /* the action desired sets the opcode to use */ switch (action) { case G_JOIN: mod.mod_op = LDAP_MOD_ADD; break; case G_RESIGN: mod.mod_op = LDAP_MOD_DELETE; break; default: printf("x_group: %d is not a known action\n", action); } if ((group_name = bind_and_fetch(name)) == NULL) return; vp = Entry.attrs[attr_to_index("joinable")].values; if (action == G_JOIN) { if (vp == NULL) { printf(" No one is permitted to join \"%s\"\n", group_name); Free(group_name); return; } if (!strcasecmp(*vp, "FALSE")) { printf(" No one is permitted to join \"%s\"\n", group_name); Free(group_name); return; } } /* fill in the rest of the modification structure */ mods[0] = &mod; mods[1] = (LDAPMod *) NULL; values[0] = Entry.DN; values[1] = NULL; mod.mod_type = "memberOfGroup"; mod.mod_values = values; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", bound_dn); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (ldap_modify_s(ld, bound_dn, mods)) { if ((action == G_JOIN) && (ld->ld_errno == LDAP_TYPE_OR_VALUE_EXISTS)) printf(" You are already subscribed to \"%s\"\n", group_name); else if ((action == G_RESIGN) && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) printf(" You are not subscribed to \"%s\"\n", group_name); else mod_perror(ld); Free(group_name); return; } ldap_uncache_entry(ld, bound_dn); if (verbose) { switch (action) { case G_JOIN: printf(" You are now subscribed to \"%s\"\n", group_name); break; case G_RESIGN: printf(" You are no longer subscribed to \"%s\"\n", group_name); break; } } Free(group_name); return; } void bulk_load(group) char *group; { register int idx_mail, idx_x500; register int count_mail, count_x500; char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1]; int added_mail_entries = FALSE, added_x500_entries = FALSE; char s[MED_BUF_SIZE]; LDAPMod mod, *mods[2]; LDAPMessage *lm; FILE *fp; int len; #ifdef DEBUG if (debug & D_TRACE) printf("->bulk_load(%s)\n", group); #endif /* you lose if going through MichNet */ if ( !isatty( 1 )) { #ifdef UOFM printf(" Not allowed via UM-X500 connections.\n"); #endif return; } /* fetch entries from the file containing the e-mail addresses */ printf("\n File to load? "); fflush(stdout); fetch_buffer(s, sizeof(s), stdin); if (s[0] == '\0') { return; /*NOTREACHED*/ } if ((fp = fopen(s, "r")) == NULL) { perror("bulk_load: fopen"); return; } if (verbose) printf(" Loading group members from %s\n", s); /* load them in MAX_VALUES at a time */ for (;;) { for (idx_mail = 0, idx_x500 = 0; idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) { (void) fgets(s, sizeof(s), fp); if (feof(fp)) break; len = strlen(s) - 1; if (len == 0) continue; s[len] = '\0'; if (strchr(s, '@')) values_mail[idx_mail++] = strdup(s); else { if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) { printf(" Could not locate \"%s\" -- skipping.\n", s); } else { parse_answer(lm); values_x500[idx_x500++] = strdup(Entry.DN); } } } values_mail[idx_mail] = NULL; values_x500[idx_x500] = NULL; count_mail = idx_mail; count_x500 = idx_x500; /* * Add the e-mail addresses. */ if (count_mail > 0) { mods[0] = &mod; mods[1] = (LDAPMod *) NULL; mod.mod_type = "mail"; mod.mod_values = values_mail; if (added_mail_entries) mod.mod_op = LDAP_MOD_ADD; else mod.mod_op = LDAP_MOD_REPLACE; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", group); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (ldap_modify_s(ld, group, mods)) mod_perror(ld); for (idx_mail--; idx_mail >= 0; idx_mail--) Free(values_mail[idx_mail]); ldap_uncache_entry(ld, group); added_mail_entries = TRUE; } /* * Add the X.500 style names. */ if (count_x500 > 0) { mods[0] = &mod; mods[1] = (LDAPMod *) NULL; mod.mod_type = "member"; mod.mod_values = values_x500; if (added_x500_entries) mod.mod_op = LDAP_MOD_ADD; else mod.mod_op = LDAP_MOD_REPLACE; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", group); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (ldap_modify_s(ld, group, mods)) mod_perror(ld); for (idx_x500--; idx_x500 >= 0; idx_x500--) Free(values_x500[idx_x500]); ldap_uncache_entry(ld, group); added_x500_entries = TRUE; } /* * If both counts were less than the maximum number we * can handle at a time, then we are done. */ if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES)) break; } fclose(fp); return; } void purge_group(group) char *group; { int isclean = TRUE; LDAPMessage *lm; LDAPMod mod, *mods[2]; char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns; extern char * my_ldap_dn2ufn(); extern int col_size; #ifdef DEBUG if (debug & D_TRACE) { if (group == NULL) printf("->purge_group(NULL)\n"); else printf("->purge_group(%s)\n", group); } #endif if (bind_status == UD_NOT_BOUND) { if (auth((char *) NULL, 1) < 0) return; } /* * If the user did not supply us with a name, prompt them for * a name. */ if ((group == NULL) || (*group == '\0')) { printf("Group to purge? "); fflush(stdout); fetch_buffer(tmp, sizeof(tmp), stdin); if (tmp[0] == '\0') return; group = tmp; } sprintf(dn, "cn=%s, %s", group, group_base); /* make sure the group in question exists */ if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) { printf(" Could not locate group \"%s\"\n", group); return; } parse_answer(lm); ldap_msgfree(lm); /* none of this stuff changes */ mods[0] = &mod; mods[1] = (LDAPMod *) NULL; values[1] = NULL; mod.mod_values = values; mod.mod_type = "member"; mod.mod_op = LDAP_MOD_DELETE; /* * Now cycle through all of the names in the "members" part of the * group (but not the e-mail address part). Lookup each one, and * if it isn't found, let the user know so s/he can delete it. */ vp = Entry.attrs[attr_to_index("member")].values; if (vp == NULL) { if (verbose) printf(" \"%s\" has no X.500 members. There is nothing to purge.\n", group); return; } for (; *vp != NULL; vp++) { char ans[BUFSIZ], *ufn, *label = "Did not find: "; int len = strlen(label); if (vrfy(*vp)) continue; isclean = FALSE; ufn = my_ldap_dn2ufn(*vp); format2(ufn, label, (char *) NULL, 2, 2 + len, col_size); ask: printf(" Purge, Keep, Replace, Abort [Keep]? "); fflush(stdout); fetch_buffer(ans, sizeof(ans), stdin); if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans))) continue; if (!strncasecmp(ans, "Abort", strlen(ans))) { ldap_uncache_entry(ld, dn); return; } if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) { values[0] = *vp; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", Entry.DN); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (ldap_modify_s(ld, Entry.DN, mods)) mod_perror(ld); /* now add the replacement if requested */ if (!strncasecmp(ans, "Purge", strlen(ans))) continue; rdns = ldap_explode_dn(*vp, TRUE); if ((lm = find(*rdns, FALSE)) == NULL) { printf(" Could not find a replacement for %s; purged only.\n", *rdns); ldap_msgfree(lm); ldap_value_free(rdns); break; } values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm)); mod.mod_op = LDAP_MOD_ADD; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", Entry.DN); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (ldap_modify_s(ld, Entry.DN, mods)) mod_perror(ld); ldap_msgfree(lm); ldap_value_free(rdns); /* set this back to DELETE for other purges */ mod.mod_op = LDAP_MOD_DELETE; } else { printf(" Did not recognize that answer.\n\n"); goto ask; } } ldap_uncache_entry(ld, Entry.DN); if (isclean) printf(" No entries were purged.\n"); return; } void tidy_up() { register int i = 0; int found_one = 0; register char **vp; LDAPMessage *lm; static LDAPMod mod; static LDAPMod *mods[2] = { &mod, NULL }; static char *values[MAX_VALUES]; #ifdef DEBUG if (debug & D_TRACE) printf("->tidy()\n"); #endif if (bind_status == UD_NOT_BOUND) { if (auth((char *) NULL, 1) < 0) { return; } } /* lookup the user, and see to which groups he has subscribed */ vp = ldap_explode_dn(bound_dn, TRUE); if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) { printf(" Could not locate \"%s\"\n", *vp); ldap_value_free(vp); return; } ldap_value_free(vp); parse_answer(lm); ldap_msgfree(lm); vp = Entry.attrs[attr_to_index("memberOfGroup")].values; if (vp == NULL) { printf(" You have not subscribed to any groups.\n"); return; } /* now, loop through these groups, deleting the bogus */ for ( ; *vp != NULL; vp++) { if (vrfy(*vp)) continue; found_one++; printf(" \"%s\" is not a valid group name.\n", *vp); values[i++] = strdup(*vp); if ( i >= MAX_VALUES ) { printf( " At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES ); break; } } if (found_one == 0) { if (verbose) printf(" You are not a member of any invalid groups. There is nothing to tidy.\n"); return; } /* delete the most heinous entries */ values[i] = NULL; mod.mod_values = values; mod.mod_op = LDAP_MOD_DELETE; mod.mod_type = "memberOfGroup"; if (ldap_modify_s(ld, bound_dn, mods)) mod_perror(ld); ldap_uncache_entry(ld, bound_dn); /* tidy up before we finish tidy_up */ for ( ; i >= 1; i--) Free(values[i - 1]); return; } /* * This routine is used to modify lists that can contain either Distinguished * Names or e-mail addresses. This includes things like group members, * the errors-to field in groups, and so on. */ void mod_addrDN(group, offset) char *group; int offset; { extern struct attribute attrlist[]; char s[BUFSIZ], *new_value /* was member */, *values[2]; char attrtype[ 64 ]; int i; LDAPMod mod, *mods[2]; LDAPMessage *mp; #ifdef DEBUG if (debug & D_TRACE) printf("->mod_addrDN(%s)\n", group); #endif /* * At this point the user can indicate that he wishes to add values * to the attribute, delete values from the attribute, or replace the * current list of values with a new list. The first two cases * are very straight-forward, but the last case requires a little * extra care and work. */ if (verbose) { printf("\n"); if ( !isatty( 1 )) format("There are three options available at this point. You may: Add additional values; Delete values; or Replace the entire list of values with a new list entered interactively.\n", 75, 2); else format("There are four options available at this point. You may: Add one or more additional values; Delete one or more existing values; Replace the entire list of values with a new list entered interactively; or Bulk load a new list of values from a file, overwriting the existing list.\n", 75, 2); } /* initialize the modififier type */ mod.mod_type = NULL; for (;;) { if ( !isatty( 1 )) printf(" Do you want to Add, Delete, or Replace? "); else printf(" Do you want to Add, Delete, Replace, or Bulk load? "); fflush(stdout); fetch_buffer(s, sizeof(s), stdin); if (s[0] == '\0') { return; /*NOTREACHED*/ } if (!strncasecmp(s, "add", strlen(s))) { mod.mod_op = LDAP_MOD_ADD; break; } else if (!strncasecmp(s, "delete", strlen(s))) { mod.mod_op = LDAP_MOD_DELETE; break; } else if (!strncasecmp(s, "replace", strlen(s))) { mod.mod_op = LDAP_MOD_REPLACE; break; } else if(!strncasecmp(s, "bulk", strlen(s))) { bulk_load(group); return; } else if (verbose) { printf("\n"); if ( !isatty( 1 )) format("Did not recognize that response. Please use 'A' to add, 'D' to delete, or 'R' to replace the entire list with a new list\n", 75, 2); else format("Did not recognize that response. Please use 'A' to add, 'D' to delete, 'R' to replace the entire list with a new list, or 'B' to bulk load a new list from a file\n", 75, 2); } } if (mod.mod_op == LDAP_MOD_REPLACE) { if ( verbose && !confirm_action( "The entire existing list will be overwritten with the new values you are about to enter." )) { printf("\n Modification halted.\n"); return; } } if (verbose) { printf("\n"); format("Values may be specified as a name (which is then looked up in the X.500 Directory) or as a domain-style (i.e., user@domain) e-mail address. Simply hit the RETURN key at the prompt when finished.\n", 75, 2); printf("\n"); } for (;;) { printf("%s? ", attrlist[offset].output_string); fflush(stdout); fetch_buffer(s, sizeof(s), stdin); if (s[0] == '\0') return; /* * If the string the user has just typed has an @-sign in it, * then we assume it is an e-mail address. In this case, we * just store away whatever it is they have typed. * * If the string had no @-sign, then we look in the Directory, * make sure it exists, and if it does, we add that. * * If the string begins with a comma, then strip off the * comma, and pass it along to the LDAP server. This is * the way one can force ud to accept a name. Handy for * debugging purposes. */ if (*s == ',') { new_value = s + 1; mod.mod_type = attrlist[offset].quipu_name; } else if (strchr(s, '@') == NULL) { if ((mp = find(s, FALSE)) == (LDAPMessage *) NULL) { printf(" Could not find \"%s\"\n", s); if (verbose && (mod.mod_op == LDAP_MOD_DELETE)){ printf("\n"); format("I could not find anything that matched what you typed. You might try the \"purge\" command instead. It is used to purge corrupted or unlocatable entries from a group.", 75, 2); printf("\n"); } continue; } parse_answer(mp); new_value = Entry.DN; mod.mod_type = attrlist[offset].quipu_name; } else if (mod.mod_op != LDAP_MOD_DELETE) { /* * Don't screw around with what the user has typed * if they are simply trying to delete a rfc822mailbox * value. * * spaces on the left hand side of the e-mail * address are bad news - we know that there * must be a @-sign in the string, or else we * would not be here * * note that this means a value like: * * first m. last@host.domain * * will be turned into: * * first.m..last@host.domain * * and the mailer will need to do the right thing * with this; alternatively we could add code that * collapsed multiple dots into a single dot * * Don't screw up things like: * * "Bryan Beecher" * Bryan Beecher */ register char *cp; if (strchr(s, '<') == NULL) { for (cp = s; *cp != '@'; cp++) if (isspace(*cp)) *cp = '.'; } new_value = s; strcpy(attrtype, "rfc822"); strcat(attrtype, attrlist[offset].quipu_name); mod.mod_type = attrtype; } else { new_value = s; strcpy(attrtype, "rfc822"); strcat(attrtype, attrlist[offset].quipu_name); mod.mod_type = attrtype; } /* fill in the rest of the ldap_mod() structure */ mods[0] = &mod; mods[1] = (LDAPMod *) NULL; values[0] = new_value; values[1] = NULL; mod.mod_values = values; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", group); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (my_ldap_modify_s(ld, group, mods)) { if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) { printf(" Could not locate value \"%s\"\n", new_value); continue; } else { mod_perror(ld); return; } } ldap_uncache_entry(ld, group); /* * If the operation was REPLACE, we now need to "zero out" the * other "half" of the list (e.g., user specified an e-mail * address; now we need to clear the DN part of the list). * * NOTE: WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE. * * Also, change the opcode to LDAP_MOD_ADD and give the user an * opportunity to add additional members to the group. We * only take this branch the very first time during a REPLACE * operation. */ if (mod.mod_op == LDAP_MOD_REPLACE) { if (!strncmp(mod.mod_type, "rfc822", 6)) mod.mod_type = mod.mod_type + 6; else { strcpy(attrtype, "rfc822"); strcat(attrtype, mod.mod_type); mod.mod_type = attrtype; } mods[0] = &mod; values[0] = NULL; mod.mod_values = values; mod.mod_op = LDAP_MOD_DELETE; #ifdef DEBUG if (debug & D_GROUPS) { register LDAPMod **lpp; register char **cp; register int i, j; printf(" About to call ldap_modify_s()\n"); printf(" ld = 0x%x\n", ld); printf(" dn = [%s]\n", group); for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) { printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op); printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type); for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++) printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp); } } #endif if (my_ldap_modify_s(ld, group, mods)) { /* * A "No such attribute" error is no big deal. * We only wanted to clear the attribute anyhow. */ if (ld->ld_errno != LDAP_NO_SUCH_ATTRIBUTE) { mod_perror(ld); return; } } ldap_uncache_entry(ld, group); if (verbose) printf(" \"%s\" has been added\n", new_value); mod.mod_op = LDAP_MOD_ADD; } else if (verbose && (mod.mod_op == LDAP_MOD_ADD)) printf(" \"%s\" has been added\n", new_value); else if (verbose && (mod.mod_op == LDAP_MOD_DELETE)) printf(" \"%s\" has been removed\n", new_value); } } my_ldap_modify_s(ldap, group, mods) LDAP *ldap; char *group; LDAPMod *mods[]; { int was_rfc822member, rc; was_rfc822member = 0; if (!strcasecmp(mods[0]->mod_type, "rfc822member")) { mods[0]->mod_type = "mail"; was_rfc822member = 1; } rc = ldap_modify_s(ldap, group, mods); if (was_rfc822member) mods[0]->mod_type = "rfc822member"; return(rc); } void list_groups(who) char *who; { LDAPMessage *mp; char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2]; char *work_area[MAX_NUM_NAMES]; char *dn, **rdns; int i, rc; #ifdef DEBUG if (debug & D_TRACE) { if (who == NULL) printf("->list_groups(NULL)\n"); else printf("->list_groups(%s)\n", who); } #endif /* * First, decide what entry we are going to list. If the * user has not included a name on the list command line, * we will use the person who was last looked up with a find * command. * * Once we know who to modify, be sure that they exist, and * parse out their DN. */ if (who == NULL) { printf(" List groups belonging to whose entry? "); fflush(stdout); fetch_buffer(name, sizeof(name), stdin); if (name[0] != '\0') who = name; else return; } if ((mp = find(who, TRUE)) == NULL) { (void) ldap_msgfree(mp); printf(" Could not locate \"%s\" in the Directory.\n", who); return; } dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); ldap_msgfree(mp); rdns = ldap_explode_dn(dn, TRUE); if (verbose) printf("\n Listing groups belonging to \"%s\"\n", *rdns); /* lookup the groups belonging to this person */ sprintf(filter, "owner=%s", dn); Free(dn); search_attrs[0] = "cn"; search_attrs[1] = NULL; if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) { ldap_perror(ld, "ldap_search_s"); ldap_value_free(rdns); return; } if ((rc = ldap_count_entries(ld, mp)) < 0) { ldap_perror(ld, "ldap_count_entries"); ldap_value_free(rdns); return; } if (rc == 0) { printf(" %s owns no groups in this portion of the Directory.\n", *rdns); ldap_value_free(rdns); return; } if (verbose) printf(" %s owns %d groups.\n\n", *rdns, rc); print_list(mp, work_area, &rc); for (i = 1; work_area[i] != NULL; i++) Free(work_area[i]); ldap_msgfree(mp); ldap_value_free(rdns); return; } static char * bind_and_fetch(name) char *name; { LDAPMessage *lm; char tmp[MED_BUF_SIZE]; extern char * strip_ignore_chars(); #ifdef DEBUG if (debug & D_TRACE) { if (name == NULL) printf("->bind_and_fetch(NULL)\n"); else printf("->bind_and_fetch(%s)\n", name); } #endif if (bind_status == UD_NOT_BOUND) { if (auth((char *) NULL, 1) < 0) return(NULL); } /* * If the user did not supply us with a name, prompt them for * a name. */ if ((name == NULL) || (*name == '\0')) { printf(" Group? "); fflush(stdout); fetch_buffer(tmp, sizeof(tmp), stdin); if (tmp[0] == '\0') return(NULL); name = tmp; } /* remove quotes, dots, and underscores. */ name = strip_ignore_chars(name); #ifdef DEBUG if (debug & D_GROUPS) printf("Group name = (%s)\n", name); #endif /* make sure the group in question exists and is joinable */ if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) { printf(" Could not locate group \"%s\"\n", name); return(NULL); } parse_answer(lm); ldap_msgfree(lm); #ifdef DEBUG if (debug & D_GROUPS) printf("Group DN = (%s)\n", Entry.DN); #endif return(strdup(Entry.DN)); } void list_memberships(who) char *who; { LDAPMessage *mp; char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2]; char *work_area[MAX_NUM_NAMES]; char *dn, **rdns; int i, rc; #ifdef DEBUG if (debug & D_TRACE) { if (who == NULL) printf("->list_memberships(NULL)\n"); else printf("->list_memberships(%s)\n", who); } #endif /* * First, decide what entry we are going to list. If the * user has not included a name on the list command line, * we will use the person who was last looked up with a find * command. * * Once we know who to modify, be sure that they exist, and * parse out their DN. */ if (who == NULL) { printf(" List memberships containing whose entry? "); fflush(stdout); fetch_buffer(name, sizeof(name), stdin); if (name[0] != '\0') who = name; else return; } if ((mp = find(who, TRUE)) == NULL) { (void) ldap_msgfree(mp); printf(" Could not locate \"%s\" in the Directory.\n", who); ldap_msgfree(mp); return; } dn = ldap_get_dn(ld, ldap_first_entry(ld, mp)); rdns = ldap_explode_dn(dn, TRUE); if (verbose) printf("\n Listing memberships of \"%s\"\n", *rdns); /* lookup the groups belonging to this person */ sprintf(filter, "member=%s", dn); Free(dn); search_attrs[0] = "cn"; search_attrs[1] = NULL; ldap_msgfree(mp); if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) { ldap_perror(ld, "ldap_search_s"); ldap_msgfree(mp); ldap_value_free(rdns); return; } if ((rc = ldap_count_entries(ld, mp)) < 0) { ldap_perror(ld, "ldap_count_entries"); ldap_msgfree(mp); ldap_value_free(rdns); return; } if (rc == 0) { printf(" %s is not a member of any groups in this portion of the Directory.\n", *rdns); ldap_msgfree(mp); ldap_value_free(rdns); return; } if (verbose) printf(" %s is a member of %d groups.\n\n", *rdns, rc); /* * print_list fills in the char * array starting at 1, not 0 */ print_list(mp, work_area, &rc); for (i = 1; work_area[i] != NULL; i++) Free(work_area[i]); ldap_msgfree(mp); ldap_value_free(rdns); return; }