DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦ac05b6944⟧ TextFile

    Length: 27823 (0x6caf)
    Types: TextFile
    Names: »dsaconfig.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/others/quipu/tools/dsaconfig/dsaconfig.c« 

TextFile

/* dsaconfig.c - build a database directory for a Level-1 DSA */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/others/quipu/tools/dsaconfig/RCS/dsaconfig.c,v 7.2 90/01/11 18:36:09 mrose Exp $";
#endif

/* 
 * $Header: /f/osi/others/quipu/tools/dsaconfig/RCS/dsaconfig.c,v 7.2 90/01/11 18:36:09 mrose Exp $
 *
 *
 * $Log:	dsaconfig.c,v $
 * Revision 7.2  90/01/11  18:36:09  mrose
 * real-sync
 * 
 * Revision 7.1  89/12/06  17:30:24  mrose
 * update
 * 
 * Revision 7.0  89/11/23  22:02:38  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <varargs.h>
#include "general.h"
#include "manifest.h"
#include "internet.h"
#include "psap.h"
#include "tailor.h"


#ifdef	SYS5
struct group *getgrnam ();
struct passwd *getpwnam (), *getpwuid ();
#endif

/* \f

   DATA */

static int debug =0;

static int uid = 0;
static int gid = 0;

static char *myname = "dsaconfig";

static char *wildlife = NULL;
static char sedfil[BUFSIZ];


void	adios (), advise ();
char   *version ();


extern int errno;

extern char  *quipuversion;

/* \f

   MAIN */

/* ARGSUSED */

main (argc, argv, envp)
int	argc;
char  **argv,
      **envp;
{
    char    buffer[BUFSIZ];

    arginit (argv);
    if (access (wildlife, 0x00) != NOTOK)
	adios (NULLCP, "%s already exists, choose a different name", wildlife);

    read_config ();
    generate_sed ();

    build_root ();
    build_TLC ();
    build_organization ();
    build_unit ();

    build_tailor ();
    build_startup ();
    build_nightly ();

    build_dsap ();
    build_fred ();

#ifndef	SYS5
    (void) sprintf (buffer, "find %s -exec /etc/chown %d {} \\;",
		    wildlife, uid);
#else
    (void) sprintf (buffer, "find %s -exec chown %d {} \\;", wildlife, uid);
#endif
    if (debug)
	fprintf (stderr, "%s\n", buffer);
    (void) system (buffer);

    (void) sprintf (buffer, "find %s -exec chgrp %d {} \\;",
		    wildlife, gid);
    if (debug)
	fprintf (stderr, "%s\n", buffer);
    (void) system (buffer);

    (void) unlink (sedfil);

    exit (0);
}

/* \f

   CONFIG */

struct country {
    char   *c_code;
    int	    c_number;
    char   *c_name;

    char   *c_root;
    char   *c_master;
    char   *c_other;
    
    char   *c_phone;

    int	    c_flags;
#define	C_SHORT	0x01
};

struct country *read_country ();

/* \f

 */

struct pair {
    char   *p_name;
    char   *p_value;

    int	    p_flags;
#define	P_NULL	0x00
#define	P_OPT	0x01
#define	P_MBOX	0x02
#define	P_XXX	0x04
#define	P_ZAP	0x08
#define	P_POST	0x10
};

static struct pair pairs[] = {
    "dsa", NULL,			/* Spectacled Bear */
	P_NULL,

    "country", NULL,			/* US */
        P_OPT,
    "organization", NULL,		/* NYSERNet, Inc. */
	P_NULL,
    "domain", NULL,			/* nyser.net */
        P_NULL,
    "unit", NULL,			/* Research and Development */
	P_NULL,
    "street", NULL,			/* 165 Jordan Road */
	P_OPT,
    "pob", NULL,			/* 1234 */
	P_OPT,
    "town", NULL,			/* Troy */
	P_NULL,
    "state", NULL,			/* New York */
	P_NULL,
    "zipcode", NULL,			/* 12180 */
	P_NULL,
    "locality", NULL,			/* Troy, New York */
        P_OPT,
    "postaladdress", NULL,		/* org $ address */
	P_OPT | P_POST,

    "telephone", NULL,			/* +1 518-283-8860 */
	P_NULL,
    "fax", NULL,			/* +1 518-283-8904 */
	P_OPT,

    "description", NULL,		/* not-for-profit ... */
	P_NULL,

