2 * Copyright (c) 1993, 1994 Regents of the University of Michigan.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of Michigan at Ann Arbor. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
18 #include <ac/string.h>
24 #include <ldapconfig.h>
27 extern LDAPMessage * find();
33 extern char *bound_dn, *group_base;
34 extern int verbose, bind_status;
35 extern struct entry Entry;
40 static char * bind_and_fetch();
45 register int i, idx = 0, prompt = 0;
46 char tmp[BUFSIZ], dn[BUFSIZ];
47 static LDAPMod *attrs[9];
48 LDAPMod init_rdn, init_owner, init_domain,
49 init_errors, init_request, init_joinable;
50 char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2],
51 *init_errors_value[MAX_VALUES], *init_joinable_value[2],
52 *init_request_value[MAX_VALUES];
53 extern void ldap_flush_cache();
54 extern char * strip_ignore_chars();
57 if (debug & D_TRACE) {
59 printf("->add_group(NULL)\n");
61 printf("->add_group(%s)\n", name);
65 if (bind_status == UD_NOT_BOUND) {
66 if (auth((char *) NULL, 1) < 0) {
72 * If the user did not supply us with a name, prompt them for
75 if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) {
77 printf(" Group to create? ");
79 fetch_buffer(tmp, sizeof(tmp), stdin);
85 /* remove quotes, dots, and underscores. */
86 name = strip_ignore_chars(name);
89 if (isauniqname(name)) {
90 printf(" '%s' could be confused with a U-M uniqname.\n", name);
91 printf(" You can create the group, but you need to make sure that\n");
92 printf(" you reserve the uniqname for use as your groupname\n\n");
93 printf(" Are you sure that you want to do this? ");
95 fetch_buffer(tmp, sizeof(tmp), stdin);
96 if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
98 printf("\n Be sure to contact your uniqname administrator to reserve\n");
99 printf(" the uniqname '%s' for use as your group name.\n", name);
102 sprintf(dn, "cn=%s, %s", name, group_base);
105 * Make sure that this group does not already exist.
107 if (vrfy(dn) == TRUE) {
108 printf(" The group \"%s\" already exists.\n", name);
113 * Take the easy way out: Fill in some reasonable values for
114 * the most important fields, and make the user use the modify
115 * command to change them, or to give values to other fields.
117 init_rdn_value[0] = name;
118 init_rdn_value[1] = NULL;
119 init_rdn.mod_op = LDAP_MOD_ADD;
120 init_rdn.mod_type = "cn";
121 init_rdn.mod_values = init_rdn_value;
122 attrs[idx++] = &init_rdn;
124 init_owner_value[0] = bound_dn;
125 init_owner_value[1] = NULL;
126 init_owner.mod_op = LDAP_MOD_ADD;
127 init_owner.mod_type = "owner";
128 init_owner.mod_values = init_owner_value;
129 attrs[idx++] = &init_owner;
132 init_domain_value[0] = "umich.edu";
134 init_domain_value[0] = ".";
136 init_domain_value[1] = NULL;
137 init_domain.mod_op = LDAP_MOD_ADD;
138 init_domain.mod_type = "associatedDomain";
139 init_domain.mod_values = init_domain_value;
140 attrs[idx++] = &init_domain;
142 init_errors_value[0] = bound_dn;
143 init_errors_value[1] = NULL;
144 init_errors.mod_op = LDAP_MOD_ADD;
145 init_errors.mod_type = "ErrorsTo";
146 init_errors.mod_values = init_errors_value;
147 attrs[idx++] = &init_errors;
149 init_request_value[0] = bound_dn;
150 init_request_value[1] = NULL;
151 init_request.mod_op = LDAP_MOD_ADD;
152 init_request.mod_type = "RequestsTo";
153 init_request.mod_values = init_request_value;
154 attrs[idx++] = &init_request;
156 init_joinable_value[0] = "FALSE";
157 init_joinable_value[1] = NULL;
158 init_joinable.mod_op = LDAP_MOD_ADD;
159 init_joinable.mod_type = "joinable";
160 init_joinable.mod_values = init_joinable_value;
161 attrs[idx++] = &init_joinable;
163 /* end it with a NULL */
167 if (debug & D_GROUPS) {
168 register LDAPMod **lpp;
171 extern char * code_to_str();
172 printf(" About to call ldap_add()\n");
173 printf(" ld = 0x%x\n", ld);
174 printf(" dn = [%s]\n", dn);
175 for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) {
176 printf(" attrs[%1d] code = %s type = %s\n", i,
177 code_to_str((*lpp)->mod_op), (*lpp)->mod_type);
178 for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++)
179 printf(" value #%1d = %s\n", j, *cpp);
180 printf(" value #%1d = NULL\n", j);
186 * Now add this to the LDAP Directory.
188 if (ldap_add_s(ld, dn, attrs) != 0) {
189 ldap_perror(ld, " ldap_add_s");
190 printf(" Group not added.\n");
191 if (prompt) Free(name);
195 printf(" Group \"%s\" has been added to the Directory\n",
199 * We need to blow away the cache here.
201 * Since we first looked up the name before trying to create it,
202 * and that look-up failed, the cache will falsely claim that this
203 * entry does not exist.
205 (void) ldap_flush_cache(ld);
206 if (prompt) Free(name);
210 void remove_group(name)
213 char *dn, tmp[BUFSIZ];
216 if (debug & D_TRACE) {
218 printf("->remove_group(NULL)\n");
220 printf("->remove_group(%s)\n", name);
223 if ((dn = bind_and_fetch(name)) == NULL)
226 printf("\n The group '%s' will be permanently removed from\n",
228 printf(" the Directory. Are you absolutely sure that you want to\n" ); printf(" remove this entire group? ");
230 fetch_buffer(tmp, sizeof(tmp), stdin);
231 if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
235 * Now remove this from the LDAP Directory.
237 if (ldap_delete_s(ld, dn) != 0) {
239 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
240 if (ld_errno == LDAP_INSUFFICIENT_ACCESS)
241 printf(" You do not own the group \"%s\".\n", name);
243 ldap_perror(ld, " ldap_delete_s");
244 printf(" Group not removed.\n");
248 ldap_uncache_entry(ld, dn);
251 printf(" The group has been removed.\n");
253 printf(" The group \"%s\" has been removed.\n", name);
258 void x_group(action, name)
263 char *values[2], *group_name;
264 LDAPMod mod, *mods[2];
265 static char *actions[] = { "join", "resign from", NULL };
268 if (debug & D_TRACE) {
270 printf("->x_group(%d, NULL)\n", action);
272 printf("->x_group(%d, %s)\n", action, name);
276 /* the action desired sets the opcode to use */
279 mod.mod_op = LDAP_MOD_ADD;
282 mod.mod_op = LDAP_MOD_DELETE;
285 printf("x_group: %d is not a known action\n", action);
288 if ((group_name = bind_and_fetch(name)) == NULL)
290 vp = Entry.attrs[attr_to_index("joinable")].values;
291 if (action == G_JOIN) {
293 printf(" No one is permitted to join \"%s\"\n", group_name);
297 if (!strcasecmp(*vp, "FALSE")) {
298 printf(" No one is permitted to join \"%s\"\n", group_name);
304 /* fill in the rest of the modification structure */
306 mods[1] = (LDAPMod *) NULL;
307 values[0] = Entry.DN;
309 mod.mod_type = "memberOfGroup";
310 mod.mod_values = values;
313 if (debug & D_GROUPS) {
314 register LDAPMod **lpp;
317 printf(" About to call ldap_modify_s()\n");
318 printf(" ld = 0x%x\n", ld);
319 printf(" dn = [%s]\n", bound_dn);
320 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
321 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
322 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
323 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
324 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
330 if (ldap_modify_s(ld, bound_dn, mods)) {
332 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
333 if ((action == G_JOIN) && (ld_errno == LDAP_TYPE_OR_VALUE_EXISTS))
334 printf(" You are already subscribed to \"%s\"\n", group_name);
335 else if ((action == G_RESIGN) && (ld_errno == LDAP_NO_SUCH_ATTRIBUTE))
336 printf(" You are not subscribed to \"%s\"\n", group_name);
342 ldap_uncache_entry(ld, bound_dn);
346 printf(" You are now subscribed to \"%s\"\n", group_name);
349 printf(" You are no longer subscribed to \"%s\"\n", group_name);
357 void bulk_load(group)
360 register int idx_mail, idx_x500;
361 register int count_mail, count_x500;
362 char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1];
363 int added_mail_entries = FALSE, added_x500_entries = FALSE;
364 char s[MED_BUF_SIZE];
365 LDAPMod mod, *mods[2];
372 printf("->bulk_load(%s)\n", group);
375 /* you lose if going through MichNet */
378 printf(" Not allowed via UM-X500 connections.\n");
383 /* fetch entries from the file containing the e-mail addresses */
384 printf("\n File to load? ");
386 fetch_buffer(s, sizeof(s), stdin);
391 if ((fp = fopen(s, "r")) == NULL) {
392 perror("bulk_load: fopen");
396 printf(" Loading group members from %s\n", s);
398 /* load them in MAX_VALUES at a time */
400 for (idx_mail = 0, idx_x500 = 0;
401 idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) {
402 (void) fgets(s, sizeof(s), fp);
410 values_mail[idx_mail++] = strdup(s);
412 if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) {
413 printf(" Could not locate \"%s\" -- skipping.\n", s);
417 values_x500[idx_x500++] = strdup(Entry.DN);
421 values_mail[idx_mail] = NULL;
422 values_x500[idx_x500] = NULL;
423 count_mail = idx_mail;
424 count_x500 = idx_x500;
427 * Add the e-mail addresses.
429 if (count_mail > 0) {
431 mods[1] = (LDAPMod *) NULL;
432 mod.mod_type = "mail";
433 mod.mod_values = values_mail;
434 if (added_mail_entries)
435 mod.mod_op = LDAP_MOD_ADD;
437 mod.mod_op = LDAP_MOD_REPLACE;
440 if (debug & D_GROUPS) {
441 register LDAPMod **lpp;
444 printf(" About to call ldap_modify_s()\n");
445 printf(" ld = 0x%x\n", ld);
446 printf(" dn = [%s]\n", group);
447 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
448 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
449 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
450 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
451 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
455 if (ldap_modify_s(ld, group, mods))
457 for (idx_mail--; idx_mail >= 0; idx_mail--)
458 Free(values_mail[idx_mail]);
459 ldap_uncache_entry(ld, group);
460 added_mail_entries = TRUE;
465 * Add the LDAP style names.
467 if (count_x500 > 0) {
469 mods[1] = (LDAPMod *) NULL;
470 mod.mod_type = "member";
471 mod.mod_values = values_x500;
472 if (added_x500_entries)
473 mod.mod_op = LDAP_MOD_ADD;
475 mod.mod_op = LDAP_MOD_REPLACE;
478 if (debug & D_GROUPS) {
479 register LDAPMod **lpp;
482 printf(" About to call ldap_modify_s()\n");
483 printf(" ld = 0x%x\n", ld);
484 printf(" dn = [%s]\n", group);
485 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
486 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
487 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
488 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
489 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
493 if (ldap_modify_s(ld, group, mods))
495 for (idx_x500--; idx_x500 >= 0; idx_x500--)
496 Free(values_x500[idx_x500]);
497 ldap_uncache_entry(ld, group);
498 added_x500_entries = TRUE;
503 * If both counts were less than the maximum number we
504 * can handle at a time, then we are done.
506 if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES))
513 void purge_group(group)
518 LDAPMod mod, *mods[2];
519 char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns;
520 extern char * my_ldap_dn2ufn();
524 if (debug & D_TRACE) {
526 printf("->purge_group(NULL)\n");
528 printf("->purge_group(%s)\n", group);
531 if (bind_status == UD_NOT_BOUND) {
532 if (auth((char *) NULL, 1) < 0)
536 * If the user did not supply us with a name, prompt them for
539 if ((group == NULL) || (*group == '\0')) {
540 printf("Group to purge? ");
542 fetch_buffer(tmp, sizeof(tmp), stdin);
547 sprintf(dn, "cn=%s, %s", group, group_base);
549 /* make sure the group in question exists */
550 if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) {
551 printf(" Could not locate group \"%s\"\n", group);
557 /* none of this stuff changes */
559 mods[1] = (LDAPMod *) NULL;
563 mod.mod_values = values;
564 mod.mod_type = "member";
565 mod.mod_op = LDAP_MOD_DELETE;
568 * Now cycle through all of the names in the "members" part of the
569 * group (but not the e-mail address part). Lookup each one, and
570 * if it isn't found, let the user know so s/he can delete it.
572 vp = Entry.attrs[attr_to_index("member")].values;
575 printf(" \"%s\" has no LDAP members. There is nothing to purge.\n", group);
578 for (; *vp != NULL; vp++) {
579 char ans[BUFSIZ], *ufn, *label = "Did not find: ";
580 int len = strlen(label);
585 ufn = my_ldap_dn2ufn(*vp);
586 format2(ufn, label, (char *) NULL, 2, 2 + len, col_size);
588 printf(" Purge, Keep, Replace, Abort [Keep]? ");
590 fetch_buffer(ans, sizeof(ans), stdin);
591 if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans)))
593 if (!strncasecmp(ans, "Abort", strlen(ans))) {
594 ldap_uncache_entry(ld, dn);
597 if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) {
600 if (debug & D_GROUPS) {
601 register LDAPMod **lpp;
604 printf(" About to call ldap_modify_s()\n");
605 printf(" ld = 0x%x\n", ld);
606 printf(" dn = [%s]\n", Entry.DN);
607 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
608 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
609 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
610 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
611 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
616 if (ldap_modify_s(ld, Entry.DN, mods))
619 /* now add the replacement if requested */
620 if (!strncasecmp(ans, "Purge", strlen(ans)))
622 rdns = ldap_explode_dn(*vp, TRUE);
623 if ((lm = find(*rdns, FALSE)) == NULL) {
624 printf(" Could not find a replacement for %s; purged only.\n", *rdns);
626 ldap_value_free(rdns);
629 values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm));
630 mod.mod_op = LDAP_MOD_ADD;
632 if (debug & D_GROUPS) {
633 register LDAPMod **lpp;
636 printf(" About to call ldap_modify_s()\n");
637 printf(" ld = 0x%x\n", ld);
638 printf(" dn = [%s]\n", Entry.DN);
639 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
640 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
641 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
642 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
643 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
648 if (ldap_modify_s(ld, Entry.DN, mods))
651 ldap_value_free(rdns);
653 /* set this back to DELETE for other purges */
654 mod.mod_op = LDAP_MOD_DELETE;
657 printf(" Did not recognize that answer.\n\n");
661 ldap_uncache_entry(ld, Entry.DN);
663 printf(" No entries were purged.\n");
674 static LDAPMod *mods[2] = { &mod, NULL };
675 static char *values[MAX_VALUES];
679 printf("->tidy()\n");
682 if (bind_status == UD_NOT_BOUND) {
683 if (auth((char *) NULL, 1) < 0) {
688 /* lookup the user, and see to which groups he has subscribed */
689 vp = ldap_explode_dn(bound_dn, TRUE);
690 if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) {
691 printf(" Could not locate \"%s\"\n", *vp);
698 vp = Entry.attrs[attr_to_index("memberOfGroup")].values;
700 printf(" You have not subscribed to any groups.\n");
704 /* now, loop through these groups, deleting the bogus */
705 for ( ; *vp != NULL; vp++) {
709 printf(" \"%s\" is not a valid group name.\n", *vp);
710 values[i++] = strdup(*vp);
711 if ( i >= MAX_VALUES ) {
712 printf( " At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES );
716 if (found_one == 0) {
718 printf(" You are not a member of any invalid groups. There is nothing to tidy.\n");
722 /* delete the most heinous entries */
724 mod.mod_values = values;
725 mod.mod_op = LDAP_MOD_DELETE;
726 mod.mod_type = "memberOfGroup";
727 if (ldap_modify_s(ld, bound_dn, mods))
729 ldap_uncache_entry(ld, bound_dn);
731 /* tidy up before we finish tidy_up */
738 * This routine is used to modify lists that can contain either Distinguished
739 * Names or e-mail addresses. This includes things like group members,
740 * the errors-to field in groups, and so on.
742 void mod_addrDN(group, offset)
746 extern struct attribute attrlist[];
747 char s[BUFSIZ], *new_value /* was member */, *values[2];
750 LDAPMod mod, *mods[2];
755 printf("->mod_addrDN(%s)\n", group);
758 * At this point the user can indicate that he wishes to add values
759 * to the attribute, delete values from the attribute, or replace the
760 * current list of values with a new list. The first two cases
761 * are very straight-forward, but the last case requires a little
762 * extra care and work.
767 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);
769 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);
772 /* initialize the modififier type */
777 printf(" Do you want to Add, Delete, or Replace? ");
779 printf(" Do you want to Add, Delete, Replace, or Bulk load? ");
781 fetch_buffer(s, sizeof(s), stdin);
786 if (!strncasecmp(s, "add", strlen(s))) {
787 mod.mod_op = LDAP_MOD_ADD;
790 else if (!strncasecmp(s, "delete", strlen(s))) {
791 mod.mod_op = LDAP_MOD_DELETE;
794 else if (!strncasecmp(s, "replace", strlen(s))) {
795 mod.mod_op = LDAP_MOD_REPLACE;
798 else if(!strncasecmp(s, "bulk", strlen(s))) {
805 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);
807 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);
810 if (mod.mod_op == LDAP_MOD_REPLACE) {
811 if ( verbose && !confirm_action( "The entire existing list will be overwritten with the new values you are about to enter." )) {
812 printf("\n Modification halted.\n");
818 format("Values may be specified as a name (which is then looked up in the LDAP 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);
823 printf("%s? ", attrlist[offset].output_string);
825 fetch_buffer(s, sizeof(s), stdin);
830 * If the string the user has just typed has an @-sign in it,
831 * then we assume it is an e-mail address. In this case, we
832 * just store away whatever it is they have typed.
834 * If the string had no @-sign, then we look in the Directory,
835 * make sure it exists, and if it does, we add that.
837 * If the string begins with a comma, then strip off the
838 * comma, and pass it along to the LDAP server. This is
839 * the way one can force ud to accept a name. Handy for
840 * debugging purposes.
844 mod.mod_type = attrlist[offset].quipu_name;
846 else if (strchr(s, '@') == NULL) {
847 if ((mp = find(s, FALSE)) == (LDAPMessage *) NULL) {
848 printf(" Could not find \"%s\"\n", s);
849 if (verbose && (mod.mod_op == LDAP_MOD_DELETE)){
851 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);
857 new_value = Entry.DN;
858 mod.mod_type = attrlist[offset].quipu_name;
860 else if (mod.mod_op != LDAP_MOD_DELETE) {
862 * Don't screw around with what the user has typed
863 * if they are simply trying to delete a rfc822mailbox
866 * spaces on the left hand side of the e-mail
867 * address are bad news - we know that there
868 * must be a @-sign in the string, or else we
871 * note that this means a value like:
873 * first m. last@host.domain
875 * will be turned into:
877 * first.m..last@host.domain
879 * and the mailer will need to do the right thing
880 * with this; alternatively we could add code that
881 * collapsed multiple dots into a single dot
883 * Don't screw up things like:
885 * "Bryan Beecher" <bryan@umich.edu>
886 * Bryan Beecher <bryan@umich.edu>
889 if (strchr(s, '<') == NULL) {
890 for (cp = s; *cp != '@'; cp++)
895 strcpy(attrtype, "rfc822");
896 strcat(attrtype, attrlist[offset].quipu_name);
897 mod.mod_type = attrtype;
901 strcpy(attrtype, "rfc822");
902 strcat(attrtype, attrlist[offset].quipu_name);
903 mod.mod_type = attrtype;
906 /* fill in the rest of the ldap_mod() structure */
908 mods[1] = (LDAPMod *) NULL;
910 values[0] = new_value;
912 mod.mod_values = values;
915 if (debug & D_GROUPS) {
916 register LDAPMod **lpp;
919 printf(" About to call ldap_modify_s()\n");
920 printf(" ld = 0x%x\n", ld);
921 printf(" dn = [%s]\n", group);
922 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
923 printf(" mods[%1d] code = %1d\n",
925 printf(" mods[%1d] type = %s\n",
926 i, (*lpp)->mod_type);
927 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
928 printf(" mods[%1d] v[%1d] = %s\n",
934 if (my_ldap_modify_s(ld, group, mods)) {
936 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
937 if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE) {
938 printf(" Could not locate value \"%s\"\n",
947 ldap_uncache_entry(ld, group);
950 * If the operation was REPLACE, we now need to "zero out" the
951 * other "half" of the list (e.g., user specified an e-mail
952 * address; now we need to clear the DN part of the list).
954 * NOTE: WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE.
956 * Also, change the opcode to LDAP_MOD_ADD and give the user an
957 * opportunity to add additional members to the group. We
958 * only take this branch the very first time during a REPLACE
961 if (mod.mod_op == LDAP_MOD_REPLACE) {
962 if (!strncmp(mod.mod_type, "rfc822", 6))
963 mod.mod_type = mod.mod_type + 6;
965 strcpy(attrtype, "rfc822");
966 strcat(attrtype, mod.mod_type);
967 mod.mod_type = attrtype;
971 mod.mod_values = values;
972 mod.mod_op = LDAP_MOD_DELETE;
974 if (debug & D_GROUPS) {
975 register LDAPMod **lpp;
978 printf(" About to call ldap_modify_s()\n");
979 printf(" ld = 0x%x\n", ld);
980 printf(" dn = [%s]\n", group);
981 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
982 printf(" mods[%1d] code = %1d\n",
984 printf(" mods[%1d] type = %s\n",
985 i, (*lpp)->mod_type);
986 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
987 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
991 if (my_ldap_modify_s(ld, group, mods)) {
993 * A "No such attribute" error is no big deal.
994 * We only wanted to clear the attribute anyhow.
997 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
998 if (ld_errno != LDAP_NO_SUCH_ATTRIBUTE) {
1003 ldap_uncache_entry(ld, group);
1005 printf(" \"%s\" has been added\n", new_value);
1006 mod.mod_op = LDAP_MOD_ADD;
1008 else if (verbose && (mod.mod_op == LDAP_MOD_ADD))
1009 printf(" \"%s\" has been added\n", new_value);
1010 else if (verbose && (mod.mod_op == LDAP_MOD_DELETE))
1011 printf(" \"%s\" has been removed\n", new_value);
1015 my_ldap_modify_s(ldap, group, mods)
1020 int was_rfc822member, rc;
1022 was_rfc822member = 0;
1024 if (!strcasecmp(mods[0]->mod_type, "rfc822member")) {
1025 mods[0]->mod_type = "mail";
1026 was_rfc822member = 1;
1029 rc = ldap_modify_s(ldap, group, mods);
1031 if (was_rfc822member)
1032 mods[0]->mod_type = "rfc822member";
1037 void list_groups(who)
1041 char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1042 char *work_area[MAX_NUM_NAMES];
1048 if (debug & D_TRACE) {
1050 printf("->list_groups(NULL)\n");
1052 printf("->list_groups(%s)\n", who);
1056 * First, decide what entry we are going to list. If the
1057 * user has not included a name on the list command line,
1058 * we will use the person who was last looked up with a find
1061 * Once we know who to modify, be sure that they exist, and
1062 * parse out their DN.
1065 printf(" List groups belonging to whose entry? ");
1067 fetch_buffer(name, sizeof(name), stdin);
1068 if (name[0] != '\0')
1073 if ((mp = find(who, TRUE)) == NULL) {
1074 (void) ldap_msgfree(mp);
1075 printf(" Could not locate \"%s\" in the Directory.\n", who);
1078 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1080 rdns = ldap_explode_dn(dn, TRUE);
1082 printf("\n Listing groups belonging to \"%s\"\n", *rdns);
1084 /* lookup the groups belonging to this person */
1085 sprintf(filter, "owner=%s", dn);
1087 search_attrs[0] = "cn";
1088 search_attrs[1] = NULL;
1089 if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE,
1090 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1091 rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1092 ldap_perror(ld, "ldap_search_s");
1093 ldap_value_free(rdns);
1096 if ((rc = ldap_count_entries(ld, mp)) < 0) {
1097 ldap_perror(ld, "ldap_count_entries");
1098 ldap_value_free(rdns);
1102 printf(" %s owns no groups in this portion of the Directory.\n", *rdns);
1103 ldap_value_free(rdns);
1107 printf(" %s owns %d groups.\n\n", *rdns, rc);
1108 print_list(mp, work_area, &rc);
1109 for (i = 1; work_area[i] != NULL; i++)
1112 ldap_value_free(rdns);
1116 static char * bind_and_fetch(name)
1120 char tmp[MED_BUF_SIZE];
1121 extern char * strip_ignore_chars();
1124 if (debug & D_TRACE) {
1126 printf("->bind_and_fetch(NULL)\n");
1128 printf("->bind_and_fetch(%s)\n", name);
1131 if (bind_status == UD_NOT_BOUND) {
1132 if (auth((char *) NULL, 1) < 0)
1137 * If the user did not supply us with a name, prompt them for
1140 if ((name == NULL) || (*name == '\0')) {
1143 fetch_buffer(tmp, sizeof(tmp), stdin);
1148 /* remove quotes, dots, and underscores. */
1149 name = strip_ignore_chars(name);
1152 if (debug & D_GROUPS)
1153 printf("Group name = (%s)\n", name);
1156 /* make sure the group in question exists and is joinable */
1157 if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) {
1158 printf(" Could not locate group \"%s\"\n", name);
1165 if (debug & D_GROUPS)
1166 printf("Group DN = (%s)\n", Entry.DN);
1168 return(strdup(Entry.DN));
1171 void list_memberships(who)
1175 char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1176 char *work_area[MAX_NUM_NAMES];
1182 if (debug & D_TRACE) {
1184 printf("->list_memberships(NULL)\n");
1186 printf("->list_memberships(%s)\n", who);
1190 * First, decide what entry we are going to list. If the
1191 * user has not included a name on the list command line,
1192 * we will use the person who was last looked up with a find
1195 * Once we know who to modify, be sure that they exist, and
1196 * parse out their DN.
1199 printf(" List memberships containing whose entry? ");
1201 fetch_buffer(name, sizeof(name), stdin);
1202 if (name[0] != '\0')
1207 if ((mp = find(who, TRUE)) == NULL) {
1208 (void) ldap_msgfree(mp);
1209 printf(" Could not locate \"%s\" in the Directory.\n", who);
1213 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1214 rdns = ldap_explode_dn(dn, TRUE);
1216 printf("\n Listing memberships of \"%s\"\n", *rdns);
1218 /* lookup the groups belonging to this person */
1219 sprintf(filter, "member=%s", dn);
1221 search_attrs[0] = "cn";
1222 search_attrs[1] = NULL;
1224 if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE,
1225 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1226 rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1227 ldap_perror(ld, "ldap_search_s");
1229 ldap_value_free(rdns);
1232 if ((rc = ldap_count_entries(ld, mp)) < 0) {
1233 ldap_perror(ld, "ldap_count_entries");
1235 ldap_value_free(rdns);
1239 printf(" %s is not a member of any groups in this portion of the Directory.\n", *rdns);
1241 ldap_value_free(rdns);
1245 printf(" %s is a member of %d groups.\n\n", *rdns, rc);
1248 * print_list fills in the char * array starting at 1, not 0
1250 print_list(mp, work_area, &rc);
1251 for (i = 1; work_area[i] != NULL; i++)
1254 ldap_value_free(rdns);