3 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1993, 1994 Regents of the University of Michigan.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that this notice is preserved and that due credit is given
12 * to the University of Michigan at Ann Arbor. The name of the University
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission. This software
15 * is provided ``as is'' without express or implied warranty.
23 #include <ac/string.h>
26 #include <ac/unistd.h>
35 #include "ldap_defaults.h"
38 static char * bind_and_fetch(char *name);
42 add_group( char *name )
44 int idx = 0, prompt = 0;
45 char tmp[BUFSIZ], dn[BUFSIZ];
46 static LDAPMod *attrs[9];
47 LDAPMod init_rdn, init_owner, init_domain,
48 init_errors, init_request, init_joinable;
49 char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2],
50 *init_errors_value[MAX_VALUES], *init_joinable_value[2],
51 *init_request_value[MAX_VALUES];
54 if (debug & D_TRACE) {
56 printf("->add_group(NULL)\n");
58 printf("->add_group(%s)\n", name);
62 if (bind_status == UD_NOT_BOUND) {
63 if (auth((char *) NULL, 1) < 0) {
69 * If the user did not supply us with a name, prompt them for
72 if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) {
74 printf(" Group to create? ");
76 fetch_buffer(tmp, sizeof(tmp), stdin);
82 /* remove quotes, dots, and underscores. */
83 name = strip_ignore_chars(name);
86 if (isauniqname(name)) {
87 printf(" '%s' could be confused with a U-M uniqname.\n", name);
88 printf(" You can create the group, but you need to make sure that\n");
89 printf(" you reserve the uniqname for use as your groupname\n\n");
90 printf(" Are you sure that you want to do this? ");
92 fetch_buffer(tmp, sizeof(tmp), stdin);
93 if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
95 printf("\n Be sure to contact your uniqname administrator to reserve\n");
96 printf(" the uniqname '%s' for use as your group name.\n", name);
99 sprintf(dn, "cn=%s, %s", name, group_base);
102 * Make sure that this group does not already exist.
104 if (vrfy(dn) == TRUE) {
105 printf(" The group \"%s\" already exists.\n", name);
110 * Take the easy way out: Fill in some reasonable values for
111 * the most important fields, and make the user use the modify
112 * command to change them, or to give values to other fields.
114 init_rdn_value[0] = name;
115 init_rdn_value[1] = NULL;
116 init_rdn.mod_op = LDAP_MOD_ADD;
117 init_rdn.mod_type = "cn";
118 init_rdn.mod_values = init_rdn_value;
119 attrs[idx++] = &init_rdn;
121 init_owner_value[0] = bound_dn;
122 init_owner_value[1] = NULL;
123 init_owner.mod_op = LDAP_MOD_ADD;
124 init_owner.mod_type = "owner";
125 init_owner.mod_values = init_owner_value;
126 attrs[idx++] = &init_owner;
129 init_domain_value[0] = "umich.edu";
131 init_domain_value[0] = ".";
133 init_domain_value[1] = NULL;
134 init_domain.mod_op = LDAP_MOD_ADD;
135 init_domain.mod_type = "associatedDomain";
136 init_domain.mod_values = init_domain_value;
137 attrs[idx++] = &init_domain;
139 init_errors_value[0] = bound_dn;
140 init_errors_value[1] = NULL;
141 init_errors.mod_op = LDAP_MOD_ADD;
142 init_errors.mod_type = "ErrorsTo";
143 init_errors.mod_values = init_errors_value;
144 attrs[idx++] = &init_errors;
146 init_request_value[0] = bound_dn;
147 init_request_value[1] = NULL;
148 init_request.mod_op = LDAP_MOD_ADD;
149 init_request.mod_type = "RequestsTo";
150 init_request.mod_values = init_request_value;
151 attrs[idx++] = &init_request;
153 init_joinable_value[0] = "FALSE";
154 init_joinable_value[1] = NULL;
155 init_joinable.mod_op = LDAP_MOD_ADD;
156 init_joinable.mod_type = "joinable";
157 init_joinable.mod_values = init_joinable_value;
158 attrs[idx++] = &init_joinable;
160 /* end it with a NULL */
164 if (debug & D_GROUPS) {
168 printf(" About to call ldap_add()\n");
169 printf(" ld = 0x%x\n", ld);
170 printf(" dn = [%s]\n", dn);
171 for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) {
172 printf(" attrs[%1d] code = %s type = %s\n", i,
173 code_to_str((*lpp)->mod_op), (*lpp)->mod_type);
174 for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++)
175 printf(" value #%1d = %s\n", j, *cpp);
176 printf(" value #%1d = NULL\n", j);
182 * Now add this to the LDAP Directory.
184 if (ldap_add_s(ld, dn, attrs) != 0) {
185 ldap_perror(ld, " ldap_add_s");
186 printf(" Group not added.\n");
187 if (prompt) Free(name);
191 printf(" Group \"%s\" has been added to the Directory\n",
195 * We need to blow away the cache here.
197 * Since we first looked up the name before trying to create it,
198 * and that look-up failed, the cache will falsely claim that this
199 * entry does not exist.
201 (void) ldap_flush_cache(ld);
202 if (prompt) Free(name);
207 remove_group( char *name )
209 char *dn, tmp[BUFSIZ];
212 if (debug & D_TRACE) {
214 printf("->remove_group(NULL)\n");
216 printf("->remove_group(%s)\n", name);
219 if ((dn = bind_and_fetch(name)) == NULL)
222 printf("\n The entry\n '%s'\n will be permanently removed from", dn);
223 printf(" the Directory.\n Are you absolutely sure that you want to" );
224 printf(" remove this entire group? ");
226 fetch_buffer(tmp, sizeof(tmp), stdin);
227 if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
231 * Now remove this from the LDAP Directory.
233 if (ldap_delete_s(ld, dn) != 0) {
235 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
236 if (ld_errno == LDAP_INSUFFICIENT_ACCESS)
237 printf(" You do not own the entry\n\t\"%s\".\n", dn);
239 ldap_perror(ld, " ldap_delete_s");
240 printf(" Group not removed.\n");
244 ldap_uncache_entry(ld, dn);
248 printf(" The group has been removed.\n");
250 printf(" The group \"%s\" has been removed.\n", name);
257 x_group( int action, char *name )
260 char *values[2], *group_name;
261 LDAPMod mod, *mods[2];
262 static char *actions[] = { "join", "resign from", NULL };
265 if (debug & D_TRACE) {
267 printf("->x_group(%d, NULL)\n", action);
269 printf("->x_group(%d, %s)\n", action, name);
273 /* the action desired sets the opcode to use */
276 mod.mod_op = LDAP_MOD_ADD;
279 mod.mod_op = LDAP_MOD_DELETE;
282 printf("x_group: %d is not a known action\n", action);
285 if ((group_name = bind_and_fetch(name)) == NULL)
287 vp = Entry.attrs[attr_to_index("joinable")].values;
288 if (action == G_JOIN) {
290 printf(" No one is permitted to join \"%s\"\n", group_name);
294 if (!strcasecmp(*vp, "FALSE")) {
295 printf(" No one is permitted to join \"%s\"\n", group_name);
301 /* fill in the rest of the modification structure */
303 mods[1] = (LDAPMod *) NULL;
304 values[0] = Entry.DN;
306 mod.mod_type = "memberOfGroup";
307 mod.mod_values = values;
310 if (debug & D_GROUPS) {
311 register LDAPMod **lpp;
314 printf(" About to call ldap_modify_s()\n");
315 printf(" ld = 0x%x\n", ld);
316 printf(" dn = [%s]\n", bound_dn);
317 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
318 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
319 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
320 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
321 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
327 if (ldap_modify_s(ld, bound_dn, mods)) {
329 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
330 if ((action == G_JOIN) && (ld_errno == LDAP_TYPE_OR_VALUE_EXISTS))
331 printf(" You are already subscribed to \"%s\"\n", group_name);
332 else if ((action == G_RESIGN) && (ld_errno == LDAP_NO_SUCH_ATTRIBUTE))
333 printf(" You are not subscribed to \"%s\"\n", group_name);
339 ldap_uncache_entry(ld, bound_dn);
343 printf(" You are now subscribed to \"%s\"\n", group_name);
346 printf(" You are no longer subscribed to \"%s\"\n", group_name);
355 bulk_load( char *group )
357 register int idx_mail, idx_x500;
358 register int count_mail, count_x500;
359 char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1];
360 int added_mail_entries = FALSE, added_x500_entries = FALSE;
361 char s[MED_BUF_SIZE];
362 LDAPMod mod, *mods[2];
369 printf("->bulk_load(%s)\n", group);
372 /* you lose if going through MichNet */
375 printf(" Not allowed via UM-X500 connections.\n");
380 /* fetch entries from the file containing the e-mail addresses */
381 printf("\n File to load? ");
383 fetch_buffer(s, sizeof(s), stdin);
388 if ((fp = fopen(s, "r")) == NULL) {
389 perror("bulk_load: fopen");
393 printf(" Loading group members from %s\n", s);
395 /* load them in MAX_VALUES at a time */
397 for (idx_mail = 0, idx_x500 = 0;
398 idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) {
399 (void) fgets(s, sizeof(s), fp);
407 values_mail[idx_mail++] = strdup(s);
409 if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) {
410 printf(" Could not locate \"%s\" -- skipping.\n", s);
414 values_x500[idx_x500++] = strdup(Entry.DN);
418 values_mail[idx_mail] = NULL;
419 values_x500[idx_x500] = NULL;
420 count_mail = idx_mail;
421 count_x500 = idx_x500;
424 * Add the e-mail addresses.
426 if (count_mail > 0) {
428 mods[1] = (LDAPMod *) NULL;
429 mod.mod_type = "mail";
430 mod.mod_values = values_mail;
431 if (added_mail_entries)
432 mod.mod_op = LDAP_MOD_ADD;
434 mod.mod_op = LDAP_MOD_REPLACE;
437 if (debug & D_GROUPS) {
438 register LDAPMod **lpp;
441 printf(" About to call ldap_modify_s()\n");
442 printf(" ld = 0x%x\n", ld);
443 printf(" dn = [%s]\n", group);
444 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
445 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
446 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
447 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
448 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
452 if (ldap_modify_s(ld, group, mods))
454 for (idx_mail--; idx_mail >= 0; idx_mail--)
455 Free(values_mail[idx_mail]);
456 ldap_uncache_entry(ld, group);
457 added_mail_entries = TRUE;
462 * Add the LDAP style names.
464 if (count_x500 > 0) {
466 mods[1] = (LDAPMod *) NULL;
467 mod.mod_type = "member";
468 mod.mod_values = values_x500;
469 if (added_x500_entries)
470 mod.mod_op = LDAP_MOD_ADD;
472 mod.mod_op = LDAP_MOD_REPLACE;
475 if (debug & D_GROUPS) {
476 register LDAPMod **lpp;
479 printf(" About to call ldap_modify_s()\n");
480 printf(" ld = 0x%x\n", ld);
481 printf(" dn = [%s]\n", group);
482 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
483 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
484 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
485 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
486 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
490 if (ldap_modify_s(ld, group, mods))
492 for (idx_x500--; idx_x500 >= 0; idx_x500--)
493 Free(values_x500[idx_x500]);
494 ldap_uncache_entry(ld, group);
495 added_x500_entries = TRUE;
500 * If both counts were less than the maximum number we
501 * can handle at a time, then we are done.
503 if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES))
511 purge_group( char *group )
515 LDAPMod mod, *mods[2];
516 char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns;
519 if (debug & D_TRACE) {
521 printf("->purge_group(NULL)\n");
523 printf("->purge_group(%s)\n", group);
526 if (bind_status == UD_NOT_BOUND) {
527 if (auth((char *) NULL, 1) < 0)
531 * If the user did not supply us with a name, prompt them for
534 if ((group == NULL) || (*group == '\0')) {
535 printf("Group to purge? ");
537 fetch_buffer(tmp, sizeof(tmp), stdin);
542 sprintf(dn, "cn=%s, %s", group, group_base);
544 /* make sure the group in question exists */
545 if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) {
546 printf(" Could not locate group \"%s\"\n", group);
552 /* none of this stuff changes */
554 mods[1] = (LDAPMod *) NULL;
558 mod.mod_values = values;
559 mod.mod_type = "member";
560 mod.mod_op = LDAP_MOD_DELETE;
563 * Now cycle through all of the names in the "members" part of the
564 * group (but not the e-mail address part). Lookup each one, and
565 * if it isn't found, let the user know so s/he can delete it.
567 vp = Entry.attrs[attr_to_index("member")].values;
570 printf(" \"%s\" has no LDAP members. There is nothing to purge.\n", group);
573 for (; *vp != NULL; vp++) {
574 char ans[BUFSIZ], *ufn, *label = "Did not find: ";
575 int len = strlen(label);
580 ufn = my_ldap_dn2ufn(*vp);
581 format2(ufn, label, (char *) NULL, 2, 2 + len, col_size);
583 printf(" Purge, Keep, Replace, Abort [Keep]? ");
585 fetch_buffer(ans, sizeof(ans), stdin);
586 if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans)))
588 if (!strncasecmp(ans, "Abort", strlen(ans))) {
589 ldap_uncache_entry(ld, dn);
592 if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) {
595 if (debug & D_GROUPS) {
596 register LDAPMod **lpp;
599 printf(" About to call ldap_modify_s()\n");
600 printf(" ld = 0x%x\n", ld);
601 printf(" dn = [%s]\n", Entry.DN);
602 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
603 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
604 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
605 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
606 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
611 if (ldap_modify_s(ld, Entry.DN, mods))
614 /* now add the replacement if requested */
615 if (!strncasecmp(ans, "Purge", strlen(ans)))
617 rdns = ldap_explode_dn(*vp, TRUE);
618 if ((lm = find(*rdns, FALSE)) == NULL) {
619 printf(" Could not find a replacement for %s; purged only.\n", *rdns);
621 ldap_value_free(rdns);
624 values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm));
625 mod.mod_op = LDAP_MOD_ADD;
627 if (debug & D_GROUPS) {
628 register LDAPMod **lpp;
631 printf(" About to call ldap_modify_s()\n");
632 printf(" ld = 0x%x\n", ld);
633 printf(" dn = [%s]\n", Entry.DN);
634 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
635 printf(" mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
636 printf(" mods[%1d] type = %s\n", i, (*lpp)->mod_type);
637 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
638 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
643 if (ldap_modify_s(ld, Entry.DN, mods))
646 ldap_value_free(rdns);
648 /* set this back to DELETE for other purges */
649 mod.mod_op = LDAP_MOD_DELETE;
652 printf(" Did not recognize that answer.\n\n");
656 ldap_uncache_entry(ld, Entry.DN);
658 printf(" No entries were purged.\n");
670 static LDAPMod *mods[2] = { &mod, NULL };
671 static char *values[MAX_VALUES];
675 printf("->tidy()\n");
678 if (bind_status == UD_NOT_BOUND) {
679 if (auth((char *) NULL, 1) < 0) {
684 /* lookup the user, and see to which groups he has subscribed */
685 vp = ldap_explode_dn(bound_dn, TRUE);
686 if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) {
687 printf(" Could not locate \"%s\"\n", *vp);
694 vp = Entry.attrs[attr_to_index("memberOfGroup")].values;
696 printf(" You have not subscribed to any groups.\n");
700 /* now, loop through these groups, deleting the bogus */
701 for ( ; *vp != NULL; vp++) {
705 printf(" \"%s\" is not a valid group name.\n", *vp);
706 values[i++] = strdup(*vp);
707 if ( i >= MAX_VALUES ) {
708 printf( " At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES );
712 if (found_one == 0) {
714 printf(" You are not a member of any invalid groups. There is nothing to tidy.\n");
718 /* delete the most heinous entries */
720 mod.mod_values = values;
721 mod.mod_op = LDAP_MOD_DELETE;
722 mod.mod_type = "memberOfGroup";
723 if (ldap_modify_s(ld, bound_dn, mods))
725 ldap_uncache_entry(ld, bound_dn);
727 /* tidy up before we finish tidy_up */
734 * This routine is used to modify lists that can contain either Distinguished
735 * Names or e-mail addresses. This includes things like group members,
736 * the errors-to field in groups, and so on.
739 mod_addrDN( char *group, int offset )
741 char s[BUFSIZ], *new_value /* was member */, *values[2];
743 LDAPMod mod, *mods[2];
748 printf("->mod_addrDN(%s)\n", group);
751 * At this point the user can indicate that he wishes to add values
752 * to the attribute, delete values from the attribute, or replace the
753 * current list of values with a new list. The first two cases
754 * are very straight-forward, but the last case requires a little
755 * extra care and work.
760 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);
762 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);
765 /* initialize the modififier type */
770 printf(" Do you want to Add, Delete, or Replace? ");
772 printf(" Do you want to Add, Delete, Replace, or Bulk load? ");
774 fetch_buffer(s, sizeof(s), stdin);
779 if (!strncasecmp(s, "add", strlen(s))) {
780 mod.mod_op = LDAP_MOD_ADD;
783 else if (!strncasecmp(s, "delete", strlen(s))) {
784 mod.mod_op = LDAP_MOD_DELETE;
787 else if (!strncasecmp(s, "replace", strlen(s))) {
788 mod.mod_op = LDAP_MOD_REPLACE;
791 else if(!strncasecmp(s, "bulk", strlen(s))) {
798 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);
800 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);
803 if (mod.mod_op == LDAP_MOD_REPLACE) {
804 if ( verbose && !confirm_action( "The entire existing list will be overwritten with the new values you are about to enter." )) {
805 printf("\n Modification halted.\n");
811 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);
816 printf("%s? ", attrlist[offset].output_string);
818 fetch_buffer(s, sizeof(s), stdin);
823 * If the string the user has just typed has an @-sign in it,
824 * then we assume it is an e-mail address. In this case, we
825 * just store away whatever it is they have typed.
827 * If the string had no @-sign, then we look in the Directory,
828 * make sure it exists, and if it does, we add that.
830 * If the string begins with a comma, then strip off the
831 * comma, and pass it along to the LDAP server. This is
832 * the way one can force ud to accept a name. Handy for
833 * debugging purposes.
837 mod.mod_type = attrlist[offset].quipu_name;
839 else if (strchr(s, '@') == NULL) {
840 if ((mp = find(s, FALSE)) == (LDAPMessage *) NULL) {
841 printf(" Could not find \"%s\"\n", s);
842 if (verbose && (mod.mod_op == LDAP_MOD_DELETE)){
844 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);
850 new_value = Entry.DN;
851 mod.mod_type = attrlist[offset].quipu_name;
853 else if (mod.mod_op != LDAP_MOD_DELETE) {
855 * Don't screw around with what the user has typed
856 * if they are simply trying to delete a rfc822mailbox
859 * spaces on the left hand side of the e-mail
860 * address are bad news - we know that there
861 * must be a @-sign in the string, or else we
864 * note that this means a value like:
866 * first m. last@host.domain
868 * will be turned into:
870 * first.m..last@host.domain
872 * and the mailer will need to do the right thing
873 * with this; alternatively we could add code that
874 * collapsed multiple dots into a single dot
876 * Don't screw up things like:
878 * "Bryan Beecher" <bryan@umich.edu>
879 * Bryan Beecher <bryan@umich.edu>
882 if (strchr(s, '<') == NULL) {
883 for (cp = s; *cp != '@'; cp++)
884 if (isspace((unsigned char)*cp))
888 strcpy(attrtype, "rfc822");
889 strcat(attrtype, attrlist[offset].quipu_name);
890 mod.mod_type = attrtype;
894 strcpy(attrtype, "rfc822");
895 strcat(attrtype, attrlist[offset].quipu_name);
896 mod.mod_type = attrtype;
899 /* fill in the rest of the ldap_mod() structure */
901 mods[1] = (LDAPMod *) NULL;
903 values[0] = new_value;
905 mod.mod_values = values;
908 if (debug & D_GROUPS) {
912 printf(" About to call ldap_modify_s()\n");
913 printf(" ld = 0x%x\n", ld);
914 printf(" dn = [%s]\n", group);
915 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
916 printf(" mods[%1d] code = %1d\n",
918 printf(" mods[%1d] type = %s\n",
919 i, (*lpp)->mod_type);
920 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
921 printf(" mods[%1d] v[%1d] = %s\n",
927 if (my_ldap_modify_s(ld, group, mods)) {
929 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
930 if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE) {
931 printf(" Could not locate value \"%s\"\n",
940 ldap_uncache_entry(ld, group);
943 * If the operation was REPLACE, we now need to "zero out" the
944 * other "half" of the list (e.g., user specified an e-mail
945 * address; now we need to clear the DN part of the list).
947 * NOTE: WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE.
949 * Also, change the opcode to LDAP_MOD_ADD and give the user an
950 * opportunity to add additional members to the group. We
951 * only take this branch the very first time during a REPLACE
954 if (mod.mod_op == LDAP_MOD_REPLACE) {
955 if (!strncmp(mod.mod_type, "rfc822", 6))
956 mod.mod_type = mod.mod_type + 6;
958 strcpy(attrtype, "rfc822");
959 strcat(attrtype, mod.mod_type);
960 mod.mod_type = attrtype;
964 mod.mod_values = values;
965 mod.mod_op = LDAP_MOD_DELETE;
967 if (debug & D_GROUPS) {
971 printf(" About to call ldap_modify_s()\n");
972 printf(" ld = 0x%x\n", ld);
973 printf(" dn = [%s]\n", group);
974 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
975 printf(" mods[%1d] code = %1d\n",
977 printf(" mods[%1d] type = %s\n",
978 i, (*lpp)->mod_type);
979 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
980 printf(" mods[%1d] v[%1d] = %s\n", i, j, *cp);
984 if (my_ldap_modify_s(ld, group, mods)) {
986 * A "No such attribute" error is no big deal.
987 * We only wanted to clear the attribute anyhow.
990 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
991 if (ld_errno != LDAP_NO_SUCH_ATTRIBUTE) {
996 ldap_uncache_entry(ld, group);
998 printf(" \"%s\" has been added\n", new_value);
999 mod.mod_op = LDAP_MOD_ADD;
1001 else if (verbose && (mod.mod_op == LDAP_MOD_ADD))
1002 printf(" \"%s\" has been added\n", new_value);
1003 else if (verbose && (mod.mod_op == LDAP_MOD_DELETE))
1004 printf(" \"%s\" has been removed\n", new_value);
1009 my_ldap_modify_s( LDAP *ldap, char *group, LDAPMod **mods )
1011 int was_rfc822member, rc;
1013 was_rfc822member = 0;
1015 if (!strcasecmp(mods[0]->mod_type, "rfc822member")) {
1016 mods[0]->mod_type = "mail";
1017 was_rfc822member = 1;
1020 rc = ldap_modify_s(ldap, group, mods);
1022 if (was_rfc822member)
1023 mods[0]->mod_type = "rfc822member";
1029 list_groups( char *who )
1032 char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1033 char *work_area[MAX_NUM_NAMES];
1039 if (debug & D_TRACE) {
1041 printf("->list_groups(NULL)\n");
1043 printf("->list_groups(%s)\n", who);
1047 * First, decide what entry we are going to list. If the
1048 * user has not included a name on the list command line,
1049 * we will use the person who was last looked up with a find
1052 * Once we know who to modify, be sure that they exist, and
1053 * parse out their DN.
1056 printf(" List groups belonging to whose entry? ");
1058 fetch_buffer(name, sizeof(name), stdin);
1059 if (name[0] != '\0')
1064 if ((mp = find(who, TRUE)) == NULL) {
1065 (void) ldap_msgfree(mp);
1066 printf(" Could not locate \"%s\" in the Directory.\n", who);
1069 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1071 rdns = ldap_explode_dn(dn, TRUE);
1073 printf("\n Listing groups belonging to \"%s\"\n", *rdns);
1075 /* lookup the groups belonging to this person */
1076 sprintf(filter, "owner=%s", dn);
1078 search_attrs[0] = "cn";
1079 search_attrs[1] = NULL;
1080 if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE,
1081 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1082 rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1083 ldap_perror(ld, "ldap_search_s");
1084 ldap_value_free(rdns);
1087 if ((rc = ldap_count_entries(ld, mp)) < 0) {
1088 ldap_perror(ld, "ldap_count_entries");
1089 ldap_value_free(rdns);
1093 printf(" %s owns no groups in this portion of the Directory.\n", *rdns);
1094 ldap_value_free(rdns);
1098 printf(" %s owns %d groups.\n\n", *rdns, rc);
1099 print_list(mp, work_area, &rc);
1100 for (i = 1; work_area[i] != NULL; i++)
1103 ldap_value_free(rdns);
1108 bind_and_fetch( char *name )
1111 char tmp[MED_BUF_SIZE];
1114 if (debug & D_TRACE) {
1116 printf("->bind_and_fetch(NULL)\n");
1118 printf("->bind_and_fetch(%s)\n", name);
1121 if (bind_status == UD_NOT_BOUND) {
1122 if (auth((char *) NULL, 1) < 0)
1127 * If the user did not supply us with a name, prompt them for
1130 if ((name == NULL) || (*name == '\0')) {
1133 fetch_buffer(tmp, sizeof(tmp), stdin);
1138 /* remove quotes, dots, and underscores. */
1139 name = strip_ignore_chars(name);
1142 if (debug & D_GROUPS)
1143 printf("Group name = (%s)\n", name);
1146 /* make sure the group in question exists and is joinable */
1147 if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) {
1148 printf(" Could not locate group \"%s\"\n", name);
1155 if (debug & D_GROUPS)
1156 printf("Group DN = (%s)\n", Entry.DN);
1158 return(strdup(Entry.DN));
1162 list_memberships( char *who )
1165 char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1166 char *work_area[MAX_NUM_NAMES];
1172 if (debug & D_TRACE) {
1174 printf("->list_memberships(NULL)\n");
1176 printf("->list_memberships(%s)\n", who);
1180 * First, decide what entry we are going to list. If the
1181 * user has not included a name on the list command line,
1182 * we will use the person who was last looked up with a find
1185 * Once we know who to modify, be sure that they exist, and
1186 * parse out their DN.
1189 printf(" List memberships containing whose entry? ");
1191 fetch_buffer(name, sizeof(name), stdin);
1192 if (name[0] != '\0')
1197 if ((mp = find(who, TRUE)) == NULL) {
1198 (void) ldap_msgfree(mp);
1199 printf(" Could not locate \"%s\" in the Directory.\n", who);
1203 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1204 rdns = ldap_explode_dn(dn, TRUE);
1206 printf("\n Listing memberships of \"%s\"\n", *rdns);
1208 /* lookup the groups belonging to this person */
1209 sprintf(filter, "member=%s", dn);
1211 search_attrs[0] = "cn";
1212 search_attrs[1] = NULL;
1214 if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE,
1215 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1216 rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1217 ldap_perror(ld, "ldap_search_s");
1219 ldap_value_free(rdns);
1222 if ((rc = ldap_count_entries(ld, mp)) < 0) {
1223 ldap_perror(ld, "ldap_count_entries");
1225 ldap_value_free(rdns);
1229 printf(" %s is not a member of any groups in this portion of the Directory.\n", *rdns);
1231 ldap_value_free(rdns);
1235 printf(" %s is a member of %d groups.\n\n", *rdns, rc);
1238 * print_list fills in the char * array starting at 1, not 0
1240 print_list(mp, work_area, &rc);
1241 for (i = 1; work_area[i] != NULL; i++)
1244 ldap_value_free(rdns);