    "ipaddr", NULL,			/* 127.0.0.1 */
        P_OPT,
    "port", NULL,			/* 17003 */
        P_OPT,

    "firstname", NULL,			/* Marshall */
	P_NULL,
    "lastname", NULL,			/* Rose */
	P_NULL,
    "middleinitial", NULL,		/* T */
	P_OPT,
    "middlename", NULL,			/* Txxx */
	P_OPT,
    "mailbox", NULL,			/* mrose@nisc.nyser.net */
	P_MBOX,
    "title", NULL,			/* Senior Scientist */
	P_NULL,
    "userid", NULL,			/* mrose */
	P_OPT,
    "groupid", NULL,			/* whitepages */
	P_OPT,
    "password", NULL,			/* secret */
	P_NULL,
    "extension", NULL,			/* +1 518-283-8860 */
	P_OPT,

    "wildlife", NULL,			/* spectacled-bear */
       P_XXX,
    "bindir", NULL,			/* /usr/local/bin/ */
        P_XXX,
    "sbindir", NULL,			/* /usr/etc/ */
        P_XXX,
    "etcdir", NULL,			/* /usr/etc/ */
        P_XXX,
    "quipuversion", NULL,		/* from -lquipu */
        P_XXX,
    "rootDSA", NULL,			/* root upstream */
        P_XXX,
    "countryDSA", NULL,			/* country upstream */
        P_XXX,
    "otherDSA", NULL,			/* hack... */
	P_XXX,
    "rootDSAaddress", NULL,		/* PSAP of root upstream */
        P_XXX,
    "countryDSAaddress", NULL,		/* PSAP of country upstream */
        P_XXX,
    "otherDSAaddress", NULL,		/* PSAP of hack... */
	P_XXX,

    NULL
};

struct pair *n2p ();

/* \f

 */

