3 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 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/stdlib.h>
25 #include <ac/signal.h>
26 #include <ac/string.h>
30 #include <ac/unistd.h>
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
38 #ifdef HAVE_SYS_RESOURCE_H
39 #include <sys/resource.h>
52 #include "ldap_defaults.h"
55 static int load_editor( void );
56 static int modifiable( char *s, short flag );
57 static int print_attrs_and_values( FILE *fp, struct attribute *attrs, short flag );
58 static int ovalues( char *attr );
59 static void write_entry( void );
61 static char entry_temp_file[L_tmpnam];
67 LDAPMessage *mp; /* returned from find() */
68 char *dn, **rdns; /* distinguished name */
69 char name[MED_BUF_SIZE]; /* entry to modify */
73 printf("->edit(%s)\n", who);
76 * One must be bound in order to edit an entry.
78 if (bind_status == UD_NOT_BOUND) {
79 if (auth((char *) NULL, 1) < 0)
84 * First, decide what entry we are going to modify. If the
85 * user has not included a name on the modify command line,
86 * we will use the person who was last looked up with a find
87 * command. If there is no value there either, we don't know
90 * Once we know who to modify, be sure that they exist, and
95 printf(" Enter the name of the person or\n");
96 printf(" group whose entry you want to edit: ");
99 printf(" Edit whose entry? ");
101 fetch_buffer(name, sizeof(name), stdin);
107 if ((mp = find(who, TRUE)) == NULL) {
108 (void) ldap_msgfree(mp);
109 printf(" Could not locate \"%s\" in the Directory.\n", who);
112 dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
113 rdns = ldap_explode_dn(dn, TRUE);
116 printf("\n Editing directory entry \"%s\"...\n", *rdns);
119 (void) ldap_msgfree(mp);
120 (void) ldap_value_free(rdns);
121 if (load_editor() < 0)
124 (void) unlink(entry_temp_file);
125 ldap_uncache_entry(ld, Entry.DN);
133 char *cp, *editor = UD_DEFAULT_EDITOR;
143 printf("->load_editor()\n");
146 /* write the entry into a temp file */
147 if (tmpnam(entry_temp_file) == NULL) {
151 if ((tmpfd = open(entry_temp_file, O_WRONLY|O_CREAT|O_EXCL, 0600)) == -1) {
152 perror(entry_temp_file);
155 if ((fp = fdopen(tmpfd, "w")) == NULL) {
159 fprintf(fp, "## Directory entry of %s\n", Entry.name);
161 fprintf(fp, "## Syntax is:\n");
162 fprintf(fp, "## <attribute-name>\n");
163 fprintf(fp, "## <TAB> <value 1>\n");
164 fprintf(fp, "## <TAB> : :\n");
165 fprintf(fp, "## <TAB> <value N>\n");
166 fprintf(fp, "## Lines beginning with a hash mark are comments.\n");
170 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD);
172 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD);
176 (void) unlink(entry_temp_file);
180 /* edit the temp file with the editor of choice */
181 if ((cp = getenv("EDITOR")) != NULL)
186 if (( p = strrchr( editor, '/' )) == NULL ) {
191 printf(" Using %s as the editor...\n", p );
197 rc = _spawnlp( _P_WAIT, editor, editor, entry_temp_file, NULL );
202 if ((pid = fork()) == 0) {
203 /* child - edit the Directory entry */
204 (void) SIGNAL(SIGINT, SIG_IGN);
205 (void) execlp(editor, editor, entry_temp_file, NULL);
207 (void) fatal(editor);
210 /* parent - wait until the child proc is done editing */
211 RETSIGTYPE (*handler)();
212 handler = SIGNAL(SIGINT, SIG_IGN);
213 (void) wait(&status);
214 (void) SIGNAL(SIGINT, handler);
225 print_attrs_and_values( FILE *fp, struct attribute *attrs, short int flag )
229 for (i = 0; attrs[i].quipu_name != NULL; i++) {
230 if (!modifiable(attrs[i].quipu_name,
231 (short) (flag|ATTR_FLAG_MAY_EDIT)))
236 fprintf(fp, "%s\n", attrs[i].quipu_name);
237 if ( attrs[i].number_of_values > MAX_VALUES ) {
238 printf(" The %s attribute has more than %d values.\n",
239 attrs[i].quipu_name, MAX_VALUES );
240 printf(" You cannot use the vedit command on this entry. Sorry!\n" );
243 for (j = 0; j < attrs[i].number_of_values; j++)
244 fprintf(fp, "\t%s\n", attrs[i].values[j]);
250 modifiable( char *s, short int flag )
254 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
255 if (strcasecmp(s, attrlist[i].quipu_name))
257 if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
261 /* should never be here */
268 int i = 0, j, number_of_values = -1;
271 char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
273 LDAPMod *mods[MAX_ATTRS + 1];
274 LDAPMod *modp = NULL;
276 /* parse the file and write the values to the Directory */
277 if ((fp = fopen(entry_temp_file, "r")) == NULL) {
282 (void) fgets(line, sizeof(line), fp);
285 line[strlen(line) - 1] = '\0'; /* kill newline */
289 if (isspace((unsigned char)*cp)) { /* value */
290 while (isspace((unsigned char)*cp))
292 values[number_of_values++] = strdup(cp);
293 if ( number_of_values >= MAX_VALUES ) {
294 printf(" A maximum of %d values can be handled at one time. Sorry!\n", MAX_VALUES );
300 while (isspace((unsigned char)*cp))
303 * If the number of values is greater than zero, then we
304 * know that this is not the first time through this
305 * loop, and we also know that we have a little bit
308 * o The modify operation needs to be changed from
309 * a DELETE to a REPLACE
311 * o The list of values pointer needs to be changed
312 * from NULL, to a NULL-terminated list of char
315 if (number_of_values > 0) {
316 modp->mod_op = LDAP_MOD_REPLACE;
317 if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
321 modp->mod_values = vp;
322 for (j = 0; j < number_of_values; j++) {
323 *vp++ = strdup(values[j]);
324 (void) Free(values[j]);
329 * If there are no values, and there were no values to begin
330 * with, then there is nothing to do.
332 if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
334 if (debug & D_MODIFY)
335 printf(" %s has zero values - skipping\n",
338 (void) Free(modp->mod_type);
339 modp->mod_type = strdup(cp);
340 modp->mod_op = LDAP_MOD_DELETE;
341 modp->mod_values = NULL;
345 * Fetch a new modify structure.
347 * Assume a DELETE operation with no values.
349 if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
353 modp->mod_values = NULL;
354 modp->mod_type = strdup(cp);
355 modp->mod_op = LDAP_MOD_DELETE;
357 number_of_values = 0;
361 /* check the last one too */
362 if (number_of_values > 0) {
363 modp->mod_op = LDAP_MOD_REPLACE;
365 * Fetch some value pointers.
367 * number_of_values To store the values
368 * 1 For the NULL terminator
369 * 1 In case we need it to store
370 * the RDN as on of the values
371 * of 'cn' in case it isn't there
373 if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
374 2))) == (char **) NULL) {
378 modp->mod_values = vp;
379 for (j = 0; j < number_of_values; j++) {
380 *vp++ = strdup(values[j]);
381 (void) Free(values[j]);
385 else if ((number_of_values == 0) &&
386 (ovalues(mods[i - 1]->mod_type) == 0)) {
388 if (debug & D_MODIFY)
389 printf(" %s has zero values - skipping\n",
390 mods[i - 1]->mod_type);
392 Free(mods[i - 1]->mod_type);
396 mods[i] = (LDAPMod *) NULL;
399 * If one of the mods pointers is 'cn', be sure that the RDN is one
402 for (j = 0; j < i; j++) {
403 if (strcasecmp("cn", mods[j]->mod_type))
406 * True only if there WERE values, but the person deleted
409 if (mods[j]->mod_values == NULL) {
410 mods[j]->mod_op = LDAP_MOD_REPLACE;
411 if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
415 mods[j]->mod_values = vp;
416 *vp++ = strdup(Entry.name);
421 * Be sure that one of the values of 'cn' is the RDN.
423 for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
424 if (strcasecmp(*vp, Entry.DN))
429 *vp++ = strdup(Entry.name);
435 if (debug & D_MODIFY) {
438 printf(" ld = 0x%x\n", ld);
439 printf(" dn = [%s]\n", Entry.DN);
440 for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
441 printf(" mods[%d]->mod_op = %s\n",
442 x, code_to_str(mods[x]->mod_op));
443 printf(" mods[%d]->mod_type = %s\n",
444 x, mods[x]->mod_type);
445 if (mods[x]->mod_values == NULL)
446 printf(" mods[%d]->mod_values = NULL\n", x);
448 for (y = 0; mods[x]->mod_values[y] != NULL; y++)
449 printf(" mods[%d]->mod_values[%1d] = %s\n",
450 x, y, mods[x]->mod_values[y]);
451 printf(" mods[%d]->mod_values[%1d] = NULL\n",
458 if (ldap_modify_s(ld, Entry.DN, mods))
461 printf(" Modification complete.\n" );
464 for (i = 0; mods[i] != NULL; i++)
465 free_mod_struct(mods[i]);
470 ovalues( char *attr )
472 struct attribute *ap;
475 * Lookup the attribute with quipu_name 'attr' in the Entry
476 * structure and return the number of values.
478 for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
479 if (!strcasecmp(ap->quipu_name, attr))
480 return(ap->number_of_values);
482 /* should never get to this point unless 'attr' was something odd */