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