static read_config () {
    int	    lineno;
    register char *cp,
		  *dp;
    char    buffer[BUFSIZ],
	    file[BUFSIZ],
	    line[BUFSIZ],
	   *vec[NVEC + 1];
    FILE   *fp;
    register struct country *c;
    register struct pair *p,
			 *q;
    register struct hostent *hp;
    struct sockaddr_in in_socket;
    register struct sockaddr_in *isock = &in_socket;

    (void) sprintf (file, "%s.dsa", wildlife);
    if ((fp = fopen (file, "r")) == NULL)
	adios (file, "unable to read");

    for (lineno = 1; fgets (buffer, sizeof buffer, fp); lineno++) {
	if (*buffer == '#')
	    continue;
	if (cp = index (buffer, '\n'))
	    *cp = NULL;
	(void) strcpy (line, buffer);

	bzero ((char *) vec, sizeof vec);
	switch (str2vec (buffer, vec)) {
	    case 0:
	        continue;

	    case 1:
		for (p = pairs; p -> p_name; p++)
		    if (strcmp (p -> p_name, vec[0]) == 0)
			break;
		if (!p -> p_name || (p -> p_flags & P_XXX))
		    adios (NULLCP, "unknown variable \"%s\"", vec[0]);
	        continue;

	    case 2:
		break;

	    default:
		adios (NULLCP, "syntax error on line %d:\n%s", lineno, line);
		/* NOTREACHED */
	}

	for (p = pairs; p -> p_name; p++)
	    if (strcmp (p -> p_name, vec[0]) == 0)
		break;
	if (!p -> p_name || (p -> p_flags & P_XXX))
	    adios (NULLCP, "unknown variable \"%s\"", vec[0]);
	if (p -> p_value)
	    adios (NULLCP, "multiple values for \"%s\" starting at line %d",
		   p -> p_name, lineno);

	if (p -> p_flags & P_MBOX) {
	    for (cp = vec[1]; *cp; cp++)
		if (!isascii (*cp) || *cp == '$' || *cp == '&') {
illegal: ;
		    adios (NULLCP,
			   "illegal character %c (0%o) in value for \"%s\"",
			   *cp, *cp & 0xff, p -> p_name);
		}
	}
	else
	    for (cp = vec[1]; *cp; cp++) {
		if (isalpha (*cp) || isdigit (*cp))
		    continue;
		switch (*cp) {
		    case 047: /* ' */
		    case '(':
		    case ')':
		    case '+':
		    case ',':
		    case '-':
		    case '.':
		    case '/':
		    case ':':
		    case '?':
		    case ' ':
			continue;

		    default:
			if ((p -> p_flags & P_POST) && *cp == '$')
			    continue;
			goto illegal;
		}
	    }

	p -> p_value = strdup (vec[1]);
    }

    if (ferror (fp) && !feof (fp))
	adios (file, "error reading");
    (void) fclose (fp);

    for (p = pairs; p -> p_name; p++)
	if (!p -> p_value && !(p -> p_flags & (P_OPT | P_XXX)))
	    adios (NULLCP, "missing value for \"%s\"", p -> p_name);

    if (n2p ("country", 0) == NULL)
	n2p ("country", 1) -> p_value = strdup ("US");

    if ((c = read_country (cp = n2p ("country", 1) -> p_value)) == NULL)
	adios (NULLCP, "unknown country code \"%s\"", cp);
    n2p ("rootDSA", 1) -> p_value =
			    strdup (c -> c_root ? c -> c_root : c -> c_master);
    if (c -> c_root)
	read_psap (c -> c_root, &(n2p ("rootDSAaddress", 1) -> p_value));
    n2p ("countryDSA", 1) -> p_value = strdup (c -> c_master);
    read_psap (c -> c_master, &(n2p ("countryDSAaddress", 1) -> p_value));
    if (c -> c_other) {
	n2p ("otherDSA", 1) -> p_value = strdup (c -> c_other);
	read_psap (c -> c_other, &(n2p ("otherDSAaddress", 1) -> p_value));
    }

    if (n2p ("postaladdress", 0) == NULL
	    && n2p ("street", 0) == NULL
	    && n2p ("pob", 0) == NULL)
	adios (NULLCP, "must specify either \"street\" or \"pob\"");

    if ((p = n2p ("locality", 1)) -> p_value == NULL) {
	(void) sprintf (buffer, "%s, %s", n2p ("town", 1) -> p_value,
			n2p ("state", 1) -> p_value);

	p -> p_value = strdup (buffer);

	if (debug)
	    printf ("setting locality to \"%s\"\n", p -> p_value);
    }
    
    if (*(p = n2p ("telephone", 1)) -> p_value != '+') {
	(void) sprintf (buffer, "+%s %s", c -> c_phone, p -> p_value);
	free (p -> p_value);
	p -> p_value = strdup (buffer);

	if (debug)
	    printf ("setting telephone number to \"%s\"\n", p -> p_value);
    }

    if ((p = n2p ("fax", 0)) && *p -> p_value != '+') {
	(void) sprintf (buffer, "+%s %s", c -> c_phone, p -> p_value);
	free (p -> p_value);
	p -> p_value = strdup (buffer);

	if (debug)
	    printf ("setting fax number to \"%s\"\n", p -> p_value);
    }

    if ((p = n2p ("ipaddr", 1)) -> p_value == NULL) {
	if ((hp = gethostbyname (cp = getlocalhost ())) == NULL)
	    adios (NULLCP, "%s: unknown host", cp);
    }
    else {
	if ((hp = gethostbystring (p -> p_value)) == NULL)
	    adios (NULLCP, "%s: unknown host", p -> p_value);
    }
    bzero ((char *) isock, sizeof *isock);
    isock -> sin_family = hp -> h_addrtype;
    inaddr_copy (hp, isock);
    p -> p_value = strdup (inet_ntoa (isock -> sin_addr));
    if (debug)
	printf ("setting IP address of DSA to \"%s\"\n", p -> p_value);

    if ((p = n2p ("port", 1)) -> p_value == NULL) {
	p -> p_value = strdup ("17003");

	if (debug)
	    printf ("setting TCP port of DSA to \"%s\"\n", p -> p_value);
    }

    if ((p = n2p ("middlename", 1)) -> p_value
	    && (q = n2p ("middleinitial", 1)) -> p_value == NULL) {
	(void) sprintf (buffer, "%c", *p -> p_value);
	p -> p_value = strdup (buffer);

	if (debug)
	    printf ("setting MiddleInitial to \"%s\"\n", p -> p_value);
    }

    uid = getuid (), gid = getgid ();
    if ((p = n2p ("userid", 1)) -> p_value) {
	register struct passwd *pw = getpwnam (p -> p_value);

	if (pw == NULL)
	    adios (NULLCP, "unknown user name \"%s\"", p -> p_value);
	uid = pw -> pw_uid, gid = pw -> pw_gid;
    }
    else {
	register struct passwd *pw = getpwuid (uid);

	if (pw == NULL)
	    adios (NULLCP, "unknown user name \"%s\"", p -> p_value);
	p -> p_value = strdup (pw -> pw_name);

	if (debug)
	    printf ("setting userid to \"%s\"\n", p -> p_value);
    }

    if (p = n2p ("groupid", 0)) {
	register struct group *gr = getgrnam (p -> p_value);

	if (gr == NULL)
	    adios (NULLCP, "unknown group name \"%s\"", p -> p_value);
	gid = gr -> gr_gid;
    }

    p = n2p ("extension", 1), q = n2p ("telephone", 1);
    if (cp = p -> p_value) {
	if (*cp == 'X' || *cp == 'x') {
	    (void) sprintf (buffer, "%s x%s", q -> p_value, p -> p_value);
	    free (p -> p_value);
	    p -> p_value = strdup (buffer);

	    if (debug)
		printf ("setting user's telephone number to \"%s\"\n",
			p -> p_value);
	}
    }
    else {
	p -> p_value = strdup (q -> p_value);

	if (debug)
	    printf ("setting user telephone number to \"%s\"\n", p -> p_value);
    }

    n2p ("wildlife", 1) -> p_value = strdup (wildlife);
    n2p ("bindir", 1) -> p_value = strdup (isodebinpath);
    n2p ("sbindir", 1) -> p_value = strdup (isodesbinpath);
    n2p ("etcdir", 1) -> p_value = strdup (isodetcpath);
    n2p ("quipuversion", 1) -> p_value = strdup (quipuversion);

    if (dp = (p = n2p ("postaladdress", 1)) -> p_value) {
	int	i;

	for (i = 1; cp = index (dp, '$'); dp = cp + 1, i++) {
	    *cp = NULL;
	    if (strlen (dp) > 30)
		goto too_long;
	    *cp = '$';
	}
	if (strlen (dp) > 30) {
too_long: ;
	    adios (NULLCP,
		   "item %d is too long (30 characters maximum): \"%s\"", i,
		   dp);
	}
	if (i > 6)
	    adios (NULLCP, "too many items (%d) in postalAddress, 6 maximum",
		   i);
    }
    else {
	int	i;

	cp = buffer;

	(void) sprintf (cp, "%s $ ", n2p ("organization", 1) -> p_value);
	if ((i = strlen (cp)) > 30 + 3) {
	    advise (NULLCP,
		    "your organization name is longer than 30 characters!");
postal_problem: ;
	    adios (NULLCP,
          "You must explicitly define the postalAddress attribute in the\n\
           configuration file for your Level-1 DSA.\n\
\n\
           The format is:\n\
\n\
               postaladdress \"item1 $ item2 $ ... $ itemN\"\n\
\n\
           where each item is <= 30 characters in length and there are no\n\
           more than six items.  Refer to the Administrator's Guide for more\n\
           information.\n\
");
	}
	cp += i;

	if (q = n2p ("pob", 0)) {
	    (void) sprintf (cp, "POB %s $ ", q -> p_value);
	    if ((i = strlen (cp)) > 30 + 3) {
		advise (NULLCP, "your POB is longer than 26 characters!");
		goto postal_problem;
	    }
	    cp += i;
	}
	else
	    if (q = n2p ("street", 0)) {
		(void) sprintf (cp, "%s $ ", q -> p_value);
		if ((i = strlen (cp)) > 30 + 3) {
		    advise (NULLCP,
			"your street address is longer than 30 characters!");
		    goto postal_problem;
		}
		cp += i;

		q -> p_flags |= P_ZAP;
	    }

	(void) sprintf (cp, "%s, %s %s $ ",
			n2p ("town", 1) -> p_value,
			n2p ("state", 1) -> p_value,
			n2p ("zipcode", 1) -> p_value);
	if ((i = strlen (cp)) > 30 + 3) {
	    advise (NULLCP,
		    "your town/state/zipcode is longer than 30 characters!");
	    goto postal_problem;
	}
	cp += i;

	if ((c -> c_flags & C_SHORT) || (i = strlen (dp = c -> c_name)) > 30)
	    i = strlen (dp = c -> c_code);
	(void) strcpy (cp, dp);
	cp += i;

	p -> p_value = strdup (buffer);
    }
}

