mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-24 08:39:37 -05:00
This could cause problems on odd systems. The generic headers should be extended as needed to include necessary system headers or, if necessary, make explicit declarations. Extended ac/string.h header to look for string.h/strings.h if STDC_HEADERS is not defined. Also provide basic declarations for str*() functions. This could cause problems on odd systems. Extended ac/unistd.h header to define basic declaration for misc functions that might be missing from headers. This includes externs for getenv(), getopt(), mktemp(), tempname(). Protect fax500.h from multiple inclusion. Moved includes of system/generic headers back to source files. Made mail500 helper functions static. Fixed includes of ctype.h, signal.h, etc. to use generics. lutil/tempname.c: was including stdlib.h twice, one should stdio.h. Wrapped <sys/resource.h> with HAVE_SYS_RESOURCE_H. lber/io.c/ber_get_next(): Changed noctets back to signed. Used with BerRead which expects signed int as second arg and returns signed int.
457 lines
11 KiB
C
457 lines
11 KiB
C
/*
|
|
* Copyright (c) 1994 Regents of the University of Michigan.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this notice is preserved and that due credit is given
|
|
* to the University of Michigan at Ann Arbor. The name of the University
|
|
* may not be used to endorse or promote products derived from this
|
|
* software without specific prior written permission. This software
|
|
* is provided ``as is'' without express or implied warranty.
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <ac/signal.h>
|
|
#include <ac/string.h>
|
|
#include <ac/ctype.h>
|
|
#include <ac/time.h>
|
|
#include <ac/wait.h>
|
|
#include <ac/unistd.h>
|
|
|
|
#ifdef HAVE_SYS_RESOURCE_H
|
|
#include <sys/resource.h>
|
|
#endif
|
|
#ifdef HAVE_PROCESS_H
|
|
#include <process.h>
|
|
#endif
|
|
|
|
#include <lber.h>
|
|
#include <ldap.h>
|
|
#include <ldapconfig.h>
|
|
#include "ud.h"
|
|
|
|
static int load_editor( void );
|
|
static int modifiable( char *s, short flag );
|
|
static int print_attrs_and_values( FILE *fp, struct attribute *attrs, short flag );
|
|
static int ovalues( char *attr );
|
|
static void write_entry( void );
|
|
|
|
static char *entry_temp_file;
|
|
|
|
|
|
void
|
|
edit( char *who )
|
|
{
|
|
LDAPMessage *mp; /* returned from find() */
|
|
char *dn, **rdns; /* distinguished name */
|
|
char name[MED_BUF_SIZE]; /* entry to modify */
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->edit(%s)\n", who);
|
|
#endif
|
|
/*
|
|
* One must be bound in order to edit an entry.
|
|
*/
|
|
if (bind_status == UD_NOT_BOUND) {
|
|
if (auth((char *) NULL, 1) < 0)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* First, decide what entry we are going to modify. If the
|
|
* user has not included a name on the modify command line,
|
|
* we will use the person who was last looked up with a find
|
|
* command. If there is no value there either, we don't know
|
|
* who to modify.
|
|
*
|
|
* Once we know who to modify, be sure that they exist, and
|
|
* parse out their DN.
|
|
*/
|
|
if (who == NULL) {
|
|
if (verbose) {
|
|
printf(" Enter the name of the person or\n");
|
|
printf(" group whose entry you want to edit: ");
|
|
}
|
|
else
|
|
printf(" Edit whose entry? ");
|
|
fflush(stdout);
|
|
fetch_buffer(name, sizeof(name), stdin);
|
|
if (name[0] != '\0')
|
|
who = name;
|
|
else
|
|
return;
|
|
}
|
|
if ((mp = find(who, TRUE)) == NULL) {
|
|
(void) ldap_msgfree(mp);
|
|
printf(" Could not locate \"%s\" in the Directory.\n", who);
|
|
return;
|
|
}
|
|
dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
|
|
rdns = ldap_explode_dn(dn, TRUE);
|
|
Free(dn);
|
|
if (verbose) {
|
|
printf("\n Editing directory entry \"%s\"...\n", *rdns);
|
|
}
|
|
parse_answer(mp);
|
|
(void) ldap_msgfree(mp);
|
|
(void) ldap_value_free(rdns);
|
|
if (load_editor() < 0)
|
|
return;
|
|
write_entry();
|
|
(void) unlink(entry_temp_file);
|
|
ldap_uncache_entry(ld, Entry.DN);
|
|
return;
|
|
}
|
|
|
|
static int
|
|
load_editor( void )
|
|
{
|
|
FILE *fp;
|
|
char *cp, *editor = UD_DEFAULT_EDITOR;
|
|
static char template[MED_BUF_SIZE];
|
|
int pid;
|
|
int status;
|
|
int rc;
|
|
void (*handler)();
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->load_editor()\n");
|
|
#endif
|
|
|
|
/* write the entry into a temp file */
|
|
(void) strcpy(template, "/tmp/udEdit.XXXXXX");
|
|
if ((entry_temp_file = mktemp(template)) == NULL) {
|
|
perror("mktemp");
|
|
return(-1);
|
|
}
|
|
if ((fp = fopen(entry_temp_file, "w")) == NULL) {
|
|
perror("fopen");
|
|
return(-1);
|
|
}
|
|
fprintf(fp, "## Directory entry of %s\n", Entry.name);
|
|
fprintf(fp, "##\n");
|
|
fprintf(fp, "## Syntax is:\n");
|
|
fprintf(fp, "## <attribute-name>\n");
|
|
fprintf(fp, "## <TAB> <value 1>\n");
|
|
fprintf(fp, "## <TAB> : :\n");
|
|
fprintf(fp, "## <TAB> <value N>\n");
|
|
fprintf(fp, "## Lines beginning with a hash mark are comments.\n");
|
|
fprintf(fp, "##\n");
|
|
fflush(fp);
|
|
if (isgroup())
|
|
rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_GROUP_MOD);
|
|
else
|
|
rc = print_attrs_and_values(fp, Entry.attrs, ATTR_FLAG_PERSON_MOD);
|
|
fclose(fp);
|
|
|
|
if ( rc != 0 ) {
|
|
(void) unlink(entry_temp_file);
|
|
return( rc );
|
|
}
|
|
|
|
/* edit the temp file with the editor of choice */
|
|
if ((cp = getenv("EDITOR")) != NULL)
|
|
editor = cp;
|
|
if (verbose) {
|
|
char *p;
|
|
|
|
if (( p = strrchr( editor, '/' )) == NULL ) {
|
|
p = editor;
|
|
} else {
|
|
++p;
|
|
}
|
|
printf(" Using %s as the editor...\n", p );
|
|
#ifndef HAVE_SPAWNLP
|
|
sleep(2);
|
|
#endif
|
|
}
|
|
#ifdef HAVE_SPAWNLP
|
|
rc = _spawnlp( _P_WAIT, editor, editor, entry_temp_file, NULL );
|
|
if(rc != 0) {
|
|
fatal("spawnlp");
|
|
}
|
|
#else
|
|
if ((pid = fork()) == 0) {
|
|
/* child - edit the Directory entry */
|
|
(void) SIGNAL(SIGINT, SIG_IGN);
|
|
(void) execlp(editor, editor, entry_temp_file, NULL);
|
|
/*NOTREACHED*/
|
|
(void) fatal(editor);
|
|
}
|
|
else if (pid > 0) {
|
|
/* parent - wait until the child proc is done editing */
|
|
handler = SIGNAL(SIGINT, SIG_IGN);
|
|
(void) wait(&status);
|
|
(void) SIGNAL(SIGINT, handler);
|
|
}
|
|
else {
|
|
fatal("fork");
|
|
/*NOTREACHED*/
|
|
}
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
print_attrs_and_values( FILE *fp, struct attribute *attrs, short int flag )
|
|
{
|
|
register int i, j;
|
|
|
|
for (i = 0; attrs[i].quipu_name != NULL; i++) {
|
|
if (!modifiable(attrs[i].quipu_name, flag|ATTR_FLAG_MAY_EDIT))
|
|
continue;
|
|
fprintf(fp, "%s\n", attrs[i].quipu_name);
|
|
if ( attrs[i].number_of_values > MAX_VALUES ) {
|
|
printf(" The %s attribute has more than %d values.\n",
|
|
attrs[i].quipu_name, MAX_VALUES );
|
|
printf(" You cannot use the vedit command on this entry. Sorry!\n" );
|
|
return( -1 );
|
|
}
|
|
for (j = 0; j < attrs[i].number_of_values; j++)
|
|
fprintf(fp, "\t%s\n", attrs[i].values[j]);
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
modifiable( char *s, short int flag )
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
|
|
if (strcasecmp(s, attrlist[i].quipu_name))
|
|
continue;
|
|
if ((attrlist[i].flags & flag) == ATTR_FLAG_NONE)
|
|
return(FALSE);
|
|
return(TRUE);
|
|
}
|
|
/* should never be here */
|
|
return(FALSE);
|
|
}
|
|
|
|
static void
|
|
write_entry( void )
|
|
{
|
|
int i = 0, j, number_of_values = -1;
|
|
|
|
FILE *fp;
|
|
char *cp, line[LARGE_BUF_SIZE], *values[MAX_VALUES], **vp;
|
|
|
|
LDAPMod *mods[MAX_ATTRS + 1];
|
|
LDAPMod *modp = NULL;
|
|
|
|
/* parse the file and write the values to the Directory */
|
|
if ((fp = fopen(entry_temp_file, "r")) == NULL) {
|
|
perror("fopen");
|
|
return;
|
|
}
|
|
for (;;) {
|
|
(void) fgets(line, sizeof(line), fp);
|
|
if (feof(fp))
|
|
break;
|
|
line[strlen(line) - 1] = '\0'; /* kill newline */
|
|
cp = line;
|
|
if (*cp == '#')
|
|
continue;
|
|
if (isspace(*cp)) { /* value */
|
|
while (isspace(*cp))
|
|
cp++;
|
|
values[number_of_values++] = strdup(cp);
|
|
if ( number_of_values >= MAX_VALUES ) {
|
|
printf(" A maximum of %d values can be handled at one time. Sorry!\n", MAX_VALUES );
|
|
return;
|
|
}
|
|
continue;
|
|
}
|
|
/* attribute */
|
|
while (isspace(*cp))
|
|
cp++;
|
|
/*
|
|
* If the number of values is greater than zero, then we
|
|
* know that this is not the first time through this
|
|
* loop, and we also know that we have a little bit
|
|
* of work to do:
|
|
*
|
|
* o The modify operation needs to be changed from
|
|
* a DELETE to a REPLACE
|
|
*
|
|
* o The list of values pointer needs to be changed
|
|
* from NULL, to a NULL-terminated list of char
|
|
* pointers.
|
|
*/
|
|
if (number_of_values > 0) {
|
|
modp->mod_op = LDAP_MOD_REPLACE;
|
|
if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values + 2))) == (char **) NULL) {
|
|
fatal("Malloc");
|
|
/*NOTREACHED*/
|
|
}
|
|
modp->mod_values = vp;
|
|
for (j = 0; j < number_of_values; j++) {
|
|
*vp++ = strdup(values[j]);
|
|
(void) Free(values[j]);
|
|
}
|
|
*vp = NULL;
|
|
}
|
|
/*
|
|
* If there are no values, and there were no values to begin
|
|
* with, then there is nothing to do.
|
|
*/
|
|
if ((number_of_values == 0) && (ovalues(modp->mod_type) == 0)) {
|
|
#ifdef DEBUG
|
|
if (debug & D_MODIFY)
|
|
printf(" %s has zero values - skipping\n",
|
|
modp->mod_type);
|
|
#endif
|
|
(void) Free(modp->mod_type);
|
|
modp->mod_type = strdup(cp);
|
|
modp->mod_op = LDAP_MOD_DELETE;
|
|
modp->mod_values = NULL;
|
|
continue;
|
|
}
|
|
/*
|
|
* Fetch a new modify structure.
|
|
*
|
|
* Assume a DELETE operation with no values.
|
|
*/
|
|
if ((modp = (LDAPMod *) Malloc(sizeof(LDAPMod))) == NULL) {
|
|
fatal("Malloc");
|
|
/*NOTREACHED*/
|
|
}
|
|
modp->mod_values = NULL;
|
|
modp->mod_type = strdup(cp);
|
|
modp->mod_op = LDAP_MOD_DELETE;
|
|
mods[i++] = modp;
|
|
number_of_values = 0;
|
|
}
|
|
fclose(fp);
|
|
|
|
/* check the last one too */
|
|
if (number_of_values > 0) {
|
|
modp->mod_op = LDAP_MOD_REPLACE;
|
|
/*
|
|
* Fetch some value pointers.
|
|
*
|
|
* number_of_values To store the values
|
|
* 1 For the NULL terminator
|
|
* 1 In case we need it to store
|
|
* the RDN as on of the values
|
|
* of 'cn' in case it isn't there
|
|
*/
|
|
if ((vp = (char **) Malloc(sizeof(char *) * (number_of_values +
|
|
2))) == (char **) NULL) {
|
|
fatal("Malloc");
|
|
/*NOTREACHED*/
|
|
}
|
|
modp->mod_values = vp;
|
|
for (j = 0; j < number_of_values; j++) {
|
|
*vp++ = strdup(values[j]);
|
|
(void) Free(values[j]);
|
|
}
|
|
*vp = NULL;
|
|
}
|
|
else if ((number_of_values == 0) &&
|
|
(ovalues(mods[i - 1]->mod_type) == 0)) {
|
|
#ifdef DEBUG
|
|
if (debug & D_MODIFY)
|
|
printf(" %s has zero values - skipping\n",
|
|
mods[i - 1]->mod_type);
|
|
#endif
|
|
Free(mods[i - 1]->mod_type);
|
|
Free(mods[i - 1]);
|
|
i--;
|
|
}
|
|
mods[i] = (LDAPMod *) NULL;
|
|
|
|
/*
|
|
* If one of the mods pointers is 'cn', be sure that the RDN is one
|
|
* of the values.
|
|
*/
|
|
for (j = 0; j < i; j++) {
|
|
if (strcasecmp("cn", mods[j]->mod_type))
|
|
continue;
|
|
/*
|
|
* True only if there WERE values, but the person deleted
|
|
* them all.
|
|
*/
|
|
if (mods[j]->mod_values == NULL) {
|
|
mods[j]->mod_op = LDAP_MOD_REPLACE;
|
|
if ((vp = (char **) Malloc(sizeof(char *) * 2)) == (char **) NULL) {
|
|
fatal("Malloc");
|
|
/*NOTREACHED*/
|
|
}
|
|
mods[j]->mod_values = vp;
|
|
*vp++ = strdup(Entry.name);
|
|
*vp = NULL;
|
|
break;
|
|
}
|
|
/*
|
|
* Be sure that one of the values of 'cn' is the RDN.
|
|
*/
|
|
for (vp = mods[j]->mod_values; *vp != NULL; vp++) {
|
|
if (strcasecmp(*vp, Entry.DN))
|
|
continue;
|
|
break;
|
|
}
|
|
if (*vp == NULL) {
|
|
*vp++ = strdup(Entry.name);
|
|
*vp = NULL;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug & D_MODIFY) {
|
|
register int x, y;
|
|
|
|
printf(" ld = 0x%x\n", ld);
|
|
printf(" dn = [%s]\n", Entry.DN);
|
|
for (x = 0; mods[x] != (LDAPMod *) NULL; x++) {
|
|
printf(" mods[%d]->mod_op = %s\n",
|
|
x, code_to_str(mods[x]->mod_op));
|
|
printf(" mods[%d]->mod_type = %s\n",
|
|
x, mods[x]->mod_type);
|
|
if (mods[x]->mod_values == NULL)
|
|
printf(" mods[%d]->mod_values = NULL\n", x);
|
|
else {
|
|
for (y = 0; mods[x]->mod_values[y] != NULL; y++)
|
|
printf(" mods[%d]->mod_values[%1d] = %s\n",
|
|
x, y, mods[x]->mod_values[y]);
|
|
printf(" mods[%d]->mod_values[%1d] = NULL\n",
|
|
x, y);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
if (ldap_modify_s(ld, Entry.DN, mods))
|
|
mod_perror(ld);
|
|
else
|
|
printf(" Modification complete.\n" );
|
|
|
|
/* clean up */
|
|
for (i = 0; mods[i] != NULL; i++)
|
|
free_mod_struct(mods[i]);
|
|
return;
|
|
}
|
|
|
|
static int
|
|
ovalues( char *attr )
|
|
{
|
|
struct attribute *ap;
|
|
|
|
/*
|
|
* Lookup the attribute with quipu_name 'attr' in the Entry
|
|
* structure and return the number of values.
|
|
*/
|
|
for (ap = Entry.attrs; ap->quipu_name != NULL; ap++) {
|
|
if (!strcasecmp(ap->quipu_name, attr))
|
|
return(ap->number_of_values);
|
|
}
|
|
/* should never get to this point unless 'attr' was something odd */
|
|
return(0);
|
|
}
|