]> git.sur5r.net Git - openldap/blob - clients/ud/group.c
Fixed ldapconfig.h.edit/Make-template to generate ldapconfig.h correctly.
[openldap] / clients / ud / group.c
1 /*
2  * Copyright (c) 1993, 1994  Regents of the University of Michigan.
3  * All rights reserved.
4  *
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.
11  *
12  */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <time.h>
17
18 #include <lber.h>
19 #include <ldap.h>
20
21 #include <ldapconfig.h>
22 #include "ud.h"
23
24 extern LDAPMessage * find();
25
26 #ifdef DEBUG
27 extern int debug;
28 #endif
29
30 extern char *bound_dn, *group_base;
31 extern int verbose, bind_status;
32 extern struct entry Entry;
33 extern LDAP *ld;
34
35 extern void Free();
36
37 void add_group(name)
38 char *name;
39 {
40         register int i, idx = 0, prompt = 0;
41         char tmp[BUFSIZ], dn[BUFSIZ];
42         static LDAPMod *attrs[9];
43         LDAPMod init_rdn,    init_owner,   init_domain,
44                 init_errors, init_request, init_joinable;
45         char *init_rdn_value[2], *init_owner_value[2], *init_domain_value[2],
46                 *init_errors_value[MAX_VALUES], *init_joinable_value[2],
47                 *init_request_value[MAX_VALUES];
48         extern void ldap_flush_cache();
49         extern char * strip_ignore_chars();
50
51 #ifdef DEBUG
52         if (debug & D_TRACE) {
53                 if (name == NULL)
54                         printf("->add_group(NULL)\n");
55                 else
56                         printf("->add_group(%s)\n", name);
57         }
58 #endif
59
60         if (bind_status == UD_NOT_BOUND) {
61                 if (auth((char *) NULL, 1) < 0) {
62                         return;
63                 }
64         }
65
66         /*
67          *  If the user did not supply us with a name, prompt them for
68          *  a name.
69          */
70         if ((name == NULL) || (*name == '\0') || !strcasecmp(name, "group")) {
71                 ++prompt;
72                 printf("  Group to create? ");
73                 fflush(stdout);
74                 fetch_buffer(tmp, sizeof(tmp), stdin);
75                 if (tmp[0] == '\0')
76                         return;
77                 name = strdup(tmp);
78         }
79
80         /* remove quotes, dots, and underscores. */
81         name = strip_ignore_chars(name);
82
83 #ifdef UOFM
84         if (isauniqname(name)) {
85                 printf(" '%s' could be confused with a U-M uniqname.\n", name);
86                 printf(" You can create the group, but you need to make sure that\n");
87                 printf(" you reserve the uniqname for use as your groupname\n\n");
88                 printf(" Are you sure that you want to do this? ");
89                 fflush(stdout);
90                 fetch_buffer(tmp, sizeof(tmp), stdin);
91                 if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
92                         return;
93                 printf("\n Be sure to contact your uniqname administrator to reserve\n");
94                 printf(" the uniqname '%s' for use as your group name.\n", name);
95         }
96 #endif
97         sprintf(dn, "cn=%s, %s", name, group_base);
98
99         /*
100          *  Make sure that this group does not already exist.
101          */
102         if (vrfy(dn) == TRUE) {
103                 printf("  The group \"%s\" already exists.\n", name);
104                 return;
105         }
106
107         /*
108          *  Take the easy way out:  Fill in some reasonable values for
109          *  the most important fields, and make the user use the modify
110          *  command to change them, or to give values to other fields.
111          */
112         init_rdn_value[0] = name;
113         init_rdn_value[1] = NULL;
114         init_rdn.mod_op = LDAP_MOD_ADD;
115         init_rdn.mod_type = "cn";
116         init_rdn.mod_values = init_rdn_value;
117         attrs[idx++] = &init_rdn;
118
119         init_owner_value[0] = bound_dn;
120         init_owner_value[1] = NULL;
121         init_owner.mod_op = LDAP_MOD_ADD;
122         init_owner.mod_type = "owner";
123         init_owner.mod_values = init_owner_value;
124         attrs[idx++] = &init_owner;
125
126 #ifdef UOFM
127         init_domain_value[0] = "umich.edu";
128 #else
129         init_domain_value[0] = ".";
130 #endif
131         init_domain_value[1] = NULL;
132         init_domain.mod_op = LDAP_MOD_ADD;
133         init_domain.mod_type = "associatedDomain";
134         init_domain.mod_values = init_domain_value;
135         attrs[idx++] = &init_domain;
136
137         init_errors_value[0] = bound_dn;
138         init_errors_value[1] = NULL;
139         init_errors.mod_op = LDAP_MOD_ADD;
140         init_errors.mod_type = "ErrorsTo";
141         init_errors.mod_values = init_errors_value;
142         attrs[idx++] = &init_errors;
143
144         init_request_value[0] = bound_dn;
145         init_request_value[1] = NULL;
146         init_request.mod_op = LDAP_MOD_ADD;
147         init_request.mod_type = "RequestsTo";
148         init_request.mod_values = init_request_value;
149         attrs[idx++] = &init_request;
150
151         init_joinable_value[0] = "FALSE";
152         init_joinable_value[1] = NULL;
153         init_joinable.mod_op = LDAP_MOD_ADD;
154         init_joinable.mod_type = "joinable";
155         init_joinable.mod_values = init_joinable_value;
156         attrs[idx++] = &init_joinable;
157
158         /* end it with a NULL */
159         attrs[idx] = NULL;
160
161 #ifdef DEBUG
162         if (debug & D_GROUPS) {
163                 register LDAPMod **lpp;
164                 register char **cpp;
165                 register int j;
166                 extern char * code_to_str();
167                 printf("  About to call ldap_add()\n");
168                 printf("  ld = 0x%x\n", ld);
169                 printf("  dn = [%s]\n", dn);
170                 for (lpp = attrs, i = 0; *lpp != NULL; lpp++, i++) {
171                         printf("  attrs[%1d]  code = %s  type = %s\n", i, 
172                                 code_to_str((*lpp)->mod_op), (*lpp)->mod_type);
173                         for (cpp = (*lpp)->mod_values, j = 0; *cpp != NULL; cpp++, j++)
174                                 printf("    value #%1d = %s\n", j, *cpp);
175                         printf("    value #%1d = NULL\n", j);
176                 }
177         }
178 #endif
179
180         /*
181          *  Now add this to the X.500 Directory.
182          */
183         if (ldap_add_s(ld, dn, attrs) != 0) {
184                 ldap_perror(ld, "  ldap_add_s");
185                 printf("  Group not added.\n");
186                 if (prompt) Free(name);
187                 return;
188         }
189         if (verbose)
190                 printf("  Group \"%s\" has been added to the Directory\n",
191                        name);
192
193         /*
194          *  We need to blow away the cache here.
195          *
196          *  Since we first looked up the name before trying to create it,
197          *  and that look-up failed, the cache will falsely claim that this
198          *  entry does not exist.
199          */
200         (void) ldap_flush_cache(ld);
201         if (prompt) Free(name);
202         return;
203 }
204
205 void remove_group(name)
206 char *name;
207 {
208         char *dn, tmp[BUFSIZ];
209         static char * bind_and_fetch();
210
211 #ifdef DEBUG
212         if (debug & D_TRACE) {
213                 if (name == NULL)
214                         printf("->remove_group(NULL)\n");
215                 else
216                         printf("->remove_group(%s)\n", name);
217         }
218 #endif
219         if ((dn = bind_and_fetch(name)) == NULL)
220                 return;
221
222         printf("\n  The group '%s' will be permanently removed from\n",
223                 name);
224         printf("  the Directory.  Are you absolutely sure that you want to\n" );        printf("  remove this entire group? ");
225         fflush(stdout);
226         fetch_buffer(tmp, sizeof(tmp), stdin);
227         if (!(tmp[0] == 'y' || tmp[0] == 'Y'))
228                 return;
229
230         /*
231          *  Now remove this from the X.500 Directory.
232          */
233         if (ldap_delete_s(ld, dn) != 0) {
234                 if (ld->ld_errno == LDAP_INSUFFICIENT_ACCESS)
235                         printf("  You do not own the group \"%s\".\n", name);
236                 else
237                         ldap_perror(ld, "  ldap_delete_s");
238                 printf("  Group not removed.\n");
239                 Free(dn);
240                 return;
241         }
242         ldap_uncache_entry(ld, dn);
243         if (verbose)
244             if (name == NULL)
245                 printf("  The group has been removed.\n");
246             else
247                 printf("  The group \"%s\" has been removed.\n", name);
248         Free(dn);
249         return;
250 }
251
252 void x_group(action, name)
253 int action;
254 char *name;
255 {
256         char **vp;
257         char *values[2], *group_name;
258         LDAPMod mod, *mods[2];
259         static char *actions[] = { "join", "resign from", NULL };
260         static char * bind_and_fetch();
261
262 #ifdef DEBUG
263         if (debug & D_TRACE) {
264                 if (name == NULL)
265                         printf("->x_group(%d, NULL)\n", action);
266                 else
267                         printf("->x_group(%d, %s)\n", action, name);
268         }
269 #endif
270
271         /* the action desired sets the opcode to use */
272         switch (action) {
273         case G_JOIN:
274                 mod.mod_op = LDAP_MOD_ADD;
275                 break;
276         case G_RESIGN:
277                 mod.mod_op = LDAP_MOD_DELETE;
278                 break;
279         default:
280                 printf("x_group:  %d is not a known action\n", action);
281         }
282
283         if ((group_name = bind_and_fetch(name)) == NULL)
284                 return;
285         vp = Entry.attrs[attr_to_index("joinable")].values;
286         if (action == G_JOIN) {
287                 if (vp == NULL) {
288                         printf("  No one is permitted to join \"%s\"\n", group_name);
289                         Free(group_name);
290                         return;
291                 }
292                 if (!strcasecmp(*vp, "FALSE")) {
293                         printf("  No one is permitted to join \"%s\"\n", group_name);
294                         Free(group_name);
295                         return;
296                 }
297         }
298
299         /*  fill in the rest of the modification structure */
300         mods[0] = &mod;
301         mods[1] = (LDAPMod *) NULL;
302         values[0] = Entry.DN;
303         values[1] = NULL;
304         mod.mod_type = "memberOfGroup";
305         mod.mod_values = values;
306
307 #ifdef DEBUG
308         if (debug & D_GROUPS) {
309                 register LDAPMod **lpp;
310                 register char **cp;
311                 register int i, j;
312                 printf("  About to call ldap_modify_s()\n");
313                 printf("  ld = 0x%x\n", ld);
314                 printf("  dn = [%s]\n", bound_dn);
315                 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
316                         printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
317                         printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
318                         for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
319                                 printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
320                                 
321                 }
322         }
323 #endif
324
325         if (ldap_modify_s(ld, bound_dn, mods)) {
326                 if ((action == G_JOIN) && (ld->ld_errno == LDAP_TYPE_OR_VALUE_EXISTS))
327                         printf("  You are already subscribed to \"%s\"\n", group_name);
328                 else if ((action == G_RESIGN) && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE))
329                         printf("  You are not subscribed to \"%s\"\n", group_name);
330                 else
331                         mod_perror(ld);
332                 Free(group_name);
333                 return;
334         }
335         ldap_uncache_entry(ld, bound_dn);
336         if (verbose) {
337                 switch (action) {
338                 case G_JOIN:
339                         printf("  You are now subscribed to \"%s\"\n", group_name);
340                         break;
341                 case G_RESIGN:
342                         printf("  You are no longer subscribed to \"%s\"\n", group_name);
343                         break;
344                 }
345         }
346         Free(group_name);
347         return;
348 }
349
350 void bulk_load(group)
351 char *group;
352 {
353         register int idx_mail, idx_x500;
354         register int count_mail, count_x500;
355         char *values_mail[MAX_VALUES + 1], *values_x500[MAX_VALUES + 1];
356         int added_mail_entries = FALSE, added_x500_entries = FALSE;
357         char s[MED_BUF_SIZE];
358         LDAPMod mod, *mods[2];
359         LDAPMessage *lm;
360         FILE *fp;
361         int len;
362
363 #ifdef DEBUG
364         if (debug & D_TRACE)
365                 printf("->bulk_load(%s)\n", group);
366 #endif
367
368         /* you lose if going through MichNet */
369         if ( !isatty( 1 )) {
370 #ifdef UOFM
371                 printf("  Not allowed via UM-X500 connections.\n");
372 #endif
373                 return;
374         }
375
376         /* fetch entries from the file containing the e-mail addresses */
377         printf("\n  File to load? ");
378         fflush(stdout);
379         fetch_buffer(s, sizeof(s), stdin);
380         if (s[0] == '\0') {
381                 return;
382                 /*NOTREACHED*/
383         }
384         if ((fp = fopen(s, "r")) == NULL) {
385                 perror("bulk_load: fopen");
386                 return;
387         }
388         if (verbose)
389                 printf("  Loading group members from %s\n", s);
390
391         /* load them in MAX_VALUES at a time */
392         for (;;) {
393                 for (idx_mail = 0, idx_x500 = 0; 
394                      idx_mail < MAX_VALUES && idx_x500 < MAX_VALUES; ) {
395                         (void) fgets(s, sizeof(s), fp);
396                         if (feof(fp))
397                                 break;
398                         len = strlen(s) - 1;
399                         if (len == 0)
400                                 continue;
401                         s[len] = '\0';
402                         if (strchr(s, '@'))
403                                 values_mail[idx_mail++] = strdup(s);
404                         else {
405                                 if ((lm = find(s, !verbose)) == (LDAPMessage *) NULL) {
406                                         printf("  Could not locate \"%s\" -- skipping.\n", s);
407                                 }
408                                 else {
409                                     parse_answer(lm);
410                                     values_x500[idx_x500++] = strdup(Entry.DN);
411                                 }
412                         }
413                 }
414                 values_mail[idx_mail] = NULL;
415                 values_x500[idx_x500] = NULL;
416                 count_mail = idx_mail;
417                 count_x500 = idx_x500;
418
419                 /*
420                  *  Add the e-mail addresses.
421                  */
422                 if (count_mail > 0) {
423                         mods[0] = &mod;
424                         mods[1] = (LDAPMod *) NULL;
425                         mod.mod_type = "mail";
426                         mod.mod_values = values_mail;
427                         if (added_mail_entries)
428                                 mod.mod_op = LDAP_MOD_ADD;
429                         else
430                                 mod.mod_op = LDAP_MOD_REPLACE;
431
432 #ifdef DEBUG
433                         if (debug & D_GROUPS) {
434                         register LDAPMod **lpp;
435                         register char **cp;
436                         register int i, j;
437                         printf("  About to call ldap_modify_s()\n");
438                         printf("  ld = 0x%x\n", ld);
439                         printf("  dn = [%s]\n", group);
440                         for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
441                                 printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
442                                 printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
443                                 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
444                                         printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
445                                 }
446                         }
447 #endif
448                         if (ldap_modify_s(ld, group, mods))
449                                 mod_perror(ld);
450                         for (idx_mail--; idx_mail >= 0; idx_mail--)
451                                 Free(values_mail[idx_mail]);
452                         ldap_uncache_entry(ld, group);
453                         added_mail_entries = TRUE;
454
455                 }
456
457                 /*
458                  *  Add the X.500 style names.
459                  */
460                 if (count_x500 > 0) {
461                         mods[0] = &mod;
462                         mods[1] = (LDAPMod *) NULL;
463                         mod.mod_type = "member";
464                         mod.mod_values = values_x500;
465                         if (added_x500_entries)
466                                 mod.mod_op = LDAP_MOD_ADD;
467                         else
468                                 mod.mod_op = LDAP_MOD_REPLACE;
469
470 #ifdef DEBUG
471                         if (debug & D_GROUPS) {
472                         register LDAPMod **lpp;
473                         register char **cp;
474                         register int i, j;
475                         printf("  About to call ldap_modify_s()\n");
476                         printf("  ld = 0x%x\n", ld);
477                         printf("  dn = [%s]\n", group);
478                         for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
479                                 printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
480                                 printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
481                                 for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
482                                         printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
483                                 }
484                         }
485 #endif
486                         if (ldap_modify_s(ld, group, mods))
487                                 mod_perror(ld);
488                         for (idx_x500--; idx_x500 >= 0; idx_x500--)
489                                 Free(values_x500[idx_x500]);
490                         ldap_uncache_entry(ld, group);
491                         added_x500_entries = TRUE;
492
493                 }
494
495                 /*
496                  *  If both counts were less than the maximum number we
497                  *  can handle at a time, then we are done.
498                  */
499                 if ((count_mail < MAX_VALUES) && (count_x500 < MAX_VALUES))
500                         break;
501         }
502         fclose(fp);
503         return;
504 }
505
506 void purge_group(group)
507 char *group;
508 {
509         int isclean = TRUE;
510         LDAPMessage *lm;
511         LDAPMod mod, *mods[2];
512         char dn[BUFSIZ], tmp[BUFSIZ], *values[2], **vp, **rdns;
513         extern char * my_ldap_dn2ufn();
514         extern int col_size;
515
516 #ifdef DEBUG
517         if (debug & D_TRACE) {
518                 if (group == NULL)
519                         printf("->purge_group(NULL)\n");
520                 else
521                         printf("->purge_group(%s)\n", group);
522         }
523 #endif
524         if (bind_status == UD_NOT_BOUND) {
525                 if (auth((char *) NULL, 1) < 0)
526                         return;
527         }
528         /*
529          *  If the user did not supply us with a name, prompt them for
530          *  a name.
531          */
532         if ((group == NULL) || (*group == '\0')) {
533                 printf("Group to purge? ");
534                 fflush(stdout);
535                 fetch_buffer(tmp, sizeof(tmp), stdin);
536                 if (tmp[0] == '\0')
537                         return;
538                 group = tmp;
539         }
540         sprintf(dn, "cn=%s, %s", group, group_base);
541
542         /* make sure the group in question exists */
543         if ((lm = find(group, FALSE)) == (LDAPMessage *) NULL) {
544                 printf("  Could not locate group \"%s\"\n", group);
545                 return;
546         }
547         parse_answer(lm);
548         ldap_msgfree(lm);
549
550         /* none of this stuff changes */
551         mods[0] = &mod;
552         mods[1] = (LDAPMod *) NULL;
553
554         values[1] = NULL;
555
556         mod.mod_values = values;
557         mod.mod_type = "member";
558         mod.mod_op = LDAP_MOD_DELETE;
559
560         /*
561          *  Now cycle through all of the names in the "members" part of the
562          *  group (but not the e-mail address part).  Lookup each one, and
563          *  if it isn't found, let the user know so s/he can delete it.
564          */
565         vp = Entry.attrs[attr_to_index("member")].values;
566         if (vp == NULL) {
567                 if (verbose)
568                         printf("  \"%s\" has no X.500 members.  There is nothing to purge.\n", group);
569                 return;
570         }
571         for (; *vp != NULL; vp++) {
572                 char ans[BUFSIZ], *ufn, *label = "Did not find:  ";
573                 int len = strlen(label);
574
575                 if (vrfy(*vp))
576                         continue;
577                 isclean = FALSE;
578                 ufn = my_ldap_dn2ufn(*vp);
579                 format2(ufn, label, (char *) NULL, 2, 2 + len, col_size);
580 ask:
581                 printf("  Purge, Keep, Replace, Abort [Keep]? ");
582                 fflush(stdout);
583                 fetch_buffer(ans, sizeof(ans), stdin);
584                 if ((ans[0] == '\0') || !strncasecmp(ans, "Keep", strlen(ans)))
585                         continue;
586                 if (!strncasecmp(ans, "Abort", strlen(ans))) {
587                         ldap_uncache_entry(ld, dn);
588                         return;
589                 }
590                 if (!strncasecmp(ans, "Purge", strlen(ans)) || !strncasecmp(ans, "Replace", strlen(ans))) {
591                         values[0] = *vp;
592 #ifdef DEBUG
593                         if (debug & D_GROUPS) {
594                                 register LDAPMod **lpp;
595                                 register char **cp;
596                                 register int i, j;
597                                 printf("  About to call ldap_modify_s()\n");
598                                 printf("  ld = 0x%x\n", ld);
599                                 printf("  dn = [%s]\n", Entry.DN);
600                                 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
601                                         printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
602                                         printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
603                                         for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
604                                                 printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
605                                                 
606                                 }
607                         }
608 #endif
609                         if (ldap_modify_s(ld, Entry.DN, mods))
610                                 mod_perror(ld);
611
612                         /* now add the replacement if requested */
613                         if (!strncasecmp(ans, "Purge", strlen(ans)))
614                                 continue;
615                         rdns = ldap_explode_dn(*vp, TRUE);
616                         if ((lm = find(*rdns, FALSE)) == NULL) {
617                                 printf("  Could not find a replacement for %s; purged only.\n", *rdns);
618                                 ldap_msgfree(lm);
619                                 ldap_value_free(rdns);
620                                 break;
621                         }
622                         values[0] = ldap_get_dn(ld, ldap_first_entry(ld, lm));
623                         mod.mod_op = LDAP_MOD_ADD;
624 #ifdef DEBUG
625                         if (debug & D_GROUPS) {
626                                 register LDAPMod **lpp;
627                                 register char **cp;
628                                 register int i, j;
629                                 printf("  About to call ldap_modify_s()\n");
630                                 printf("  ld = 0x%x\n", ld);
631                                 printf("  dn = [%s]\n", Entry.DN);
632                                 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
633                                         printf("  mods[%1d] code = %1d\n", i, (*lpp)->mod_op);
634                                         printf("  mods[%1d] type = %s\n", i, (*lpp)->mod_type);
635                                         for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
636                                                 printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
637                                                 
638                                 }
639                         }
640 #endif
641                         if (ldap_modify_s(ld, Entry.DN, mods))
642                                 mod_perror(ld);
643                         ldap_msgfree(lm);
644                         ldap_value_free(rdns);
645         
646                         /* set this back to DELETE for other purges */
647                         mod.mod_op = LDAP_MOD_DELETE;
648                 }
649                 else {
650                         printf("  Did not recognize that answer.\n\n");
651                         goto ask;
652                 }
653         }
654         ldap_uncache_entry(ld, Entry.DN);
655         if (isclean)
656                 printf("  No entries were purged.\n");
657         return;
658 }
659
660 void tidy_up()
661 {
662         register int i = 0;
663         int found_one = 0;
664         register char **vp;
665         LDAPMessage *lm;
666         static LDAPMod mod;
667         static LDAPMod *mods[2] = { &mod, NULL };
668         static char *values[MAX_VALUES];
669
670 #ifdef DEBUG
671         if (debug & D_TRACE)
672                 printf("->tidy()\n");
673 #endif
674
675         if (bind_status == UD_NOT_BOUND) {
676                 if (auth((char *) NULL, 1) < 0) {
677                         return;
678                 }
679         }
680
681         /* lookup the user, and see to which groups he has subscribed */
682         vp = ldap_explode_dn(bound_dn, TRUE);
683         if ((lm = find(*vp, TRUE)) == (LDAPMessage *) NULL) {
684                 printf("  Could not locate \"%s\"\n", *vp);
685                 ldap_value_free(vp);
686                 return;
687         }
688         ldap_value_free(vp);
689         parse_answer(lm);
690         ldap_msgfree(lm);
691         vp = Entry.attrs[attr_to_index("memberOfGroup")].values;
692         if (vp == NULL) {
693                 printf("  You have not subscribed to any groups.\n");
694                 return;
695         }
696
697         /* now, loop through these groups, deleting the bogus */
698         for ( ; *vp != NULL; vp++) {
699                 if (vrfy(*vp))
700                         continue;
701                 found_one++;
702                 printf("  \"%s\" is not a valid group name.\n", *vp);
703                 values[i++] = strdup(*vp);
704                 if ( i >= MAX_VALUES ) {
705                         printf( "  At most %d invalid groups can be removed at one time; skipping the rest.\n", MAX_VALUES );
706                         break;
707                 }
708         }
709         if (found_one == 0) {
710                 if (verbose)
711                         printf("  You are not a member of any invalid groups.  There is nothing to tidy.\n");
712                 return;
713         }
714
715         /* delete the most heinous entries */
716         values[i] = NULL;
717         mod.mod_values = values;
718         mod.mod_op = LDAP_MOD_DELETE;
719         mod.mod_type = "memberOfGroup";
720         if (ldap_modify_s(ld, bound_dn, mods))
721                 mod_perror(ld);
722         ldap_uncache_entry(ld, bound_dn);
723
724         /* tidy up before we finish tidy_up */
725         for ( ; i >= 1; i--)
726                 Free(values[i - 1]);
727         return;
728 }
729
730 /*
731  *  This routine is used to modify lists that can contain either Distinguished
732  *  Names or e-mail addresses.  This includes things like group members,
733  *  the errors-to field in groups, and so on.
734  */
735 void mod_addrDN(group, offset)
736 char *group;
737 int offset;
738 {
739         extern struct attribute attrlist[];
740         char s[BUFSIZ], *new_value /* was member */, *values[2];
741         char attrtype[ 64 ];
742         int i;
743         LDAPMod mod, *mods[2];
744         LDAPMessage *mp;
745
746 #ifdef DEBUG
747         if (debug & D_TRACE)
748                 printf("->mod_addrDN(%s)\n", group);
749 #endif
750         /*
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.
756          */
757         if (verbose) {
758                 printf("\n");
759                 if ( !isatty( 1 ))
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);
761                 else
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);
763         }
764
765         /* initialize the modififier type */
766         mod.mod_type = NULL;
767
768         for (;;) {
769                 if ( !isatty( 1 ))
770                         printf("  Do you want to Add, Delete, or Replace? ");
771                 else
772                         printf("  Do you want to Add, Delete, Replace, or Bulk load? ");
773                 fflush(stdout);
774                 fetch_buffer(s, sizeof(s), stdin);
775                 if (s[0] == '\0') {
776                         return;
777                         /*NOTREACHED*/
778                 }
779                 if (!strncasecmp(s, "add", strlen(s))) {
780                         mod.mod_op = LDAP_MOD_ADD;
781                         break;
782                 }
783                 else if (!strncasecmp(s, "delete", strlen(s))) {
784                         mod.mod_op = LDAP_MOD_DELETE;
785                         break;
786                 }
787                 else if (!strncasecmp(s, "replace", strlen(s))) {
788                         mod.mod_op = LDAP_MOD_REPLACE;
789                         break;
790                 }
791                 else if(!strncasecmp(s, "bulk", strlen(s))) {
792                         bulk_load(group);
793                         return;
794                 }
795                 else if (verbose) {
796                         printf("\n");
797                         if ( !isatty( 1 ))
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);
799                         else
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);
801                 }
802         }
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");
806                         return;
807                 }
808         }
809         if (verbose) {
810                 printf("\n");
811                 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);
812                 printf("\n");
813         }
814
815         for (;;) {
816                 printf("%s? ", attrlist[offset].output_string);
817                 fflush(stdout);
818                 fetch_buffer(s, sizeof(s), stdin);
819                 if (s[0] == '\0')
820                         return;
821
822                 /*
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.
826                  *
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.
829                  *
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.
834                  */
835                 if (*s == ',') {
836                         new_value = s + 1;
837                         mod.mod_type = attrlist[offset].quipu_name;
838                 }
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)){
843                                         printf("\n");
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);
845                                         printf("\n");
846                                 }
847                                 continue;
848                         }
849                         parse_answer(mp);
850                         new_value = Entry.DN;
851                         mod.mod_type = attrlist[offset].quipu_name;
852                 }
853                 else if (mod.mod_op != LDAP_MOD_DELETE) {
854                         /*
855                          * Don't screw around with what the user has typed
856                          * if they are simply trying to delete a rfc822mailbox
857                          * value.
858                          *
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
862                          * would not be here
863                          *
864                          * note that this means a value like:
865                          *
866                          *      first m. last@host.domain
867                          *
868                          * will be turned into:
869                          *
870                          *      first.m..last@host.domain
871                          *
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
875                          *
876                          * Don't screw up things like:
877                          *
878                          *      "Bryan Beecher" <bryan@umich.edu>
879                          *       Bryan Beecher  <bryan@umich.edu>
880                          */
881                         register char *cp;
882                         if (strchr(s, '<') == NULL) {
883                                 for (cp = s; *cp != '@'; cp++)
884                                         if (isspace(*cp))
885                                                 *cp = '.';
886                         }
887                         new_value = s;
888                         strcpy(attrtype, "rfc822");
889                         strcat(attrtype, attrlist[offset].quipu_name);
890                         mod.mod_type = attrtype;
891                 }
892                 else {
893                         new_value = s;
894                         strcpy(attrtype, "rfc822");
895                         strcat(attrtype, attrlist[offset].quipu_name);
896                         mod.mod_type = attrtype;
897                 }
898
899                 /*  fill in the rest of the ldap_mod() structure */
900                 mods[0] = &mod;
901                 mods[1] = (LDAPMod *) NULL;
902
903                 values[0] = new_value;
904                 values[1] = NULL;
905                 mod.mod_values = values;
906
907 #ifdef DEBUG
908                 if (debug & D_GROUPS) {
909                         register LDAPMod **lpp;
910                         register char **cp;
911                         register int i, j;
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", 
917                                                         i, (*lpp)->mod_op);
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", 
922                                                                 i, j, *cp);
923                         }
924                 }
925 #endif
926
927                 if (my_ldap_modify_s(ld, group, mods)) {
928                         if (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) {
929                                 printf("  Could not locate value \"%s\"\n", 
930                                                                 new_value);
931                                 continue;
932                         }
933                         else {
934                                 mod_perror(ld);
935                                 return;
936                         }
937                 }
938                 ldap_uncache_entry(ld, group);
939
940                 /*
941                  *  If the operation was REPLACE, we now need to "zero out" the
942                  *  other "half" of the list (e.g., user specified an e-mail
943                  *  address; now we need to clear the DN part of the list).
944                  *
945                  *  NOTE:  WE HAVE ALREADY DONE HALF OF THE REPLACE ABOVE.
946                  *
947                  *  Also, change the opcode to LDAP_MOD_ADD and give the user an
948                  *  opportunity to add additional members to the group.  We
949                  *  only take this branch the very first time during a REPLACE
950                  *  operation.
951                  */
952                 if (mod.mod_op == LDAP_MOD_REPLACE) {
953                         if (!strncmp(mod.mod_type, "rfc822", 6))
954                                 mod.mod_type = mod.mod_type + 6;
955                         else {
956                                 strcpy(attrtype, "rfc822");
957                                 strcat(attrtype, mod.mod_type);
958                                 mod.mod_type = attrtype;
959                         }
960                         mods[0] = &mod;
961                         values[0] = NULL;
962                         mod.mod_values = values;
963                         mod.mod_op = LDAP_MOD_DELETE;
964 #ifdef DEBUG
965                         if (debug & D_GROUPS) {
966                                 register LDAPMod **lpp;
967                                 register char **cp;
968                                 register int i, j;
969                                 printf("  About to call ldap_modify_s()\n");
970                                 printf("  ld = 0x%x\n", ld);
971                                 printf("  dn = [%s]\n", group);
972                                 for (lpp = mods, i = 1; *lpp != NULL; lpp++, i++) {
973                                         printf("  mods[%1d] code = %1d\n", 
974                                                         i, (*lpp)->mod_op);
975                                         printf("  mods[%1d] type = %s\n", 
976                                                         i, (*lpp)->mod_type);
977                                         for (cp = (*lpp)->mod_values, j = 1; *cp != NULL; cp++, j++)
978                                                 printf("  mods[%1d] v[%1d] = %s\n", i, j, *cp);
979                                 }
980                         }
981 #endif
982                         if (my_ldap_modify_s(ld, group, mods)) {
983                                 /*
984                                 *  A "No such attribute" error is no big deal.
985                                 *  We only wanted to clear the attribute anyhow.
986                                 */
987                                 if (ld->ld_errno != LDAP_NO_SUCH_ATTRIBUTE) {
988                                         mod_perror(ld);
989                                         return;
990                                 }
991                         }
992                         ldap_uncache_entry(ld, group);
993                         if (verbose)
994                                 printf("  \"%s\" has been added\n", new_value);
995                         mod.mod_op = LDAP_MOD_ADD;
996                 }
997                 else if (verbose && (mod.mod_op == LDAP_MOD_ADD))
998                         printf("  \"%s\" has been added\n", new_value);
999                 else if (verbose && (mod.mod_op == LDAP_MOD_DELETE))
1000                         printf("  \"%s\" has been removed\n", new_value);
1001         }
1002 }
1003
1004 my_ldap_modify_s(ldap, group, mods)
1005 LDAP *ldap;
1006 char *group;
1007 LDAPMod *mods[];
1008 {
1009         int     was_rfc822member, rc;
1010
1011         was_rfc822member = 0;
1012
1013         if (!strcasecmp(mods[0]->mod_type, "rfc822member")) {
1014                 mods[0]->mod_type = "mail";
1015                 was_rfc822member = 1;
1016         }
1017
1018         rc = ldap_modify_s(ldap, group, mods);
1019
1020         if (was_rfc822member)
1021             mods[0]->mod_type = "rfc822member";
1022
1023         return(rc);
1024 }
1025
1026 void list_groups(who)
1027 char *who;
1028 {
1029         LDAPMessage *mp;
1030         char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1031         char *work_area[MAX_NUM_NAMES];
1032         char *dn, **rdns;
1033         int i, rc;
1034         
1035
1036 #ifdef DEBUG
1037         if (debug & D_TRACE) {
1038                 if (who == NULL)
1039                         printf("->list_groups(NULL)\n");
1040                 else
1041                         printf("->list_groups(%s)\n", who);
1042         }
1043 #endif
1044         /*
1045          *  First, decide what entry we are going to list.  If the
1046          *  user has not included a name on the list command line,
1047          *  we will use the person who was last looked up with a find
1048          *  command.
1049          *
1050          *  Once we know who to modify, be sure that they exist, and
1051          *  parse out their DN.
1052          */
1053         if (who == NULL) {
1054                 printf("  List groups belonging to whose entry? ");
1055                 fflush(stdout);
1056                 fetch_buffer(name, sizeof(name), stdin);
1057                 if (name[0] != '\0')
1058                         who = name;
1059                 else
1060                         return;
1061         }
1062         if ((mp = find(who, TRUE)) == NULL) {
1063                 (void) ldap_msgfree(mp);
1064                 printf("  Could not locate \"%s\" in the Directory.\n", who);
1065                 return;
1066         }
1067         dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1068         ldap_msgfree(mp);
1069         rdns = ldap_explode_dn(dn, TRUE);
1070         if (verbose)
1071                 printf("\n  Listing groups belonging to \"%s\"\n", *rdns);
1072
1073         /* lookup the groups belonging to this person */
1074         sprintf(filter, "owner=%s", dn);
1075         Free(dn);
1076         search_attrs[0] = "cn";
1077         search_attrs[1] = NULL;
1078         if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, 
1079                 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1080             rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1081                 ldap_perror(ld, "ldap_search_s");
1082                 ldap_value_free(rdns);
1083                 return;
1084         }
1085         if ((rc = ldap_count_entries(ld, mp)) < 0) {
1086                 ldap_perror(ld, "ldap_count_entries");
1087                 ldap_value_free(rdns);
1088                 return;
1089         }
1090         if (rc == 0) {
1091                 printf("  %s owns no groups in this portion of the Directory.\n", *rdns);
1092                 ldap_value_free(rdns);
1093                 return;
1094         }
1095         if (verbose)
1096                 printf("  %s owns %d groups.\n\n", *rdns, rc);
1097         print_list(mp, work_area, &rc);
1098         for (i = 1; work_area[i] != NULL; i++)
1099                 Free(work_area[i]);
1100         ldap_msgfree(mp);
1101         ldap_value_free(rdns);
1102         return;
1103 }
1104
1105 static char * bind_and_fetch(name)
1106 char *name;
1107 {
1108         LDAPMessage *lm;
1109         char tmp[MED_BUF_SIZE];
1110         extern char * strip_ignore_chars();
1111
1112 #ifdef DEBUG
1113         if (debug & D_TRACE) {
1114                 if (name == NULL)
1115                         printf("->bind_and_fetch(NULL)\n");
1116                 else
1117                         printf("->bind_and_fetch(%s)\n", name);
1118         }
1119 #endif
1120         if (bind_status == UD_NOT_BOUND) {
1121                 if (auth((char *) NULL, 1) < 0)
1122                         return(NULL);
1123         }
1124
1125         /*
1126          *  If the user did not supply us with a name, prompt them for
1127          *  a name.
1128          */
1129         if ((name == NULL) || (*name == '\0')) {
1130                 printf("  Group? ");
1131                 fflush(stdout);
1132                 fetch_buffer(tmp, sizeof(tmp), stdin);
1133                 if (tmp[0] == '\0')
1134                         return(NULL);
1135                 name = tmp;
1136         }
1137         /* remove quotes, dots, and underscores. */
1138         name = strip_ignore_chars(name);
1139
1140 #ifdef DEBUG
1141         if (debug & D_GROUPS)
1142                 printf("Group name = (%s)\n", name);
1143 #endif
1144
1145         /* make sure the group in question exists and is joinable */
1146         if ((lm = find(name, TRUE)) == (LDAPMessage *) NULL) {
1147                 printf("  Could not locate group \"%s\"\n", name);
1148                 return(NULL);
1149         }
1150         parse_answer(lm);
1151         ldap_msgfree(lm);
1152
1153 #ifdef DEBUG
1154         if (debug & D_GROUPS)
1155                 printf("Group DN = (%s)\n", Entry.DN);
1156 #endif
1157         return(strdup(Entry.DN));
1158 }
1159
1160 void list_memberships(who)
1161 char *who;
1162 {
1163         LDAPMessage *mp;
1164         char name[BUFSIZ], filter[BUFSIZ], *search_attrs[2];
1165         char *work_area[MAX_NUM_NAMES];
1166         char *dn, **rdns;
1167         int i, rc;
1168         
1169
1170 #ifdef DEBUG
1171         if (debug & D_TRACE) {
1172                 if (who == NULL)
1173                         printf("->list_memberships(NULL)\n");
1174                 else
1175                         printf("->list_memberships(%s)\n", who);
1176         }
1177 #endif
1178         /*
1179          *  First, decide what entry we are going to list.  If the
1180          *  user has not included a name on the list command line,
1181          *  we will use the person who was last looked up with a find
1182          *  command.
1183          *
1184          *  Once we know who to modify, be sure that they exist, and
1185          *  parse out their DN.
1186          */
1187         if (who == NULL) {
1188                 printf("  List memberships containing whose entry? ");
1189                 fflush(stdout);
1190                 fetch_buffer(name, sizeof(name), stdin);
1191                 if (name[0] != '\0')
1192                         who = name;
1193                 else
1194                         return;
1195         }
1196         if ((mp = find(who, TRUE)) == NULL) {
1197                 (void) ldap_msgfree(mp);
1198                 printf("  Could not locate \"%s\" in the Directory.\n", who);
1199                 ldap_msgfree(mp);
1200                 return;
1201         }
1202         dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
1203         rdns = ldap_explode_dn(dn, TRUE);
1204         if (verbose)
1205                 printf("\n  Listing memberships of \"%s\"\n", *rdns);
1206
1207         /* lookup the groups belonging to this person */
1208         sprintf(filter, "member=%s", dn);
1209         Free(dn);
1210         search_attrs[0] = "cn";
1211         search_attrs[1] = NULL;
1212         ldap_msgfree(mp);
1213         if ((rc = ldap_search_s(ld, UD_WHERE_ALL_GROUPS_LIVE, LDAP_SCOPE_SUBTREE, 
1214                 filter, search_attrs, FALSE, &mp)) != LDAP_SUCCESS &&
1215             rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
1216                 ldap_perror(ld, "ldap_search_s");
1217                 ldap_msgfree(mp);
1218                 ldap_value_free(rdns);
1219                 return;
1220         }
1221         if ((rc = ldap_count_entries(ld, mp)) < 0) {
1222                 ldap_perror(ld, "ldap_count_entries");
1223                 ldap_msgfree(mp);
1224                 ldap_value_free(rdns);
1225                 return;
1226         }
1227         if (rc == 0) {
1228                 printf("  %s is not a member of any groups in this portion of the Directory.\n", *rdns);
1229                 ldap_msgfree(mp);
1230                 ldap_value_free(rdns);
1231                 return;
1232         }
1233         if (verbose)
1234                 printf("  %s is a member of %d groups.\n\n", *rdns, rc);
1235
1236         /*
1237          *  print_list fills in the char * array starting at 1, not 0
1238          */
1239         print_list(mp, work_area, &rc);
1240         for (i = 1; work_area[i] != NULL; i++)
1241                 Free(work_area[i]);
1242         ldap_msgfree(mp);
1243         ldap_value_free(rdns);
1244         return;
1245 }