/* \f

 */

static struct country *read_country (code)
char   *code;
{
    int	    vecp;
    register char *cp,
		  *dp;
    char    d,
	   *ep,
	    buffer[BUFSIZ + 1],
	    file[BUFSIZ],
	   *vec[NVEC + NSLACK + 1];
    FILE   *fp;
    static struct country cs;
    register struct country *c = NULL;

    (void) strcpy (file, "iso3166");
    if ((fp = fopen (file, "r")) == NULL)
	adios (file, "unable to open");

    ep = (dp = buffer) + sizeof buffer;
    while (fgets (dp, ep - dp, fp)) {
	if (*buffer == '#')
	    continue;
	if (cp = index (buffer, '\n')) {
	    *cp = NULL;
	    if ((d = getc (fp)) != EOF)
		(void) ungetc (d, fp);
	    switch (d) {
		case '#':
		case '\n':
		case EOF:
		    break;

		default:
		    *cp++ = ' ';
		    if ((dp = cp) + 1 >= ep) {
			*ep = NULL;
			adios (NULLCP,
			       "virtual line too long in %s: \"%s\"",
			       file, cp);
		    }
		    continue;
	    }
	}

	dp = buffer;
	switch (vecp = str2vec (buffer, vec)) {
	    case 7:		/* standard entry */
	    case 8:
	        if (strcmp (vec[0], code))
		    continue;
		c = &cs;
		bzero ((char *) c, sizeof *c);
		c -> c_code = strdup (vec[0]);
		if (sscanf (vec[1], "%d", &c -> c_number) != 1)
		    adios (NULLCP,
			   "malformed ISO3166 number for country %s in %s",
			   code, file);
		c -> c_number = atoi (vec[1]);
		c -> c_name = strdup (vec[2]);
		if (strcmp (vec[3], "NULL"))
		    c -> c_root = strdup (vec[3]);
		if (strcmp (vec[4], "NULL"))
		    c -> c_master = strdup (vec[4]);
		else
		    adios (NULLCP, "no masterDSA known for country %s in %s",
			   code,file);
		if (strcmp (vec[5], "NULL"))
		    c -> c_other = strdup (vec[5]);
		c -> c_phone = strdup (vec[6]);
		if (vecp == 8) {
		    char   *bp;

		    if (strncmp (cp = vec[7], "0x", 2) == 0)
			cp += 2, bp = "%x";
		    else
			if (*cp == '0')
			    cp += 1, bp = "%o";
		        else
			    bp = "%d";
		    if (sscanf (cp, bp, &c -> c_flags) != 1)
			adios (NULLCP,
			      "malformed entry for country %s in %s",
			       code, file);
		}
		break;

	    default:
	        continue;
	}
	break;
    }

    (void) fclose (fp);

    return c;
}

