2 * Copyright (c) 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/signal.h>
19 #include <ac/string.h>
23 #include <sys/resource.h>
27 #include <ldapconfig.h>
29 extern void *Malloc();
31 extern struct entry Entry;
35 extern LDAPMessage *find();
37 static int load_editor();
38 static int modifiable();
39 static int print_attrs_and_values();
41 static int write_entry();
43 static char *entry_temp_file;
52 LDAPMessage *mp; /* returned from find() */
53 char *dn, **rdns; /* distinguished name */
54 char name[MED_BUF_SIZE]; /* entry to modify */
55 extern int bind_status;
59 printf("->edit(%s)\n", who);
62 * One must be bound in order to edit an entry.
64 if (bind_status == UD_NOT_BOUND) {
65 if (auth((char *) NULL, 1) < 0)
70 * First, decide what entry we are going to modify. If the
71 * user has not included a name on the modify command line,
72 * we will use the person who was last looked up with a find
73 * command. If there is no value there either, we don't know
76 * Once we know who to modify, be sure that they exist, and
81 printf(" Enter the name of the person or\n");
82 printf(" group whose entry you want to edit: ");
85 printf(" Edit whose entry? ");
87 fetch_buffer(name, sizeof(name), stdin);
93 if ((mp = find(who, TRUE)) == NULL) {
94 (void) ldap_msgfree(mp);
95 printf(" Could not locate \"%s\" in the Directory.\n", who);
98 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
99 rdns = ldap_explode_dn(dn, TRUE);
102 printf("\n Editing directory entry \"%s\"...\n", *rdns);
105 (void) ldap_msgfree(mp);
106 (void) ldap_value_free(rdns);
107 if (load_editor() < 0)
109 (void) write_entry();
110 (void) unlink(entry_temp_file);
111 ldap_uncache_entry(ld, Entry.DN);
118 char *cp, *editor = UD_DEFAULT_EDITOR;
119 static char template[MED_BUF_SIZE];
120 extern char * mktemp();
121 extern int isgroup(), fatal();
129 printf("->load_editor()\n");
132 /* write the entry into a temp file */
133 (void) strcpy(template, "/tmp/udEdit.XXXXXX");
134 if ((entry_temp_file = mktemp(template)) == NULL) {
138 if ((fp = fopen(entry_temp_file, "w")) == NULL) {
142 fprintf(fp, "## Directory entry of %s\n", Entry.name);
144 fprintf(fp, "## Syntax is:\n");
145 fprintf(fp, "## <attribute-name>\n");
146 fprintf(fp, "## <TAB> <value 1>\n");
147 fprintf(fp, "## <TAB> : :\n");
148 fprintf(fp, "## <TAB> <value N>\n");
149 fprintf(fp, "## Lines beginning with a hash mark are comments.\n");
153 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD);
155 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD);
159 (void) unlink(entry_temp_file);
163 /* edit the temp file with the editor of choice */
164 if ((cp = getenv("EDITOR")) != NULL)
169 if (( p = strrchr( editor, '/' )) == NULL ) {
174 printf(" Using %s as the editor...\n", p );
177 if ((pid = fork()) == 0) {
178 /* child - edit the Directory entry */
179 (void) SIGNAL(SIGINT, SIG_IGN);
180 (void) execlp(editor, editor, entry_temp_file, NULL);
182 (void) fatal(editor);
185 /* parent - wait until the child proc is done editing */
186 handler = SIGNAL(SIGINT, SIG_IGN);
187 (void) wait(&status);
188 (void) SIGNAL(SIGINT, handler);
197 static int print_attrs_and_values(fp, attrs, flag)
199 struct attribute attrs[];
204 for (i = 0; attrs[i].quipu_name != NULL; i++) {
205 if (!modifiable(attrs[i].quipu_name, flag|ATTR_FLAG_MAY_EDIT))
207 fprintf(fp, "%s\n", attrs[i].quipu_name);
208 if ( attrs[i].number_of_values > MAX_VALUES ) {
209 printf(" The %s attribute has more than %d values.\n",
210 attrs[i].quipu_name, MAX_VALUES );
211 printf(" You cannot use the vedit command on this entry. Sorry!\n" );
214 for (j = 0; j < attrs[i].number_of_values; j++)
215 fprintf(fp, "\t%s\n", attrs[i].values[j]);
220 static modifiable(s, flag)
225 extern struct attribute attrlist[];
227 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
228 if (strcasecmp(s, attrlist[i].quipu_name))
230 if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
234 /* should never be here */
240 int i = 0, j, number_of_values = -1;
243 char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
245 LDAPMod *mods[MAX_ATTRS + 1];
246 LDAPMod *modp = NULL;
248 extern char * code_to_str();
249 extern void free_mod_struct();
251 /* parse the file and write the values to the Directory */
252 if ((fp = fopen(entry_temp_file, "r")) == NULL) {
257 (void) fgets(line, sizeof(line), fp);
260 line[strlen(line) - 1] = '\0'; /* kill newline */
264 if (isspace(*cp)) { /* value */
267 values[number_of_values++] = strdup(cp);
268 if ( number_of_values >= MAX_VALUES ) {
269 printf(" A maximum of %d values can be handled at one time. Sorry!\n", MAX_VALUES );
278 * If the number of values is greater than zero, then we
279 * know that this is not the first time through this
280 * loop, and we also know that we have a little bit
283 * o The modify operation needs to be changed from
284 * a DELETE to a REPLACE
286 * o The list of values pointer needs to be changed
287 * from NULL, to a NULL-terminated list of char
290 if (number_of_values > 0) {
291 modp->mod_op = LDAP_MOD_REPLACE;
292 if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
296 modp->mod_values = vp;
297 for (j = 0; j < number_of_values; j++) {
298 *vp++ = strdup(values[j]);
299 (void) Free(values[j]);
304 * If there are no values, and there were no values to begin
305 * with, then there is nothing to do.
307 if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
309 if (debug & D_MODIFY)
310 printf(" %s has zero values - skipping\n",
313 (void) Free(modp->mod_type);
314 modp->mod_type = strdup(cp);
315 modp->mod_op = LDAP_MOD_DELETE;
316 modp->mod_values = NULL;
320 * Fetch a new modify structure.
322 * Assume a DELETE operation with no values.
324 if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
328 modp->mod_values = NULL;
329 modp->mod_type = strdup(cp);
330 modp->mod_op = LDAP_MOD_DELETE;
332 number_of_values = 0;
336 /* check the last one too */
337 if (number_of_values > 0) {
338 modp->mod_op = LDAP_MOD_REPLACE;
340 * Fetch some value pointers.
342 * number_of_values To store the values
343 * 1 For the NULL terminator
344 * 1 In case we need it to store
345 * the RDN as on of the values
346 * of 'cn' in case it isn't there
348 if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
349 2))) == (char **) NULL) {
353 modp->mod_values = vp;
354 for (j = 0; j < number_of_values; j++) {
355 *vp++ = strdup(values[j]);
356 (void) Free(values[j]);
360 else if ((number_of_values == 0) &&
361 (ovalues(mods[i - 1]->mod_type) == 0)) {
363 if (debug & D_MODIFY)
364 printf(" %s has zero values - skipping\n",
365 mods[i - 1]->mod_type);
367 Free(mods[i - 1]->mod_type);
371 mods[i] = (LDAPMod *) NULL;
374 * If one of the mods pointers is 'cn', be sure that the RDN is one
377 for (j = 0; j < i; j++) {
378 if (strcasecmp("cn", mods[j]->mod_type))
381 * True only if there WERE values, but the person deleted
384 if (mods[j]->mod_values == NULL) {
385 mods[j]->mod_op = LDAP_MOD_REPLACE;
386 if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
390 mods[j]->mod_values = vp;
391 *vp++ = strdup(Entry.name);
396 * Be sure that one of the values of 'cn' is the RDN.
398 for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
399 if (strcasecmp(*vp, Entry.DN))
404 *vp++ = strdup(Entry.name);
410 if (debug & D_MODIFY) {
413 printf(" ld = 0x%x\n", ld);
414 printf(" dn = [%s]\n", Entry.DN);
415 for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
416 printf(" mods[%d]->mod_op = %s\n",
417 x, code_to_str(mods[x]->mod_op));
418 printf(" mods[%d]->mod_type = %s\n",
419 x, mods[x]->mod_type);
420 if (mods[x]->mod_values == NULL)
421 printf(" mods[%d]->mod_values = NULL\n", x);
423 for (y = 0; mods[x]->mod_values[y] != NULL; y++)
424 printf(" mods[%d]->mod_values[%1d] = %s\n",
425 x, y, mods[x]->mod_values[y]);
426 printf(" mods[%d]->mod_values[%1d] = NULL\n",
433 if (ldap_modify_s(ld, Entry.DN, mods))
436 printf(" Modification complete.\n" );
439 for (i = 0; mods[i] != NULL; i++)
440 free_mod_struct(mods[i]);
447 struct attribute *ap;
450 * Lookup the attribute with quipu_name 'attr' in the Entry
451 * structure and return the number of values.
453 for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
454 if (!strcasecmp(ap->quipu_name, attr))
455 return(ap->number_of_values);
457 /* should never get to this point unless 'attr' was something odd */