]> git.sur5r.net Git - openldap/blob - clients/ud/edit.c
Remove lint
[openldap] / clients / ud / edit.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1994  Regents of the University of Michigan.
8  * All rights reserved.
9  *
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.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/stdlib.h>
23
24 #include <ac/signal.h>
25 #include <ac/string.h>
26 #include <ac/ctype.h>
27 #include <ac/time.h>
28 #include <ac/wait.h>
29 #include <ac/unistd.h>
30
31 #ifdef HAVE_SYS_RESOURCE_H
32 #include <sys/resource.h>
33 #endif
34 #ifdef HAVE_PROCESS_H
35 #include <process.h>
36 #endif
37
38 #ifdef HAVE_IO_H
39 #include <io.h>
40 #endif
41
42 #include <lber.h>
43 #include <ldap.h>
44
45 #include "ldap_defaults.h"
46 #include "ud.h"
47
48 static int  load_editor( void );
49 static int  modifiable( char *s, short flag );
50 static int  print_attrs_and_values( FILE *fp, struct attribute *attrs, short flag );
51 static int  ovalues( char *attr );
52 static void write_entry( void );
53
54 static char *entry_temp_file;
55
56
57 void
58 edit( char *who )
59 {
60         LDAPMessage *mp;                        /* returned from find() */
61         char *dn, **rdns;                       /* distinguished name */
62         char name[MED_BUF_SIZE];                /* entry to modify */
63
64 #ifdef DEBUG
65         if (debug & D_TRACE)
66                 printf("->edit(%s)\n", who);
67 #endif
68         /*
69          *  One must be bound in order to edit an entry.
70          */
71         if (bind_status == UD_NOT_BOUND) {
72                 if (auth((char *) NULL, 1) < 0)
73                         return;
74         }
75
76         /*
77          *  First, decide what entry we are going to modify.  If the
78          *  user has not included a name on the modify command line,
79          *  we will use the person who was last looked up with a find
80          *  command.  If there is no value there either, we don't know
81          *  who to modify.
82          *
83          *  Once we know who to modify, be sure that they exist, and
84          *  parse out their DN.
85          */
86         if (who == NULL) {
87                 if (verbose) {
88                         printf("  Enter the name of the person or\n");
89                         printf("  group whose entry you want to edit: ");
90                 }
91                 else
92                         printf("  Edit whose entry? ");
93                 fflush(stdout);
94                 fetch_buffer(name, sizeof(name), stdin);
95                 if (name[0] != '\0')
96                         who = name;
97                 else
98                         return;
99         }
100         if ((mp = find(who, TRUE)) == NULL) {
101                 (void) ldap_msgfree(mp);
102                 printf("  Could not locate \"%s\" in the Directory.\n", who);
103                 return;
104         }
105         dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
106         rdns = ldap_explode_dn(dn, TRUE);
107         ldap_memfree(dn);
108         if (verbose) {
109                 printf("\n  Editing directory entry \"%s\"...\n", *rdns);
110         }
111         parse_answer(mp);
112         (void) ldap_msgfree(mp);
113         (void) ldap_value_free(rdns);
114         if (load_editor() < 0)
115                 return;
116         write_entry();
117         (void) unlink(entry_temp_file);
118         ldap_uncache_entry(ld, Entry.DN);
119         return;
120 }
121
122 static int
123 load_editor( void )
124 {
125         FILE *fp;
126         char *cp, *editor = UD_DEFAULT_EDITOR;
127         static char template[MED_BUF_SIZE];
128 #ifndef HAVE_SPAWNLP
129         int pid;
130         int status;
131 #endif
132         int rc;
133         
134 #ifdef DEBUG
135         if (debug & D_TRACE)
136                 printf("->load_editor()\n");
137 #endif
138
139         /* write the entry into a temp file */
140         (void) strcpy(template, "/tmp/udEdit.XXXXXX");
141         if ((entry_temp_file = mktemp(template)) == NULL) {
142                 perror("mktemp");
143                 return(-1);
144         }
145         if ((fp = fopen(entry_temp_file, "w")) == NULL) {
146                 perror("fopen");
147                 return(-1);
148         }
149         fprintf(fp, "## Directory entry of %s\n", Entry.name);
150         fprintf(fp, "##\n");
151         fprintf(fp, "## Syntax is:\n");
152         fprintf(fp, "## <attribute-name>\n");
153         fprintf(fp, "##         <TAB> <value 1>\n");
154         fprintf(fp, "##         <TAB>   :  :\n");
155         fprintf(fp, "##         <TAB> <value N>\n");
156         fprintf(fp, "## Lines beginning with a hash mark are comments.\n");
157         fprintf(fp, "##\n");
158         fflush(fp);
159         if (isgroup())
160                 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD);
161         else
162                 rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD);
163         fclose(fp);
164
165         if ( rc != 0 ) {
166             (void) unlink(entry_temp_file);
167             return( rc );
168         }
169
170         /* edit the temp file with the editor of choice */
171         if ((cp = getenv("EDITOR")) != NULL)
172                 editor = cp;
173         if (verbose) {
174                 char    *p;
175
176                 if (( p = strrchr( editor, '/' )) == NULL ) {
177                         p = editor;
178                 } else {
179                         ++p;
180                 }
181                 printf("  Using %s as the editor...\n", p );
182 #ifndef HAVE_SPAWNLP
183                 sleep(2);
184 #endif
185         }
186 #ifdef HAVE_SPAWNLP
187         rc = _spawnlp( _P_WAIT, editor, editor, entry_temp_file, NULL );
188         if(rc != 0) {
189                 fatal("spawnlp");
190         }
191 #else
192         if ((pid = fork()) == 0) {      
193                 /* child - edit the Directory entry */
194                 (void) SIGNAL(SIGINT, SIG_IGN);
195                 (void) execlp(editor, editor, entry_temp_file, NULL);
196                 /*NOTREACHED*/
197                 (void) fatal(editor);   
198         }
199         else if (pid > 0) {
200                 /* parent - wait until the child proc is done editing */
201                 RETSIGTYPE (*handler)();
202                 handler = SIGNAL(SIGINT, SIG_IGN);
203                 (void) wait(&status);
204                 (void) SIGNAL(SIGINT, handler);
205         }
206         else {
207                 fatal("fork");
208                 /*NOTREACHED*/
209         }
210 #endif
211         return(0);
212 }
213
214 static int
215 print_attrs_and_values( FILE *fp, struct attribute *attrs, short int flag )
216 {
217         register int i, j;
218
219         for (i = 0; attrs[i].quipu_name != NULL; i++) {
220                 if (!modifiable(attrs[i].quipu_name,
221                         (short) (flag|ATTR_FLAG_MAY_EDIT)))
222                 {
223                         continue;
224                 }
225
226                 fprintf(fp, "%s\n", attrs[i].quipu_name);
227                 if ( attrs[i].number_of_values > MAX_VALUES ) {
228                         printf("  The %s attribute has more than %d values.\n",
229                                 attrs[i].quipu_name, MAX_VALUES );
230                         printf("  You cannot use the vedit command on this entry.  Sorry!\n" );
231                         return( -1 );
232                 }
233                 for (j = 0; j < attrs[i].number_of_values; j++)
234                         fprintf(fp, "\t%s\n", attrs[i].values[j]);
235         }
236         return( 0 );
237 }
238
239 static int
240 modifiable( char *s, short int flag )
241 {
242         register int i;
243
244         for (i = 0; attrlist[i].quipu_name != NULL; i++) {
245                 if (strcasecmp(s, attrlist[i].quipu_name))
246                         continue;
247                 if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
248                         return(FALSE);
249                 return(TRUE);
250         }
251         /* should never be here */
252         return(FALSE);
253 }
254
255 static void
256 write_entry( void )
257 {
258         int i = 0, j, number_of_values = -1;
259
260         FILE *fp;
261         char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
262
263         LDAPMod *mods[MAX_ATTRS + 1];
264         LDAPMod *modp = NULL;
265
266         /* parse the file and write the values to the Directory */
267         if ((fp = fopen(entry_temp_file, "r")) == NULL) {
268                 perror("fopen");
269                 return;
270         }
271         for (;;) {
272                 (void) fgets(line, sizeof(line), fp);
273                 if (feof(fp))
274                         break;
275                 line[strlen(line) - 1] = '\0';          /* kill newline */
276                 cp = line;
277                 if (*cp == '#')
278                         continue;
279                 if (isspace((unsigned char)*cp)) {      /* value */
280                         while (isspace((unsigned char)*cp))
281                                 cp++;
282                         values[number_of_values++] = strdup(cp);
283                         if ( number_of_values >= MAX_VALUES ) {
284                                 printf("  A maximum of %d values can be handled at one time.  Sorry!\n", MAX_VALUES );
285                                 return;
286                         }
287                         continue;
288                 }
289                 /* attribute */
290                 while (isspace((unsigned char)*cp))
291                         cp++;
292                 /*
293                  *  If the number of values is greater than zero, then we
294                  *  know that this is not the first time through this
295                  *  loop, and we also know that we have a little bit
296                  *  of work to do:
297                  *
298                  *      o The modify operation needs to be changed from
299                  *        a DELETE to a REPLACE
300                  *
301                  *      o The list of values pointer needs to be changed
302                  *        from NULL, to a NULL-terminated list of char
303                  *        pointers.
304                  */
305                 if (number_of_values > 0) {
306                         modp->mod_op = LDAP_MOD_REPLACE;
307                         if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
308                                 fatal("Malloc");
309                                 /*NOTREACHED*/
310                         }
311                         modp->mod_values = vp;
312                         for (j = 0; j < number_of_values; j++) {
313                                 *vp++ = strdup(values[j]);
314                                 (void) Free(values[j]);
315                         }
316                         *vp = NULL;
317                 }
318                 /*
319                  *  If there are no values, and there were no values to begin
320                  *  with, then there is nothing to do.
321                  */
322                 if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
323 #ifdef DEBUG
324                         if (debug & D_MODIFY)
325                                 printf(" %s has zero values - skipping\n",
326                                                 modp->mod_type);
327 #endif
328                         (void) Free(modp->mod_type);
329                         modp->mod_type = strdup(cp);
330                         modp->mod_op = LDAP_MOD_DELETE;
331                         modp->mod_values = NULL;
332                         continue;
333                 }
334                 /*
335                  *  Fetch a new modify structure.
336                  *
337                  *  Assume a DELETE operation with no values.
338                  */
339                 if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
340                         fatal("Malloc");
341                         /*NOTREACHED*/
342                 }
343                 modp->mod_values = NULL;
344                 modp->mod_type = strdup(cp);
345                 modp->mod_op = LDAP_MOD_DELETE;
346                 mods[i++] = modp;
347                 number_of_values = 0;
348         }
349         fclose(fp);
350
351         /* check the last one too */
352         if (number_of_values > 0) {
353                 modp->mod_op = LDAP_MOD_REPLACE;
354                 /*
355                  *  Fetch some value pointers.
356                  *
357                  *      number_of_values        To store the values
358                  *              1               For the NULL terminator
359                  *              1               In case we need it to store
360                  *                              the RDN as on of the values
361                  *                              of 'cn' in case it isn't there
362                  */
363                 if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
364                                                  2))) == (char **) NULL) {
365                         fatal("Malloc");
366                         /*NOTREACHED*/
367                 }
368                 modp->mod_values = vp;
369                 for (j = 0; j < number_of_values; j++) {
370                         *vp++ = strdup(values[j]);
371                         (void) Free(values[j]);
372                 }
373                 *vp = NULL;
374         }
375         else if ((number_of_values == 0) && 
376                                 (ovalues(mods[i - 1]->mod_type) == 0)) {
377 #ifdef DEBUG
378                 if (debug & D_MODIFY)
379                         printf(" %s has zero values - skipping\n",
380                                         mods[i - 1]->mod_type);
381 #endif
382                 Free(mods[i - 1]->mod_type);
383                 Free(mods[i - 1]);
384                 i--;
385         }
386         mods[i] = (LDAPMod *) NULL;
387
388         /* 
389          * If one of the mods pointers is 'cn', be sure that the RDN is one
390          * of the values.
391          */
392         for (j = 0; j < i; j++) {
393                 if (strcasecmp("cn", mods[j]->mod_type))
394                         continue;
395                 /*
396                  *  True only if there WERE values, but the person deleted
397                  *  them all.
398                  */
399                 if (mods[j]->mod_values == NULL) {
400                         mods[j]->mod_op = LDAP_MOD_REPLACE;
401                         if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
402                                 fatal("Malloc");
403                                 /*NOTREACHED*/
404                         }
405                         mods[j]->mod_values = vp;
406                         *vp++ = strdup(Entry.name);
407                         *vp = NULL;
408                         break;
409                 }
410                 /*
411                  *  Be sure that one of the values of 'cn' is the RDN.
412                  */
413                 for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
414                         if (strcasecmp(*vp, Entry.DN))
415                                 continue;
416                         break;
417                 }
418                 if (*vp == NULL) {
419                         *vp++ = strdup(Entry.name);
420                         *vp = NULL;
421                         break;
422                 }
423         }
424 #ifdef DEBUG
425         if (debug & D_MODIFY) {
426                 register int x, y;
427
428                 printf("  ld = 0x%x\n", ld);
429                 printf("  dn = [%s]\n", Entry.DN);
430                 for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
431                         printf("  mods[%d]->mod_op = %s\n", 
432                                         x, code_to_str(mods[x]->mod_op));
433                         printf("  mods[%d]->mod_type = %s\n", 
434                                                         x, mods[x]->mod_type);
435                         if (mods[x]->mod_values == NULL)
436                                 printf("  mods[%d]->mod_values = NULL\n", x);
437                         else {
438                                 for (y = 0; mods[x]->mod_values[y] != NULL; y++)
439                                    printf("  mods[%d]->mod_values[%1d] = %s\n", 
440                                                 x, y, mods[x]->mod_values[y]);
441                                 printf("  mods[%d]->mod_values[%1d] = NULL\n",
442                                                                         x, y);
443                         }
444                         printf("\n");
445                 }
446         }
447 #endif
448         if (ldap_modify_s(ld, Entry.DN, mods))
449                 mod_perror(ld);
450         else
451                 printf("  Modification complete.\n" );
452
453         /* clean up */
454         for (i = 0; mods[i] != NULL; i++)
455                 free_mod_struct(mods[i]);
456         return;
457 }
458
459 static int
460 ovalues( char *attr )
461 {
462         struct attribute *ap;
463
464         /*
465          *  Lookup the attribute with quipu_name 'attr' in the Entry
466          *  structure and return the number of values.
467          */
468         for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
469                 if (!strcasecmp(ap->quipu_name, attr))
470                         return(ap->number_of_values);
471         }
472         /* should never get to this point unless 'attr' was something odd */
473         return(0);
474 }