/* \f

 */

static	read_psap (dsa, addr)
char   *dsa,
     **addr;
{
    int	    i;
    register char *cp,
		  *dp;
    char    buffer[BUFSIZ],
	    stuff[BUFSIZ];
    FILE   *fp;

    if ((fp = fopen (cp = isodefile ("dsaptailor", 0), "r")) == NULL)
	adios (cp, "unable to open");

    while (fgets (buffer, sizeof buffer, fp)) {
	if (lexnequ (buffer, "dsa_address", sizeof "dsa_address" - 1)
	        || (cp = index (buffer, '"')) == NULL
	        || lexnequ (++cp, dsa + 3, i = strlen (dsa + 3))
	        || *(cp += i ) != '"')
	    continue;
	for (cp++; isspace (*cp); cp++)
	    continue;
	if (*cp == NULL) {
malformed: ;
	    adios (NULLCP, "malformed entry in dsaptailor for DSA %s", dsa);
	}
	for (dp = stuff; *cp; *dp++ = *cp++) {
	    switch (*cp) {
		case '\n':
		    break;

		case '\'':
		    *dp++ = '\\';
		    /* and fall... */
		case '\\':
		    *dp++ = '\\';
		    continue;

		default:
		    continue;
	    }
	    break;
	}
	*dp = NULL;
	if (*cp != '\n')
	    goto malformed;
	*addr = strdup (stuff);
	goto hit;
    }
    adios (NULLCP, "unable to find presentationAddress for DSA %s", dsa);

hit: ;
    (void) fclose (fp);
}

/* \f

 */

generate_sed () {
    FILE   *fp;
    register struct pair *p;

    (void) sprintf (sedfil, "/tmp/%sXXXXXX", myname);
    (void) unlink (mktemp (sedfil));

    if ((fp = fopen (sedfil, "w")) == NULL)
	adios (sedfil, "unable to create");

    for (p = pairs; p -> p_name; p++)
	if (!(p -> p_flags & P_MBOX) && p -> p_value)
	    fprintf (fp, "s!@(%s)!%s!\n", p -> p_name, p -> p_value);

    if (ferror (fp))
	adios (sedfil, "error writing");
    (void) fclose (fp);
}

/* \f

 */

static struct pair *n2p (name, any)
char   *name;
int	any;
{
    register struct pair *p;

    for (p = pairs; p -> p_name; p++)
	if (strcmp (p -> p_name, name) == 0)
	    return (any || (p -> p_value && !(p -> p_flags & P_ZAP)) ? p
                                                                     : NULL);

    adios (NULLCP, "internal error -- unable to find \"%s\"", name);
    /* NOTREACHED */
}

/* \f

 */

static	munge (fp, entries)
FILE   *fp;
char   *entries[];
{
    register char   c,
		   *bp,
		   *cp,
		   *dp,
		  **pp;
    char    buffer[BUFSIZ];
    register struct pair *p;


    for (pp = entries; cp = *pp; pp++) {
	bp = buffer;

	while (c = *cp++) {
	    if (c != '@' || *cp != '(') {
		*bp++ = c;
		continue;
	    }
	    if ((dp = index (++cp, ')')) == NULL)
		adios (NULLCP, "internal error -- you lose big");
	    *dp = NULL;

	    if ((p = n2p (cp, 0)) == NULL) {
		bp = buffer;
		goto no_match;
	    }
	    (void) strcpy (bp, p -> p_value);
	    bp += strlen (bp);

	    cp = ++dp;
	}

	*bp = NULL;
	fprintf (fp, "%s\n", buffer);
no_match: ;
    }
}

/* \f

   EDB */

static	build_root () {
    if (debug)
	fprintf (stderr, "mkdir %s\n", wildlife);
    if (mkdir (wildlife, 0700) == NOTOK)
	adios (wildlife, "unable to create directory");

    make_file ("root.edb", "EDB", 0600, 0);
}

/* \f

 */

static char *c_TLC[] = {
    "o=@(organization)",
    "masterDSA= c=@(country)@cn=@(dsa)#",
    "acl= others # read # entry",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # entry",
    "acl= others # read # default",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # default",
    "acl= others # compare # attributes # accessControlList$userPassword",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # attributes # accessControlList$userPassword",
    "o= @(organization)",
    "streetAddress= @(street)",
    "postOfficeBox= @(pob)",
    "physicalDeliveryOfficeName= @(town)",
    "stateOrProvinceName= @(state)",
    "postalCode= @(zipcode)",
    "postalAddress= @(postaladdress)",
    "telephoneNumber= @(telephone)",
    "facsimileTelephoneNumber= @(fax)",
    "localityName= @(locality)",
    "description= @(description)",
    "associatedDomain= @(domain)",
    "treeStructure= quipuNonLeafObject & organizationalUnit",
    "treeStructure= quipuDSA & alias & organizationalRole",
    "treeStructure= domainRelatedObject",
    "objectClass= top & quipuObject & quipuNonLeafObject",
    "objectClass= domainRelatedObject",
    "objectClass= organization",
    "",

    "cn=@(dsa)",
    "acl= others # read # entry",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # entry",
    "acl= others # read # default",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # default",
    "acl= others # compare # attributes # accessControlList$userPassword",
    "acl= group # c=@(country)@o=@(organization)@cn=Manager # write # attributes # accessControlList$userPassword",
    "cn= @(dsa)",
    "eDBinfo= # @(rootDSA) #",
    "eDBinfo= c=@(country) # @(countryDSA) #",
    "eDBinfo= c=@(country)@o=@(organization) # # @(countryDSA)",
    "eDBinfo= c=@(country)@o=@(organization) # # @(rootDSA)",
    "eDBinfo= c=@(country)@o=@(organization) # # @(otherDSA)",
    "presentationAddress= '0101'H/Internet=@(ipaddr)+@(port)",
    "manager= c=@(country)@o=@(organization)@cn=Manager#",
    "manager= c=@(country)@cn=Manager#",
    "userPassword= @(wildlife)",
    "quipuVersion= @(quipuversion)",
    "description= The Endangered @(dsa)",
    "description= Master DSA for @(organization) in the @(country)",
    "objectClass= top & quipuObject",
    "objectClass= applicationEntity & dSA & quipuDSA",
    "supportedApplicationContext= x500DSP & x500DAP & quipuDSP",
    "",

    NULL
};


static	build_TLC () {
    char    buffer[BUFSIZ];

    (void) sprintf (buffer, "%s/c=%s", wildlife,
		    n2p ("country", 1) -> p_value);
    make_edb (buffer, "SLAVE", "0000000000Z", c_TLC);
}

/* \f

 */

static char *o_I[] = {
    "cn=Manager",
    "acl=",
    "cn= Manager",
    "aliasedObjectName= c=@(country)@o=@(organization)@ou=@(unit)@cn=@(firstname) @(lastname)#",
    "objectClass= top & quipuObject",
    "objectClass= alias",
    "",

    "cn=Postmaster",
    "acl=",
    "cn= Postmaster",
    "aliasedObjectName= c=@(country)@o=@(organization)@ou=@(unit)@cn=@(firstname) @(lastname)#",
    "objectClass= top & quipuObject",
    "objectClass= alias",
    "",

    "ou=@(unit)",
    "masterDSA= c=@(country)@cn=@(dsa)#",
    "acl= others # read # entry",
    "acl= others # read # default",
    "acl= others # compare # attributes # accessControlList$userPassword",
    "ou= @(unit)",
    "treeStructure= quipuNonLeafObject & organizationalUnit",
    "treeStructure= alias & pilotPerson & organizationalRole",
    "objectClass= top & quipuObject & quipuNonLeafObject",
    "objectClass= organizationalUnit",
    "",

    NULL
};
	

static	build_organization () {
    char    buffer[BUFSIZ];

    (void) sprintf (buffer, "%s/c=%s/o=%s", wildlife,
		   n2p ("country", 1) -> p_value,
		   n2p ("organization", 1) -> p_value);
    make_edb (buffer, "MASTER", version (), o_I);
}

/* \f

 */

static char *u_J[] = {
    "cn=@(firstname) @(lastname)",
    "acl= self # write # entry",
    "acl= others # read # entry",
    "acl= self # write # default",
    "acl= others # read # default",
    "acl= self # write # attributes # accessControlList$userPassword",
    "acl= others # compare # attributes # accessControlList$userPassword",
    "rfc822Mailbox= @(mailbox)",
    "otherMailbox = internet $ @(mailbox)",
    "title= @(title)",
    "userid= @(userid)",
    "userPassword= @(password)",
    "telephoneNumber= @(extension)",
    "surname= @(lastname)",
    "cn= @(firstname) @(lastname)",
    "cn= @(firstname) @(middleinitial). @(lastname)",
    "cn= @(firstname) @(middlename) @(lastname)",
    "objectClass= top & quipuObject",
    "objectClass= person & thornPerson & pilotPerson",
    "",

    NULL
};


static	build_unit () {
    char    buffer[BUFSIZ];

    (void) sprintf (buffer, "%s/c=%s/o=%s/ou=%s", wildlife,
		   n2p ("country", 1) -> p_value,
		   n2p ("organization", 1) -> p_value,
		   n2p ("unit", 1) -> p_value);
    make_edb (buffer, "MASTER", version (), u_J);
}

/* \f

 */

static	make_edb (dir, type, date, entries)
char   *dir,
       *type,
       *date;
char   *entries[];
{
    char    edb[BUFSIZ];
    FILE   *fp;

    if (debug)
	fprintf (stderr, "mkdir %s\n", dir);
    if (mkdir (dir, 0700) == NOTOK)
	adios (dir, "unable to create directory");

    (void) sprintf (edb, "%s/EDB", dir);
    if (debug)
	fprintf (stderr, "create %s\n", edb);
    if ((fp = fopen (edb, "w")) == NULL)
	adios (edb, "unable to create");

    fprintf (fp, "%s\n%s\n", type, date);
    munge (fp, entries);
    
    if (ferror (fp))
	adios (edb, "error writing");
    (void) fclose (fp);

    (void) chmod (edb, 0600);
}

/* \f

 */

static char *version () {
    long    clock;
    struct UTCtime ut;
    static char buffer[BUFSIZ];

    (void) time (&clock);
    tm2ut (gmtime (&clock), &ut);
    (void) strcpy (buffer, gent2str (&ut));

    return buffer;
}

/* \f

   FILES */

static	build_tailor () { make_file ("quiputailor", "quiputailor", 0644, 1); }

static	build_startup () { make_file ("startup.sh", "startup.sh", 0755, 1); }

static	build_nightly () { make_file ("nightly.sh", "nightly.sh", 0755, 1); }

/* \f

 */

static	make_file (infile, outfile, mode, dosed)
char   *infile,
       *outfile;
int	mode,
	dosed;
{
    char    buffer[BUFSIZ];

    if (dosed)
	(void) sprintf (buffer, "sed -f %s < templates/%s > %s/%s",
			sedfil, infile, wildlife, outfile);
    else
	(void) sprintf (buffer, "cp templates/%s %s/%s", infile, wildlife,
			outfile);

    if (debug)
	fprintf (stderr, "%s\n", buffer);
    if (system (buffer) != 0)
	adios (NULLCP, "%s of %s failed", dosed ? "sed" : "cp", infile);

    (void) sprintf (buffer, "%s/%s", wildlife, outfile);
    (void) chmod (buffer, mode);
}

/* \f

   SED */

static	build_dsap () { fudge_file ("dsaptailor"); }

static	build_fred () { fudge_file ("fredrc"); }

/* \f

 */

static	fudge_file (name)
char   *name;
{
    char   buffer[BUFSIZ],
	   file[BUFSIZ],
	   oldfil[BUFSIZ],
	   tmpfil[BUFSIZ];

    (void) strcpy (file, isodefile (name, 0));
    
    (void) sprintf (buffer, "%sXXXXXX", myname);
    (void) strcpy (tmpfil, isodefile (buffer, 0));
    (void) unlink (mktemp (tmpfil));

    (void) sprintf (buffer, "sed -f %s < %s > %s", sedfil, file, tmpfil);
    if (debug)
	fprintf (stderr, "%s\n", buffer);
    if (system (buffer) != 0) {
	(void) unlink (tmpfil);
	adios (NULLCP, "sed failed");
    }

    (void) sprintf (oldfil, "%s.old", file);
    if (access (oldfil, 0x00) == NOTOK)
	(void) rename (file, oldfil);
    if (rename (tmpfil, file) == NOTOK)
	adios (file, "unable to rename %s to", tmpfil);
}

/* \f

   ARGINIT */

static	arginit (vec)
char  **vec;
{
    register char  *ap;

    if (myname = rindex (*vec, '/'))
	myname++;
    if (myname == NULL || *myname == NULL)
	myname = *vec;

    isodetailor (myname, 1);

    for (vec++; ap = *vec; vec++) {
	if (*ap == '-') {
	    while (*++ap)
		switch (*ap) {
		    case 'd':
		        debug++;
			break;

 		    default:
			adios (NULLCP, "unknown switch -%c", *ap);
		}
	    continue;
	}

	if (wildlife) {
usage: ;
	    adios (NULLCP, "usage: %s config-file", myname);
	}
	wildlife = ap;
    }

    if (!wildlife)
	goto usage;
}

/* \f

   ERRORS */

#ifndef	lint
void	_advise ();


static void  adios (va_alist)
va_dcl
{
    va_list ap;

    va_start (ap);

    _advise (ap);

    va_end (ap);

    _exit (1);
}
#else
/* VARARGS */

static void  adios (what, fmt)
char   *what,
       *fmt;
{
    adios (what, fmt);
}
#endif


#ifndef	lint
static void  advise (va_alist)
va_dcl
{
    va_list ap;

    va_start (ap);

    _advise (ap);

    va_end (ap);
}


static void  _advise (ap)
va_list	ap;
{
    char    buffer[BUFSIZ];

    asprintf (buffer, ap);

    (void) fflush (stdout);

    fprintf (stderr, "%s: ", myname);
    (void) fputs (buffer, stderr);
    (void) fputc ('\n', stderr);

    (void) fflush (stderr);
}
#else
/* VARARGS */

static void  advise (what, fmt)
char   *what,
       *fmt;
{
    advise (what, fmt);
}
#endif

/* \f

   MISCELLANY */

#ifndef	lint
static char *strdup (s)
char   *s;
{
    char    *p;

    if ((p = malloc((unsigned) (strlen (s) + 1))) == NULL)
	adios (NULLCP, "out of memory");

    (void) strcpy (p, s);

    return p;
}
#endif