process.c revision 772b5186
19fe995a9Smrg/*
29fe995a9Smrg *
39fe995a9SmrgCopyright 1989, 1998  The Open Group
49fe995a9Smrg
59fe995a9SmrgPermission to use, copy, modify, distribute, and sell this software and its
69fe995a9Smrgdocumentation for any purpose is hereby granted without fee, provided that
79fe995a9Smrgthe above copyright notice appear in all copies and that both that
89fe995a9Smrgcopyright notice and this permission notice appear in supporting
99fe995a9Smrgdocumentation.
109fe995a9Smrg
119fe995a9SmrgThe above copyright notice and this permission notice shall be included in
129fe995a9Smrgall copies or substantial portions of the Software.
139fe995a9Smrg
149fe995a9SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159fe995a9SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169fe995a9SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
179fe995a9SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
189fe995a9SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
199fe995a9SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
209fe995a9Smrg
219fe995a9SmrgExcept as contained in this notice, the name of The Open Group shall not be
229fe995a9Smrgused in advertising or otherwise to promote the sale, use or other dealings
239fe995a9Smrgin this Software without prior written authorization from The Open Group.
249fe995a9Smrg * *
259fe995a9Smrg * Original Author of "xauth" : Jim Fulton, MIT X Consortium
269fe995a9Smrg * Modified into "iceauth"    : Ralph Mor, X Consortium
279fe995a9Smrg */
289fe995a9Smrg
299fe995a9Smrg#include "iceauth.h"
309fe995a9Smrg#include <ctype.h>
319fe995a9Smrg#include <errno.h>
329fe995a9Smrg#include <sys/types.h>
339fe995a9Smrg#include <sys/stat.h>
349fe995a9Smrg#include <signal.h>
359fe995a9Smrg
369fe995a9Smrg#define SECURERPC "SUN-DES-1"
379fe995a9Smrg#define K5AUTH "KERBEROS-V5-1"
389fe995a9Smrg
399fe995a9Smrg#define ICEAUTH_DEFAULT_RETRIES 10	/* number of competitors we expect */
409fe995a9Smrg#define ICEAUTH_DEFAULT_TIMEOUT 2	/* in seconds, be quick */
419fe995a9Smrg#define ICEAUTH_DEFAULT_DEADTIME 600L	/* 10 minutes in seconds */
429fe995a9Smrg
439fe995a9Smrgtypedef struct _AuthList {		/* linked list of entries */
449fe995a9Smrg    struct _AuthList *next;
459fe995a9Smrg    IceAuthFileEntry *auth;
469fe995a9Smrg} AuthList;
479fe995a9Smrg
489fe995a9Smrg#define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);}
499fe995a9Smrg
50e8ac26b0Smrgtypedef int (*ProcessFunc)(const char *, int, int, const char **);
519d794632Smrgtypedef int (*DoFunc)(const char *, int, IceAuthFileEntry *, void *);
529fe995a9Smrg
539fe995a9Smrgtypedef struct _CommandTable {		/* commands that are understood */
549d794632Smrg    const char *name;			/* full name */
559d794632Smrg    unsigned int minlen;		/* unique prefix */
569d794632Smrg    unsigned int maxlen;		/* strlen(name) */
579fe995a9Smrg    ProcessFunc processfunc;		/* handler */
589d794632Smrg    const char *helptext;		/* what to print for help */
599fe995a9Smrg} CommandTable;
609fe995a9Smrg
619fe995a9Smrgstruct _extract_data {			/* for iterating */
629fe995a9Smrg    FILE *fp;				/* input source */
639d794632Smrg    const char *filename;		/* name of input */
649fe995a9Smrg    Bool used_stdout;			/* whether or not need to close */
659fe995a9Smrg    int nwritten;			/* number of entries written */
669d794632Smrg    const char *cmd;			/* for error messages */
679fe995a9Smrg};
689fe995a9Smrg
699fe995a9Smrgstruct _list_data {			/* for iterating */
709fe995a9Smrg    FILE *fp;				/* output file */
719fe995a9Smrg};
729fe995a9Smrg
739fe995a9Smrg
749fe995a9Smrg/*
759fe995a9Smrg * private data
769fe995a9Smrg */
779d794632Smrgstatic const char *stdin_filename = "(stdin)";  /* for messages */
789d794632Smrgstatic const char *stdout_filename = "(stdout)";  /* for messages */
799fe995a9Smrgstatic const char *Yes = "yes";		/* for messages */
809fe995a9Smrgstatic const char *No = "no";			/* for messages */
819fe995a9Smrg
829fe995a9Smrgstatic int binaryEqual ( const char *a, const char *b, unsigned len );
839fe995a9Smrgstatic void prefix ( const char *fn, int n );
849fe995a9Smrgstatic void badcommandline ( const char *cmd );
859fe995a9Smrgstatic char *skip_space ( char *s );
869fe995a9Smrgstatic char *skip_nonspace ( char *s );
879fe995a9Smrgstatic char **split_into_words ( char *src, int *argcp );
889d794632Smrgstatic FILE *open_file ( const char **filenamep, const char *mode, Bool *usedstdp, const char *srcfn, int srcln, const char *cmd );
899fe995a9Smrgstatic int read_auth_entries ( FILE *fp, AuthList **headp, AuthList **tailp );
909d794632Smrgstatic int cvthexkey ( const char *hexstr, char **ptrp );
91e8ac26b0Smrgstatic int dispatch_command ( const char *inputfilename, int lineno, int argc, const char **argv, const CommandTable *tab, int *statusp );
929d794632Smrgstatic void die ( int sig ) _X_NORETURN;
939d794632Smrgstatic void catchsig ( int sig ) _X_NORETURN;
949fe995a9Smrgstatic void register_signals ( void );
959fe995a9Smrgstatic int write_auth_file ( char *tmp_nam, size_t tmp_nam_len );
969fe995a9Smrgstatic void fprintfhex ( FILE *fp, unsigned int len, const char *cp );
979d794632Smrgstatic int dump_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
989d794632Smrgstatic int extract_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
999fe995a9Smrgstatic int match_auth ( IceAuthFileEntry *a, IceAuthFileEntry *b, int *authDataSame );
1009fe995a9Smrgstatic int merge_entries ( AuthList **firstp, AuthList *second, int *nnewp, int *nreplp, int *ndupp );
101e8ac26b0Smrgstatic int search_and_do ( const char *inputfilename, int lineno, int start, int argc, const char *argv[], DoFunc do_func, void *data );
1029d794632Smrgstatic int remove_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
103e8ac26b0Smrgstatic int do_help ( const char *inputfilename, int lineno, int argc, const char **argv );
104e8ac26b0Smrgstatic int do_questionmark ( const char *inputfilename, int lineno, int argc, const char **argv );
105e8ac26b0Smrgstatic int do_list ( const char *inputfilename, int lineno, int argc, const char **argv );
106e8ac26b0Smrgstatic int do_merge ( const char *inputfilename, int lineno, int argc, const char **argv );
107e8ac26b0Smrgstatic int do_extract ( const char *inputfilename, int lineno, int argc, const char **argv );
108e8ac26b0Smrgstatic int do_add ( const char *inputfilename, int lineno, int argc, const char **argv );
109e8ac26b0Smrgstatic int do_remove ( const char *inputfilename, int lineno, int argc, const char **argv );
110e8ac26b0Smrgstatic int do_info ( const char *inputfilename, int lineno, int argc, const char **argv );
111e8ac26b0Smrgstatic int do_exit ( const char *inputfilename, int lineno, int argc, const char **argv );
112e8ac26b0Smrgstatic int do_quit ( const char *inputfilename, int lineno, int argc, const char **argv );
113e8ac26b0Smrgstatic int do_source ( const char *inputfilename, int lineno, int argc, const char **argv );
1149fe995a9Smrg
1159fe995a9Smrgstatic const CommandTable command_table[] = {	/* table of known commands */
1169fe995a9Smrg{ "add", 2, 3, do_add,
1179fe995a9Smrg"\
1189fe995a9Smrgadd       add an entry\n\
1199fe995a9Smrg          add protoname protodata netid authname authdata"
1209fe995a9Smrg},
1219fe995a9Smrg
1229fe995a9Smrg{ "exit", 3, 4, do_exit,
1239fe995a9Smrg"\
1249fe995a9Smrgexit      save changes and exit program"
1259fe995a9Smrg},
1269fe995a9Smrg
1279fe995a9Smrg{ "extract", 3, 7, do_extract,
1289fe995a9Smrg"\
1299fe995a9Smrgextract   extract entries into file\n\
1309fe995a9Smrg          extract filename <protoname=$> <protodata=$> <netid=$> <authname=$>"
1319fe995a9Smrg},
1329fe995a9Smrg
1339fe995a9Smrg{ "help", 1, 4, do_help,
1349fe995a9Smrg"\
1359fe995a9Smrghelp      print help\n\
1369fe995a9Smrg          help <topic>"
1379fe995a9Smrg},
1389fe995a9Smrg
1399fe995a9Smrg{ "info", 1, 4, do_info,
1409fe995a9Smrg"\
1419fe995a9Smrginfo      print information about entries"
1429fe995a9Smrg},
1439fe995a9Smrg
1449fe995a9Smrg{ "list", 1, 4, do_list,
1459fe995a9Smrg"\
1469fe995a9Smrglist      list entries\n\
1479fe995a9Smrg          list <protoname=$> <protodata=$> <netid=$> <authname=$>"
1489fe995a9Smrg},
1499fe995a9Smrg
1509fe995a9Smrg{ "merge", 1, 5, do_merge,
1519fe995a9Smrg"\
1529fe995a9Smrgmerge     merge entries from files\n\
1539fe995a9Smrg          merge filename1 <filename2> <filename3> ..."
1549fe995a9Smrg},
1559fe995a9Smrg
1569fe995a9Smrg{ "quit", 1, 4, do_quit,
1579fe995a9Smrg"\
1589fe995a9Smrgquit      abort changes and exit program" },
1599fe995a9Smrg
1609fe995a9Smrg{ "remove", 1, 6, do_remove,
1619fe995a9Smrg"\
1629fe995a9Smrgremove    remove entries\n\
1639fe995a9Smrg          remove <protoname=$> <protodata=$> <netid=$> <authname=$>"
1649fe995a9Smrg},
1659fe995a9Smrg
1669fe995a9Smrg{ "source", 1, 6, do_source,
1679fe995a9Smrg"\
1689fe995a9Smrgsource    read commands from file\n\
1699fe995a9Smrg          source filename"
1709fe995a9Smrg},
1719fe995a9Smrg
1729fe995a9Smrg{ "?", 1, 1, do_questionmark,
1739fe995a9Smrg"\
1749fe995a9Smrg?         list available commands" },
1759fe995a9Smrg
1769fe995a9Smrg{ NULL, 0, 0, NULL, NULL },
1779fe995a9Smrg};
1789fe995a9Smrg
1799fe995a9Smrg#define COMMAND_NAMES_PADDED_WIDTH 10	/* wider than anything above */
1809fe995a9Smrg
1819fe995a9Smrg
1829fe995a9Smrgstatic Bool okay_to_use_stdin = True;	/* set to false after using */
1839fe995a9Smrg
1849fe995a9Smrgstatic const char * const hex_table[] = {	/* for printing hex digits */
1859fe995a9Smrg    "00", "01", "02", "03", "04", "05", "06", "07",
1869fe995a9Smrg    "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
1879fe995a9Smrg    "10", "11", "12", "13", "14", "15", "16", "17",
1889fe995a9Smrg    "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
1899fe995a9Smrg    "20", "21", "22", "23", "24", "25", "26", "27",
1909fe995a9Smrg    "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
1919fe995a9Smrg    "30", "31", "32", "33", "34", "35", "36", "37",
1929fe995a9Smrg    "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
1939fe995a9Smrg    "40", "41", "42", "43", "44", "45", "46", "47",
1949fe995a9Smrg    "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
1959fe995a9Smrg    "50", "51", "52", "53", "54", "55", "56", "57",
1969fe995a9Smrg    "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
1979fe995a9Smrg    "60", "61", "62", "63", "64", "65", "66", "67",
1989fe995a9Smrg    "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
1999fe995a9Smrg    "70", "71", "72", "73", "74", "75", "76", "77",
2009fe995a9Smrg    "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
2019fe995a9Smrg    "80", "81", "82", "83", "84", "85", "86", "87",
2029fe995a9Smrg    "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
2039fe995a9Smrg    "90", "91", "92", "93", "94", "95", "96", "97",
2049fe995a9Smrg    "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
2059fe995a9Smrg    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
2069fe995a9Smrg    "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
2079fe995a9Smrg    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
2089fe995a9Smrg    "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
2099fe995a9Smrg    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
2109fe995a9Smrg    "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
2119fe995a9Smrg    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
2129fe995a9Smrg    "d8", "d9", "da", "db", "dc", "dd", "de", "df",
2139fe995a9Smrg    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
2149fe995a9Smrg    "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
2159fe995a9Smrg    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
2169fe995a9Smrg    "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
2179fe995a9Smrg};
2189fe995a9Smrg
2199fe995a9Smrgstatic unsigned int hexvalues[256];	/* for parsing hex input */
2209fe995a9Smrg
2219fe995a9Smrgstatic mode_t original_umask = 0;	/* for restoring */
2229fe995a9Smrg
2239fe995a9Smrg
2249fe995a9Smrg/*
2259fe995a9Smrg * private utility procedures
2269fe995a9Smrg */
2279fe995a9Smrg
2289fe995a9Smrg#define copystring(s)	( s != NULL ? strdup(s) : NULL )
2299fe995a9Smrg
2309fe995a9Smrgstatic int
2319fe995a9SmrgbinaryEqual (
2329fe995a9Smrg    register const char	*a,
2339fe995a9Smrg    register const char	*b,
2349fe995a9Smrg    register unsigned	len)
2359fe995a9Smrg
2369fe995a9Smrg{
2379fe995a9Smrg    while (len--)
2389fe995a9Smrg	if (*a++ != *b++)
2399fe995a9Smrg	    return 0;
2409fe995a9Smrg    return 1;
2419fe995a9Smrg}
2429fe995a9Smrg
2439fe995a9Smrgstatic void prefix (const char *fn, int n)
2449fe995a9Smrg{
2459fe995a9Smrg    fprintf (stderr, "%s: %s:%d:  ", ProgramName, fn, n);
2469fe995a9Smrg}
2479fe995a9Smrg
2489fe995a9Smrgstatic void badcommandline (const char *cmd)
2499fe995a9Smrg{
2509fe995a9Smrg    fprintf (stderr, "bad \"%s\" command line\n", cmd);
2519fe995a9Smrg}
2529fe995a9Smrg
2539fe995a9Smrgstatic char *skip_space (register char *s)
2549fe995a9Smrg{
2559fe995a9Smrg    if (!s) return NULL;
2569fe995a9Smrg
2579fe995a9Smrg    for ( ; *s && isascii(*s) && isspace(*s); s++)
2589fe995a9Smrg	;
2599fe995a9Smrg    return s;
2609fe995a9Smrg}
2619fe995a9Smrg
2629fe995a9Smrg
2639fe995a9Smrgstatic char *skip_nonspace (register char *s)
2649fe995a9Smrg{
2659fe995a9Smrg    if (!s) return NULL;
2669fe995a9Smrg
2679fe995a9Smrg    /* put quoting into loop if need be */
2689fe995a9Smrg    for ( ; *s && isascii(*s) && !isspace(*s); s++)
2699fe995a9Smrg	;
2709fe995a9Smrg    return s;
2719fe995a9Smrg}
2729fe995a9Smrg
273772b5186Smrg#ifndef HAVE_REALLOCARRAY
274772b5186Smrgstatic inline void *
275772b5186Smrgreallocarray(void *optr, size_t nmemb, size_t size)
276772b5186Smrg{
277772b5186Smrg    if ((nmemb > 0) && (SIZE_MAX / nmemb < size)) {
278772b5186Smrg        errno = ENOMEM;
279772b5186Smrg        return NULL;
280772b5186Smrg    }
281772b5186Smrg    return realloc(optr, size * nmemb);
282772b5186Smrg}
283772b5186Smrg#endif
284772b5186Smrg
2859fe995a9Smrgstatic char **split_into_words (  /* argvify string */
2869fe995a9Smrg    char *src,
2879fe995a9Smrg    int *argcp)
2889fe995a9Smrg{
2899fe995a9Smrg    char *jword;
2909fe995a9Smrg    char **argv;
2919fe995a9Smrg    int cur, total;
2929fe995a9Smrg
2939fe995a9Smrg    *argcp = 0;
294772b5186Smrg#define WORDSTOALLOC 6			/* most lines are short */
2959fe995a9Smrg    argv = (char **) malloc (WORDSTOALLOC * sizeof (char *));
2969fe995a9Smrg    if (!argv) return NULL;
2979fe995a9Smrg    cur = 0;
2989fe995a9Smrg    total = WORDSTOALLOC;
2999fe995a9Smrg
3009fe995a9Smrg    /*
3019fe995a9Smrg     * split the line up into separate, nul-terminated tokens; the last
3029fe995a9Smrg     * "token" will point to the empty string so that it can be bashed into
3039fe995a9Smrg     * a null pointer.
3049fe995a9Smrg     */
3059fe995a9Smrg
3069fe995a9Smrg    do {
307772b5186Smrg	char savec;
308772b5186Smrg
3099fe995a9Smrg	jword = skip_space (src);
3109fe995a9Smrg	src = skip_nonspace (jword);
3119fe995a9Smrg	savec = *src;
3129fe995a9Smrg	*src = '\0';
3139fe995a9Smrg	if (cur == total) {
314e8ac26b0Smrg	    char **prevargv = argv;
3159fe995a9Smrg	    total += WORDSTOALLOC;
316772b5186Smrg	    argv = reallocarray (argv, total, sizeof (char *));
317e8ac26b0Smrg	    if (!argv) {
318e8ac26b0Smrg		free (prevargv);
319e8ac26b0Smrg		return NULL;
320e8ac26b0Smrg	    }
3219fe995a9Smrg	}
3229fe995a9Smrg	argv[cur++] = jword;
3239fe995a9Smrg	if (savec) src++;		/* if not last on line advance */
3249fe995a9Smrg    } while (jword != src);
3259fe995a9Smrg
3269fe995a9Smrg    argv[--cur] = NULL;			/* smash empty token to end list */
3279fe995a9Smrg    *argcp = cur;
3289fe995a9Smrg    return argv;
3299fe995a9Smrg}
3309fe995a9Smrg
3319fe995a9Smrg
3329fe995a9Smrgstatic FILE *open_file (
3339d794632Smrg    const char **filenamep,
3349fe995a9Smrg    const char *mode,
3359fe995a9Smrg    Bool *usedstdp,
3369fe995a9Smrg    const char *srcfn,
3379fe995a9Smrg    int srcln,
3389fe995a9Smrg    const char *cmd)
3399fe995a9Smrg{
3409fe995a9Smrg    FILE *fp;
3419fe995a9Smrg
3429fe995a9Smrg    if (strcmp (*filenamep, "-") == 0) {
3439fe995a9Smrg	*usedstdp = True;
3449fe995a9Smrg					/* select std descriptor to use */
3459fe995a9Smrg	if (mode[0] == 'r') {
3469fe995a9Smrg	    if (okay_to_use_stdin) {
3479fe995a9Smrg		okay_to_use_stdin = False;
3489fe995a9Smrg		*filenamep = stdin_filename;
3499fe995a9Smrg		return stdin;
3509fe995a9Smrg	    } else {
3519fe995a9Smrg		prefix (srcfn, srcln);
3529fe995a9Smrg		fprintf (stderr, "%s:  stdin already in use\n", cmd);
3539fe995a9Smrg		return NULL;
3549fe995a9Smrg	    }
3559fe995a9Smrg	} else {
3569fe995a9Smrg	    *filenamep = stdout_filename;
3579fe995a9Smrg	    return stdout;		/* always okay to use stdout */
3589fe995a9Smrg	}
3599fe995a9Smrg    }
3609fe995a9Smrg
3619fe995a9Smrg    fp = fopen (*filenamep, mode);
3629fe995a9Smrg    if (!fp) {
3639fe995a9Smrg	prefix (srcfn, srcln);
3649fe995a9Smrg	fprintf (stderr, "%s:  unable to open file %s\n", cmd, *filenamep);
3659fe995a9Smrg    }
3669fe995a9Smrg    return fp;
3679fe995a9Smrg}
3689fe995a9Smrg
3699fe995a9Smrg
3709fe995a9Smrgstatic int read_auth_entries (FILE *fp, AuthList **headp, AuthList **tailp)
3719fe995a9Smrg{
3729fe995a9Smrg    IceAuthFileEntry *auth;
3739fe995a9Smrg    AuthList *head, *tail;
3749fe995a9Smrg    int n;
3759fe995a9Smrg
3769fe995a9Smrg    head = tail = NULL;
3779fe995a9Smrg    n = 0;
3789fe995a9Smrg					/* put all records into linked list */
3799fe995a9Smrg    while ((auth = IceReadAuthFileEntry (fp)) != NULL) {
3809fe995a9Smrg	AuthList *l = (AuthList *) malloc (sizeof (AuthList));
3819fe995a9Smrg	if (!l) {
3829fe995a9Smrg	    fprintf (stderr,
3839fe995a9Smrg		     "%s:  unable to alloc entry reading auth file\n",
3849fe995a9Smrg		     ProgramName);
3859fe995a9Smrg	    exit (1);
3869fe995a9Smrg	}
3879fe995a9Smrg	l->next = NULL;
3889fe995a9Smrg	l->auth = auth;
3899fe995a9Smrg	if (tail) 			/* if not first time through append */
3909fe995a9Smrg	  tail->next = l;
3919fe995a9Smrg	else
3929fe995a9Smrg	  head = l;			/* first time through, so assign */
3939fe995a9Smrg	tail = l;
3949fe995a9Smrg	n++;
3959fe995a9Smrg    }
3969fe995a9Smrg    *headp = head;
3979fe995a9Smrg    *tailp = tail;
3989fe995a9Smrg    return n;
3999fe995a9Smrg}
4009fe995a9Smrg
4019fe995a9Smrg
4029fe995a9Smrgstatic int cvthexkey (	/* turn hex key string into octets */
4039d794632Smrg    const char *hexstr,
4049fe995a9Smrg    char **ptrp)
4059fe995a9Smrg{
4069d794632Smrg    unsigned int i;
4079d794632Smrg    unsigned int len = 0;
4089d794632Smrg    char *retval;
4099fe995a9Smrg    unsigned char *us;
4109fe995a9Smrg    char savec = '\0';
4119fe995a9Smrg
4129fe995a9Smrg    /* count */
413772b5186Smrg    for (const char *s = hexstr; *s; s++) {
4149fe995a9Smrg	if (!isascii(*s)) return -1;
4159fe995a9Smrg	if (isspace(*s)) continue;
4169fe995a9Smrg	if (!isxdigit(*s)) return -1;
4179fe995a9Smrg	len++;
4189fe995a9Smrg    }
4199fe995a9Smrg
42090b6713cSmrg    /* if 0 or odd, then there was an error */
42190b6713cSmrg    if (len == 0 || (len & 1) == 1) return -1;
4229fe995a9Smrg
4239fe995a9Smrg
4249fe995a9Smrg    /* now we know that the input is good */
4259fe995a9Smrg    len >>= 1;
4269fe995a9Smrg    retval = malloc (len);
4279fe995a9Smrg    if (!retval) {
4289fe995a9Smrg	fprintf (stderr, "%s:  unable to allocate %d bytes for hexkey\n",
4299fe995a9Smrg		 ProgramName, len);
4309fe995a9Smrg	return -1;
4319fe995a9Smrg    }
4329fe995a9Smrg
4339fe995a9Smrg    for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
434772b5186Smrg	char c = *hexstr;
435772b5186Smrg
4369fe995a9Smrg	if (isspace(c)) continue;	 /* already know it is ascii */
4379fe995a9Smrg	if (isupper(c))
4389fe995a9Smrg	    c = tolower(c);
4399fe995a9Smrg	if (savec) {
4409fe995a9Smrg#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
4419fe995a9Smrg	    *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
4429fe995a9Smrg#undef atoh
4439fe995a9Smrg	    savec = 0;		/* ready for next character */
4449fe995a9Smrg	    us++;
4459fe995a9Smrg	    i--;
4469fe995a9Smrg	} else {
4479fe995a9Smrg	    savec = c;
4489fe995a9Smrg	}
4499fe995a9Smrg    }
4509fe995a9Smrg    *ptrp = retval;
4519d794632Smrg    return (int) len;
4529fe995a9Smrg}
4539fe995a9Smrg
4549fe995a9Smrgstatic int dispatch_command (
4559fe995a9Smrg    const char *inputfilename,
4569fe995a9Smrg    int lineno,
4579fe995a9Smrg    int argc,
458e8ac26b0Smrg    const char **argv,
4599fe995a9Smrg    const CommandTable *tab,
4609fe995a9Smrg    int *statusp)
4619fe995a9Smrg{
4629d794632Smrg    const char *cmd;
4639d794632Smrg    size_t n;
4649fe995a9Smrg					/* scan table for command */
4659fe995a9Smrg    cmd = argv[0];
4669fe995a9Smrg    n = strlen (cmd);
467772b5186Smrg    for (const CommandTable *ct = tab; ct->name; ct++) {
4689fe995a9Smrg					/* look for unique prefix */
4699fe995a9Smrg	if (n >= ct->minlen && n <= ct->maxlen &&
4709fe995a9Smrg	    strncmp (cmd, ct->name, n) == 0) {
4719fe995a9Smrg	    *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
4729fe995a9Smrg	    return 1;
4739fe995a9Smrg	}
4749fe995a9Smrg    }
4759fe995a9Smrg
4769fe995a9Smrg    *statusp = 1;
4779fe995a9Smrg    return 0;
4789fe995a9Smrg}
4799fe995a9Smrg
4809fe995a9Smrg
4819fe995a9Smrgstatic AuthList *iceauth_head = NULL;	/* list of auth entries */
4829fe995a9Smrgstatic Bool iceauth_existed = False;	/* if was present at initialize */
4839fe995a9Smrgstatic Bool iceauth_modified = False;	/* if added, removed, or merged */
4849fe995a9Smrgstatic Bool iceauth_allowed = True;	/* if allowed to write auth file */
4859fe995a9Smrgstatic char *iceauth_filename = NULL;
486c048b52eSmrgstatic volatile Bool dying = False;
4879fe995a9Smrg
4889fe995a9Smrg/* poor man's puts(), for under signal handlers */
4899fe995a9Smrg#define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
4909fe995a9Smrg
4919fe995a9Smrg/* ARGSUSED */
4929d794632Smrgstatic void die (_X_UNUSED int sig)
4939fe995a9Smrg{
494c048b52eSmrg    dying = True;
4959fe995a9Smrg    _exit (auth_finalize ());
4969fe995a9Smrg    /* NOTREACHED */
4979fe995a9Smrg}
4989fe995a9Smrg
4999d794632Smrgstatic void catchsig (int sig)
5009fe995a9Smrg{
5019fe995a9Smrg#ifdef SYSV
5029fe995a9Smrg    if (sig > 0) signal (sig, die);	/* re-establish signal handler */
5039fe995a9Smrg#endif
5049fe995a9Smrg    /*
5059fe995a9Smrg     * fileno() might not be reentrant, avoid it if possible, and use
5069fe995a9Smrg     * stderr instead of stdout
5079fe995a9Smrg     */
5089fe995a9Smrg#ifdef STDERR_FILENO
5099fe995a9Smrg    if (verbose && iceauth_modified) WRITES(STDERR_FILENO, "\r\n");
5109fe995a9Smrg#else
5119fe995a9Smrg    if (verbose && iceauth_modified) WRITES(fileno(stderr), "\r\n");
5129fe995a9Smrg#endif
5139fe995a9Smrg    die (sig);
5149fe995a9Smrg    /* NOTREACHED */
5159fe995a9Smrg}
5169fe995a9Smrg
5179fe995a9Smrgstatic void register_signals (void)
5189fe995a9Smrg{
5199fe995a9Smrg    signal (SIGINT, catchsig);
5209fe995a9Smrg    signal (SIGTERM, catchsig);
5219fe995a9Smrg#ifdef SIGHUP
5229fe995a9Smrg    signal (SIGHUP, catchsig);
5239fe995a9Smrg#endif
5249fe995a9Smrg    return;
5259fe995a9Smrg}
5269fe995a9Smrg
5279fe995a9Smrg
5289fe995a9Smrg/*
5299fe995a9Smrg * public procedures for parsing lines of input
5309fe995a9Smrg */
5319fe995a9Smrg
5329fe995a9Smrgint auth_initialize ( char *authfilename )
5339fe995a9Smrg{
5349fe995a9Smrg    int n;
5359fe995a9Smrg    FILE *authfp;
5369fe995a9Smrg    Bool exists;
5379fe995a9Smrg
5389fe995a9Smrg    register_signals ();
5399fe995a9Smrg
5409fe995a9Smrg    bzero ((char *) hexvalues, sizeof hexvalues);
5419fe995a9Smrg    hexvalues['0'] = 0;
5429fe995a9Smrg    hexvalues['1'] = 1;
5439fe995a9Smrg    hexvalues['2'] = 2;
5449fe995a9Smrg    hexvalues['3'] = 3;
5459fe995a9Smrg    hexvalues['4'] = 4;
5469fe995a9Smrg    hexvalues['5'] = 5;
5479fe995a9Smrg    hexvalues['6'] = 6;
5489fe995a9Smrg    hexvalues['7'] = 7;
5499fe995a9Smrg    hexvalues['8'] = 8;
5509fe995a9Smrg    hexvalues['9'] = 9;
5519fe995a9Smrg    hexvalues['a'] = hexvalues['A'] = 0xa;
5529fe995a9Smrg    hexvalues['b'] = hexvalues['B'] = 0xb;
5539fe995a9Smrg    hexvalues['c'] = hexvalues['C'] = 0xc;
5549fe995a9Smrg    hexvalues['d'] = hexvalues['D'] = 0xd;
5559fe995a9Smrg    hexvalues['e'] = hexvalues['E'] = 0xe;
5569fe995a9Smrg    hexvalues['f'] = hexvalues['F'] = 0xf;
5579fe995a9Smrg
5589fe995a9Smrg    if (break_locks && verbose) {
5599fe995a9Smrg	printf ("Attempting to break locks on authority file %s\n",
5609fe995a9Smrg		authfilename);
5619fe995a9Smrg    }
5629fe995a9Smrg
5639fe995a9Smrg    iceauth_filename = strdup(authfilename);
5649fe995a9Smrg
5659fe995a9Smrg    if (ignore_locks) {
5669fe995a9Smrg	if (break_locks) IceUnlockAuthFile (authfilename);
5679fe995a9Smrg    } else {
5689fe995a9Smrg	n = IceLockAuthFile (authfilename, ICEAUTH_DEFAULT_RETRIES,
5699fe995a9Smrg			 ICEAUTH_DEFAULT_TIMEOUT,
5709fe995a9Smrg			 (break_locks ? 0L : ICEAUTH_DEFAULT_DEADTIME));
5719fe995a9Smrg	if (n != IceAuthLockSuccess) {
5729d794632Smrg	    const char *reason = "unknown error";
5739fe995a9Smrg	    switch (n) {
5749fe995a9Smrg	      case IceAuthLockError:
5759fe995a9Smrg		reason = "error";
5769fe995a9Smrg		break;
5779fe995a9Smrg	      case IceAuthLockTimeout:
5789fe995a9Smrg		reason = "timeout";
5799fe995a9Smrg		break;
5809fe995a9Smrg	    }
5819fe995a9Smrg	    fprintf (stderr, "%s:  %s in locking authority file %s\n",
5829fe995a9Smrg		     ProgramName, reason, authfilename);
5839fe995a9Smrg	    return -1;
5849fe995a9Smrg	}
5859fe995a9Smrg    }
5869fe995a9Smrg
5879fe995a9Smrg    /* these checks can only be done reliably after the file is locked */
5889fe995a9Smrg    exists = (access (authfilename, F_OK) == 0);
5899fe995a9Smrg    if (exists && access (authfilename, W_OK) != 0) {
5909fe995a9Smrg	fprintf (stderr,
5919fe995a9Smrg	 "%s:  %s not writable, changes will be ignored\n",
5929fe995a9Smrg		 ProgramName, authfilename);
5939fe995a9Smrg	iceauth_allowed = False;
5949fe995a9Smrg    }
5959fe995a9Smrg
5969fe995a9Smrg    original_umask = umask (0077);	/* disallow non-owner access */
5979fe995a9Smrg
5989fe995a9Smrg    authfp = fopen (authfilename, "rb");
5999fe995a9Smrg    if (!authfp) {
6009fe995a9Smrg	int olderrno = errno;
6019fe995a9Smrg
6029fe995a9Smrg					/* if file there then error */
6039fe995a9Smrg	if (access (authfilename, F_OK) == 0) {	 /* then file does exist! */
6049fe995a9Smrg	    errno = olderrno;
6059fe995a9Smrg	    return -1;
6069fe995a9Smrg	}				/* else ignore it */
6079fe995a9Smrg	fprintf (stderr,
6089fe995a9Smrg		 "%s:  creating new authority file %s\n",
6099fe995a9Smrg		 ProgramName, authfilename);
6109fe995a9Smrg    } else {
611772b5186Smrg	AuthList *head, *tail;
612772b5186Smrg
6139fe995a9Smrg	iceauth_existed = True;
6149fe995a9Smrg	n = read_auth_entries (authfp, &head, &tail);
6159fe995a9Smrg	(void) fclose (authfp);
6169fe995a9Smrg	if (n < 0) {
6179fe995a9Smrg	    fprintf (stderr,
6189fe995a9Smrg		     "%s:  unable to read auth entries from file \"%s\"\n",
6199fe995a9Smrg		     ProgramName, authfilename);
6209fe995a9Smrg	    return -1;
6219fe995a9Smrg	}
6229fe995a9Smrg	iceauth_head = head;
6239fe995a9Smrg    }
6249fe995a9Smrg
6259fe995a9Smrg    iceauth_modified = False;
6269fe995a9Smrg
6279fe995a9Smrg    if (verbose) {
6289fe995a9Smrg	printf ("%s authority file %s\n",
6299fe995a9Smrg		ignore_locks ? "Ignoring locks on" : "Using", authfilename);
6309fe995a9Smrg    }
6319fe995a9Smrg    return 0;
6329fe995a9Smrg}
6339fe995a9Smrg
6349fe995a9Smrgstatic int write_auth_file (char *tmp_nam, size_t tmp_nam_len)
6359fe995a9Smrg{
6369fe995a9Smrg    FILE *fp;
6379fe995a9Smrg
6389fe995a9Smrg    if ((strlen(iceauth_filename) + 3) > tmp_nam_len) {
6399fe995a9Smrg	strncpy(tmp_nam, "filename too long", tmp_nam_len);
6409fe995a9Smrg	tmp_nam[tmp_nam_len - 1] = '\0';
6419fe995a9Smrg	return -1;
6429fe995a9Smrg    }
6439fe995a9Smrg
6449fe995a9Smrg    strcpy (tmp_nam, iceauth_filename);
6459fe995a9Smrg    strcat (tmp_nam, "-n");		/* for new */
6469fe995a9Smrg    (void) unlink (tmp_nam);
6479fe995a9Smrg    fp = fopen (tmp_nam, "wb");		/* umask is still set to 0077 */
6489fe995a9Smrg    if (!fp) {
6499fe995a9Smrg	fprintf (stderr, "%s:  unable to open tmp file \"%s\"\n",
6509fe995a9Smrg		 ProgramName, tmp_nam);
6519fe995a9Smrg	return -1;
6529fe995a9Smrg    }
6539fe995a9Smrg
654772b5186Smrg    for (AuthList *list = iceauth_head; list; list = list->next) {
6559fe995a9Smrg	IceWriteAuthFileEntry (fp, list->auth);
656772b5186Smrg    }
6579fe995a9Smrg
6589fe995a9Smrg    (void) fclose (fp);
6599fe995a9Smrg    return 0;
6609fe995a9Smrg}
6619fe995a9Smrg
6629fe995a9Smrgint auth_finalize (void)
6639fe995a9Smrg{
6649fe995a9Smrg    if (iceauth_modified) {
665c048b52eSmrg	if (dying) {
6669fe995a9Smrg	    if (verbose) {
6679fe995a9Smrg		/*
6689fe995a9Smrg		 * called from a signal handler -- printf is *not* reentrant; also
6699fe995a9Smrg		 * fileno() might not be reentrant, avoid it if possible, and use
6709fe995a9Smrg		 * stderr instead of stdout
6719fe995a9Smrg		 */
6729fe995a9Smrg#ifdef STDERR_FILENO
6739fe995a9Smrg		WRITES(STDERR_FILENO, "\nAborting changes to authority file ");
6749fe995a9Smrg		WRITES(STDERR_FILENO, iceauth_filename);
6759fe995a9Smrg		WRITES(STDERR_FILENO, "\n");
6769fe995a9Smrg#else
6779fe995a9Smrg		WRITES(fileno(stderr), "\nAborting changes to authority file ");
6789fe995a9Smrg		WRITES(fileno(stderr), iceauth_filename);
6799fe995a9Smrg		WRITES(fileno(stderr), "\n");
6809fe995a9Smrg#endif
6819fe995a9Smrg	    }
6829fe995a9Smrg	} else if (!iceauth_allowed) {
6839fe995a9Smrg	    fprintf (stderr,
6849fe995a9Smrg		     "%s:  %s not writable, changes ignored\n",
6859fe995a9Smrg		     ProgramName, iceauth_filename);
6869fe995a9Smrg	} else {
687772b5186Smrg	    char temp_name[1024];		/* large filename size */
688772b5186Smrg
6899fe995a9Smrg	    if (verbose) {
6909fe995a9Smrg		printf ("%s authority file %s\n",
6919fe995a9Smrg			ignore_locks ? "Ignoring locks and writing" :
6929fe995a9Smrg			"Writing", iceauth_filename);
6939fe995a9Smrg	    }
6949fe995a9Smrg	    temp_name[0] = '\0';
6959fe995a9Smrg	    if (write_auth_file (temp_name, sizeof(temp_name)) == -1) {
6969fe995a9Smrg		fprintf (stderr,
6979fe995a9Smrg			 "%s:  unable to write authority file %s\n",
6989fe995a9Smrg			 ProgramName, temp_name);
6999fe995a9Smrg	    } else {
7009fe995a9Smrg		(void) unlink (iceauth_filename);
701772b5186Smrg#ifdef WIN32
7029fe995a9Smrg		if (rename(temp_name, iceauth_filename) == -1)
7039fe995a9Smrg#else
70490b6713cSmrg		/* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */
70590b6713cSmrg		if (link (temp_name, iceauth_filename) == -1 && rename(temp_name, iceauth_filename) == -1)
7069fe995a9Smrg#endif
7079fe995a9Smrg		{
7089fe995a9Smrg		    fprintf (stderr,
7099fe995a9Smrg		     "%s:  unable to link authority file %s, use %s\n",
7109fe995a9Smrg			     ProgramName, iceauth_filename, temp_name);
7119fe995a9Smrg		} else {
7129fe995a9Smrg		    (void) unlink (temp_name);
7139fe995a9Smrg		}
7149fe995a9Smrg	    }
7159fe995a9Smrg	}
7169fe995a9Smrg    }
7179fe995a9Smrg
7189fe995a9Smrg    if (!ignore_locks && (iceauth_filename != NULL)) {
7199fe995a9Smrg	IceUnlockAuthFile (iceauth_filename);
7209fe995a9Smrg    }
7219fe995a9Smrg    (void) umask (original_umask);
7229fe995a9Smrg    return 0;
7239fe995a9Smrg}
7249fe995a9Smrg
7259fe995a9Smrgint process_command (
7269fe995a9Smrg    const char *inputfilename,
7279fe995a9Smrg    int lineno,
7289fe995a9Smrg    int argc,
729e8ac26b0Smrg    const char **argv)
7309fe995a9Smrg{
7319fe995a9Smrg    int status;
7329fe995a9Smrg
7339fe995a9Smrg    if (argc < 1 || !argv || !argv[0]) return 1;
7349fe995a9Smrg
7359fe995a9Smrg    if (dispatch_command (inputfilename, lineno, argc, argv,
7369fe995a9Smrg			  command_table, &status))
7379fe995a9Smrg      return status;
7389fe995a9Smrg
7399fe995a9Smrg    prefix (inputfilename, lineno);
7409fe995a9Smrg    fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
7419fe995a9Smrg    return 1;
7429fe995a9Smrg}
7439fe995a9Smrg
7449fe995a9Smrg
7459fe995a9Smrg/*
7469fe995a9Smrg * utility routines
7479fe995a9Smrg */
7489fe995a9Smrg
7499fe995a9Smrgstatic void fprintfhex (
7509fe995a9Smrg    register FILE *fp,
7519fe995a9Smrg    unsigned int len,
7529fe995a9Smrg    const char *cp)
7539fe995a9Smrg{
7549fe995a9Smrg    const unsigned char *ucp = (const unsigned char *) cp;
7559fe995a9Smrg
7569fe995a9Smrg    for (; len > 0; len--, ucp++) {
7579fe995a9Smrg	register const char *s = hex_table[*ucp];
7589fe995a9Smrg	putc (s[0], fp);
7599fe995a9Smrg	putc (s[1], fp);
7609fe995a9Smrg    }
7619fe995a9Smrg    return;
7629fe995a9Smrg}
7639fe995a9Smrg
7649fe995a9Smrg/* ARGSUSED */
7659fe995a9Smrgstatic int dump_entry (
7669d794632Smrg    const char *inputfilename _X_UNUSED,
7679d794632Smrg    int lineno _X_UNUSED,
7689fe995a9Smrg    IceAuthFileEntry *auth,
7699d794632Smrg    void *data)
7709fe995a9Smrg{
7719fe995a9Smrg    struct _list_data *ld = (struct _list_data *) data;
7729fe995a9Smrg    FILE *fp = ld->fp;
7739fe995a9Smrg
7749fe995a9Smrg    fprintf (fp, "%s", auth->protocol_name);
7759fe995a9Smrg    putc (' ', fp);
7769fe995a9Smrg    if (auth->protocol_data_length > 0)
7779fe995a9Smrg	fprintfhex (fp, auth->protocol_data_length, auth->protocol_data);
7789fe995a9Smrg    else
7799fe995a9Smrg	fprintf (fp, "\"\"");
7809fe995a9Smrg    putc (' ', fp);
7819fe995a9Smrg    fprintf (fp, "%s", auth->network_id);
7829fe995a9Smrg    putc (' ', fp);
7839fe995a9Smrg    fprintf (fp, "%s", auth->auth_name);
7849fe995a9Smrg    putc (' ', fp);
7859fe995a9Smrg
7869fe995a9Smrg    if (auth->auth_data_length == 0)
7879fe995a9Smrg	fprintf (fp, "\"\"");
7889fe995a9Smrg    else if (!strcmp(auth->auth_name, SECURERPC) ||
7899fe995a9Smrg	!strcmp(auth->auth_name, K5AUTH))
7909fe995a9Smrg	fwrite (auth->auth_data, sizeof (char), auth->auth_data_length, fp);
7919fe995a9Smrg    else
7929fe995a9Smrg	fprintfhex (fp, auth->auth_data_length, auth->auth_data);
7939fe995a9Smrg    putc ('\n', fp);
7949fe995a9Smrg
7959fe995a9Smrg    return 0;
7969fe995a9Smrg}
7979fe995a9Smrg
7989fe995a9Smrgstatic int extract_entry (
7999fe995a9Smrg    const char *inputfilename,
8009fe995a9Smrg    int lineno,
8019fe995a9Smrg    IceAuthFileEntry *auth,
8029d794632Smrg    void *data)
8039fe995a9Smrg{
8049fe995a9Smrg    struct _extract_data *ed = (struct _extract_data *) data;
8059fe995a9Smrg
8069fe995a9Smrg    if (!ed->fp) {
8079fe995a9Smrg	ed->fp = open_file (&ed->filename, "wb",
8089fe995a9Smrg			    &ed->used_stdout,
8099fe995a9Smrg			    inputfilename, lineno, ed->cmd);
8109fe995a9Smrg	if (!ed->fp) {
8119fe995a9Smrg	    prefix (inputfilename, lineno);
8129fe995a9Smrg	    fprintf (stderr,
8139fe995a9Smrg		     "unable to open extraction file \"%s\"\n",
8149fe995a9Smrg		     ed->filename);
8159fe995a9Smrg	    return -1;
8169fe995a9Smrg	}
8179fe995a9Smrg    }
8189fe995a9Smrg    IceWriteAuthFileEntry (ed->fp, auth);
8199fe995a9Smrg    ed->nwritten++;
8209fe995a9Smrg
8219fe995a9Smrg    return 0;
8229fe995a9Smrg}
8239fe995a9Smrg
8249fe995a9Smrg
8259fe995a9Smrgstatic int match_auth (
8269fe995a9Smrg    register IceAuthFileEntry *a,
8279fe995a9Smrg    register IceAuthFileEntry *b,
8289fe995a9Smrg    int *authDataSame)
8299fe995a9Smrg{
8309fe995a9Smrg    int match = strcmp (a->protocol_name, b->protocol_name) == 0 &&
8319fe995a9Smrg	    strcmp (a->network_id, b->network_id) == 0 &&
8329fe995a9Smrg            strcmp (a->auth_name, b->auth_name) == 0;
8339fe995a9Smrg
8349fe995a9Smrg    if (match)
8359fe995a9Smrg    {
8369fe995a9Smrg	*authDataSame = (a->auth_data_length == b->auth_data_length &&
8379fe995a9Smrg	    binaryEqual (a->auth_data, b->auth_data, a->auth_data_length));
8389fe995a9Smrg    }
8399fe995a9Smrg    else
8409fe995a9Smrg	*authDataSame = 0;
8419fe995a9Smrg
8429fe995a9Smrg    return (match);
8439fe995a9Smrg}
8449fe995a9Smrg
8459fe995a9Smrg
8469fe995a9Smrgstatic int merge_entries (
8479fe995a9Smrg    AuthList **firstp, AuthList *second,
8489fe995a9Smrg    int *nnewp, int *nreplp, int *ndupp)
8499fe995a9Smrg{
850772b5186Smrg    AuthList *first, *tail;
8519fe995a9Smrg    int n = 0, nnew = 0, nrepl = 0, ndup = 0;
8529fe995a9Smrg
8539fe995a9Smrg    if (!second) return 0;
8549fe995a9Smrg
8559fe995a9Smrg    if (!*firstp) {			/* if nothing to merge into */
8569fe995a9Smrg	*firstp = second;
8579fe995a9Smrg	for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
8589fe995a9Smrg	*nnewp = n;
8599fe995a9Smrg	*nreplp = 0;
8609fe995a9Smrg	*ndupp = 0;
8619fe995a9Smrg	return n;
8629fe995a9Smrg    }
8639fe995a9Smrg
8649fe995a9Smrg    first = *firstp;
8659fe995a9Smrg    /*
8669fe995a9Smrg     * find end of first list and stick second list on it
8679fe995a9Smrg     */
8689fe995a9Smrg    for (tail = first; tail->next; tail = tail->next) ;
8699fe995a9Smrg    tail->next = second;
8709fe995a9Smrg
8719fe995a9Smrg    /*
8729fe995a9Smrg     * run down list freeing duplicate entries; if an entry is okay, then
8739fe995a9Smrg     * bump the tail up to include it, otherwise, cut the entry out of
8749fe995a9Smrg     * the chain.
8759fe995a9Smrg     */
876772b5186Smrg    for (AuthList *b = second; b; ) {
8779fe995a9Smrg	AuthList *next = b->next;	/* in case we free it */
878772b5186Smrg	AuthList *a = first;
879772b5186Smrg	int duplicate = 0;
8809fe995a9Smrg
8819fe995a9Smrg	for (;;) {
8829fe995a9Smrg	    int authDataSame;
8839fe995a9Smrg	    if (match_auth (a->auth, b->auth, &authDataSame)) {
8849fe995a9Smrg		if (authDataSame)
8859fe995a9Smrg		{
8869fe995a9Smrg		    /* found a complete duplicate, ignore */
8879fe995a9Smrg		    duplicate = 1;
8889fe995a9Smrg		    break;
8899fe995a9Smrg		}
8909fe995a9Smrg		else
8919fe995a9Smrg		{
8929fe995a9Smrg		    /* found a duplicate, but auth data differs */
8939fe995a9Smrg
8949fe995a9Smrg		    AuthList tmp;		/* swap it in for old one */
8959fe995a9Smrg		    tmp = *a;
8969fe995a9Smrg		    *a = *b;
8979fe995a9Smrg		    *b = tmp;
8989fe995a9Smrg		    a->next = b->next;
8999fe995a9Smrg		    IceFreeAuthFileEntry (b->auth);
9009fe995a9Smrg		    free ((char *) b);
9019fe995a9Smrg		    b = NULL;
9029fe995a9Smrg		    tail->next = next;
9039fe995a9Smrg		    nrepl++;
9049fe995a9Smrg		    nnew--;
9059fe995a9Smrg		    break;
9069fe995a9Smrg		}
9079fe995a9Smrg	    }
9089fe995a9Smrg	    if (a == tail) break;	/* if have looked at left side */
9099fe995a9Smrg	    a = a->next;
9109fe995a9Smrg	}
9119fe995a9Smrg	if (!duplicate && b) {		/* if we didn't remove it */
9129fe995a9Smrg	    tail = b;			/* bump end of first list */
9139fe995a9Smrg	}
9149fe995a9Smrg	b = next;
9159fe995a9Smrg
9169fe995a9Smrg	if (duplicate)
9179fe995a9Smrg	    ndup++;
9189fe995a9Smrg	else
9199fe995a9Smrg	{
9209fe995a9Smrg	    n++;
9219fe995a9Smrg	    nnew++;
9229fe995a9Smrg	}
9239fe995a9Smrg    }
9249fe995a9Smrg
9259fe995a9Smrg    *nnewp = nnew;
9269fe995a9Smrg    *nreplp = nrepl;
9279fe995a9Smrg    *ndupp = ndup;
9289fe995a9Smrg    return n;
9299fe995a9Smrg
9309fe995a9Smrg}
9319fe995a9Smrg
9329fe995a9Smrg
9339fe995a9Smrgstatic int search_and_do (
9349fe995a9Smrg    const char *inputfilename,
9359fe995a9Smrg    int lineno,
9369fe995a9Smrg    int start,
9379fe995a9Smrg    int argc,
938e8ac26b0Smrg    const char *argv[],
9399fe995a9Smrg    DoFunc do_func,
9409d794632Smrg    void *data)
9419fe995a9Smrg{
9429fe995a9Smrg    int status = 0;
9439fe995a9Smrg    int errors = 0;
944772b5186Smrg    AuthList *next;
9459fe995a9Smrg
946772b5186Smrg    for (AuthList *l = iceauth_head; l; l = next)
9479fe995a9Smrg    {
948772b5186Smrg	const char *protoname, *protodata, *netid, *authname;
949772b5186Smrg
9509fe995a9Smrg	next = l->next;
9519fe995a9Smrg
9529fe995a9Smrg	protoname = protodata = netid = authname = NULL;
9539fe995a9Smrg
954772b5186Smrg	for (int i = start; i < argc; i++)
9559fe995a9Smrg	{
9569fe995a9Smrg	    if (!strncmp ("protoname=", argv[i], 10))
9579fe995a9Smrg		protoname = argv[i] + 10;
9589fe995a9Smrg	    else if (!strncmp ("protodata=", argv[i], 10))
9599fe995a9Smrg		protodata = argv[i] + 10;
9609fe995a9Smrg	    else if (!strncmp ("netid=", argv[i], 6))
9619fe995a9Smrg		netid = argv[i] + 6;
9629fe995a9Smrg	    else if (!strncmp ("authname=", argv[i], 9))
9639fe995a9Smrg		authname = argv[i] + 9;
9649fe995a9Smrg	}
9659fe995a9Smrg
9669fe995a9Smrg	status = 0;
9679fe995a9Smrg
9689fe995a9Smrg	if (protoname || protodata || netid || authname)
9699fe995a9Smrg	{
9709fe995a9Smrg	    if (protoname && strcmp (protoname, l->auth->protocol_name))
9719fe995a9Smrg		continue;
9729fe995a9Smrg
9739fe995a9Smrg	    if (protodata && !binaryEqual (protodata,
9749fe995a9Smrg		l->auth->protocol_data, l->auth->protocol_data_length))
9759fe995a9Smrg		continue;
9769fe995a9Smrg
9779fe995a9Smrg	    if (netid && strcmp (netid, l->auth->network_id))
9789fe995a9Smrg		continue;
9799fe995a9Smrg
9809fe995a9Smrg	    if (authname && strcmp (authname, l->auth->auth_name))
9819fe995a9Smrg		continue;
9829fe995a9Smrg
9839fe995a9Smrg	    status = (*do_func) (inputfilename, lineno, l->auth, data);
9849fe995a9Smrg
9859fe995a9Smrg	    if (status < 0)
9869fe995a9Smrg		break;
9879fe995a9Smrg	}
9889fe995a9Smrg    }
9899fe995a9Smrg
9909fe995a9Smrg    if (status < 0)
9919fe995a9Smrg	errors -= status;		/* since status is negative */
9929fe995a9Smrg
9939fe995a9Smrg    return (errors);
9949fe995a9Smrg}
9959fe995a9Smrg
9969fe995a9Smrg
9979fe995a9Smrg/* ARGSUSED */
9989fe995a9Smrgstatic int remove_entry (
9999d794632Smrg    const char *inputfilename _X_UNUSED,
10009d794632Smrg    int lineno _X_UNUSED,
10019fe995a9Smrg    IceAuthFileEntry *auth,
10029d794632Smrg    void *data)
10039fe995a9Smrg{
10049fe995a9Smrg    int *nremovedp = (int *) data;
10059fe995a9Smrg    AuthList **listp = &iceauth_head;
10069fe995a9Smrg    AuthList *list;
10079fe995a9Smrg
10089fe995a9Smrg    /*
10099fe995a9Smrg     * unlink the auth we were asked to
10109fe995a9Smrg     */
10119fe995a9Smrg    while ((list = *listp)->auth != auth)
10129fe995a9Smrg	listp = &list->next;
10139fe995a9Smrg    *listp = list->next;
10149fe995a9Smrg    IceFreeAuthFileEntry (list->auth);                    /* free the auth */
10159fe995a9Smrg    free (list);				    /* free the link */
10169fe995a9Smrg    iceauth_modified = True;
10179fe995a9Smrg    (*nremovedp)++;
10189fe995a9Smrg    return 1;
10199fe995a9Smrg}
10209fe995a9Smrg
10219fe995a9Smrg/*
10229fe995a9Smrg * action routines
10239fe995a9Smrg */
10249fe995a9Smrg
10259fe995a9Smrg/*
10269fe995a9Smrg * help
10279fe995a9Smrg */
10289fe995a9Smrgint print_help (
10299fe995a9Smrg    FILE *fp,
10309fe995a9Smrg    const char *cmd)
10319fe995a9Smrg{
10329fe995a9Smrg    int n = 0;
10339fe995a9Smrg
10349fe995a9Smrg    fprintf (fp, "\n");
10359fe995a9Smrg    if (!cmd) {				/* if no cmd, print all help */
1036772b5186Smrg	for (const CommandTable *ct = command_table; ct->name; ct++) {
10379fe995a9Smrg	    fprintf (fp, "%s\n\n", ct->helptext);
10389fe995a9Smrg	    n++;
10399fe995a9Smrg	}
10409fe995a9Smrg    } else {
10419d794632Smrg	size_t len = strlen (cmd);
1042772b5186Smrg	for (const CommandTable *ct = command_table; ct->name; ct++) {
10439fe995a9Smrg	    if (strncmp (cmd, ct->name, len) == 0) {
10449fe995a9Smrg		fprintf (fp, "%s\n\n", ct->helptext);
10459fe995a9Smrg		n++;
10469fe995a9Smrg	    }
10479fe995a9Smrg	}
10489fe995a9Smrg    }
10499fe995a9Smrg
10509fe995a9Smrg    return n;
10519fe995a9Smrg}
10529fe995a9Smrg
10539fe995a9Smrgstatic int do_help (
10549fe995a9Smrg    const char *inputfilename,
10559fe995a9Smrg    int lineno,
10569fe995a9Smrg    int argc,
1057e8ac26b0Smrg    const char **argv)
10589fe995a9Smrg{
1059e8ac26b0Smrg    const char *cmd = (argc > 1 ? argv[1] : NULL);
10609fe995a9Smrg    int n;
10619fe995a9Smrg
10629fe995a9Smrg    n = print_help (stdout, cmd);
10639fe995a9Smrg
10649fe995a9Smrg    if (n < 0 || (n == 0 && !cmd)) {
10659fe995a9Smrg	prefix (inputfilename, lineno);
10669fe995a9Smrg	fprintf (stderr, "internal error with help");
10679fe995a9Smrg	if (cmd) {
10689fe995a9Smrg	    fprintf (stderr, " on command \"%s\"", cmd);
10699fe995a9Smrg	}
10709fe995a9Smrg	fprintf (stderr, "\n");
10719fe995a9Smrg	return 1;
10729fe995a9Smrg    }
10739fe995a9Smrg
10749fe995a9Smrg    if (n == 0) {
10759fe995a9Smrg	prefix (inputfilename, lineno);
10769fe995a9Smrg	/* already know that cmd is set in this case */
1077e8ac26b0Smrg	fprintf (stderr, "no help for nonexistent command \"%s\"\n", cmd);
10789fe995a9Smrg    }
10799fe995a9Smrg
10809fe995a9Smrg    return 0;
10819fe995a9Smrg}
10829fe995a9Smrg
10839fe995a9Smrg/*
10849fe995a9Smrg * questionmark
10859fe995a9Smrg */
10869fe995a9Smrg/* ARGSUSED */
10879fe995a9Smrgstatic int do_questionmark (
10889d794632Smrg    const char *inputfilename _X_UNUSED,
10899d794632Smrg    int lineno _X_UNUSED,
10909d794632Smrg    int argc _X_UNUSED,
1091e8ac26b0Smrg    const char **argv _X_UNUSED)
10929fe995a9Smrg{
10939fe995a9Smrg#define WIDEST_COLUMN 72
10949d794632Smrg    unsigned int col = WIDEST_COLUMN;
10959fe995a9Smrg
10969fe995a9Smrg    printf ("Commands:\n");
1097772b5186Smrg    for (const CommandTable *ct = command_table; ct->name; ct++) {
10989fe995a9Smrg	if ((col + ct->maxlen) > WIDEST_COLUMN) {
10999fe995a9Smrg	    if (ct != command_table) {
11009fe995a9Smrg		putc ('\n', stdout);
11019fe995a9Smrg	    }
11029fe995a9Smrg	    fputs ("        ", stdout);
11039fe995a9Smrg	    col = 8;			/* length of string above */
11049fe995a9Smrg	}
11059fe995a9Smrg	fputs (ct->name, stdout);
11069fe995a9Smrg	col += ct->maxlen;
1107772b5186Smrg	for (unsigned int i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
11089fe995a9Smrg	    putc (' ', stdout);
11099fe995a9Smrg	    col++;
11109fe995a9Smrg	}
11119fe995a9Smrg    }
11129fe995a9Smrg    if (col != 0) {
11139fe995a9Smrg	putc ('\n', stdout);
11149fe995a9Smrg    }
11159fe995a9Smrg
11169fe995a9Smrg    /* allow bad lines since this is help */
11179fe995a9Smrg    return 0;
11189fe995a9Smrg}
11199fe995a9Smrg
11209fe995a9Smrg/*
11219fe995a9Smrg * list [displayname ...]
11229fe995a9Smrg */
11239fe995a9Smrgstatic int do_list (
11249fe995a9Smrg    const char *inputfilename,
11259fe995a9Smrg    int lineno,
11269fe995a9Smrg    int argc,
1127e8ac26b0Smrg    const char **argv)
11289fe995a9Smrg{
11299fe995a9Smrg    struct _list_data ld;
11309fe995a9Smrg
11319fe995a9Smrg    ld.fp = stdout;
11329fe995a9Smrg
11339fe995a9Smrg    if (argc == 1) {
11349fe995a9Smrg	if (iceauth_head) {
1135772b5186Smrg	    for (AuthList *l = iceauth_head; l; l = l->next) {
11369d794632Smrg		dump_entry (inputfilename, lineno, l->auth, &ld);
11379fe995a9Smrg	    }
11389fe995a9Smrg	}
11399fe995a9Smrg	return 0;
11409fe995a9Smrg    }
11419fe995a9Smrg    else
11429fe995a9Smrg    {
11439fe995a9Smrg	return (search_and_do (inputfilename, lineno, 1, argc, argv,
11449d794632Smrg	    dump_entry, &ld));
11459fe995a9Smrg    }
11469fe995a9Smrg}
11479fe995a9Smrg
11489fe995a9Smrg/*
11499fe995a9Smrg * merge filename [filename ...]
11509fe995a9Smrg */
11519fe995a9Smrgstatic int do_merge (
11529fe995a9Smrg    const char *inputfilename,
11539fe995a9Smrg    int lineno,
11549fe995a9Smrg    int argc,
1155e8ac26b0Smrg    const char **argv)
11569fe995a9Smrg{
11579fe995a9Smrg    int errors = 0;
1158772b5186Smrg    AuthList *listhead, *listtail;
11599fe995a9Smrg
11609fe995a9Smrg    if (argc < 2) {
11619fe995a9Smrg	prefix (inputfilename, lineno);
11629fe995a9Smrg	badcommandline (argv[0]);
11639fe995a9Smrg	return 1;
11649fe995a9Smrg    }
11659fe995a9Smrg
11669fe995a9Smrg    listhead = listtail = NULL;
11679fe995a9Smrg
1168772b5186Smrg    for (int i = 1; i < argc; i++) {
11699d794632Smrg	const char *filename = argv[i];
11709fe995a9Smrg	FILE *fp;
11719fe995a9Smrg	Bool used_stdin = False;
1172772b5186Smrg	int nentries;
1173772b5186Smrg	AuthList *head, *tail;
11749fe995a9Smrg
11759fe995a9Smrg	fp = open_file (&filename, "rb",
11769fe995a9Smrg			&used_stdin, inputfilename, lineno,
11779fe995a9Smrg			argv[0]);
11789fe995a9Smrg	if (!fp) {
11799fe995a9Smrg	    errors++;
11809fe995a9Smrg	    continue;
11819fe995a9Smrg	}
11829fe995a9Smrg
11839fe995a9Smrg	head = tail = NULL;
11849fe995a9Smrg	nentries = read_auth_entries (fp, &head, &tail);
11859fe995a9Smrg	if (nentries == 0) {
11869fe995a9Smrg	    prefix (inputfilename, lineno);
11879fe995a9Smrg	    fprintf (stderr, "unable to read any entries from file \"%s\"\n",
11889fe995a9Smrg		     filename);
11899fe995a9Smrg	    errors++;
11909fe995a9Smrg	} else {			/* link it in */
11919fe995a9Smrg	    add_to_list (listhead, listtail, head);
11929fe995a9Smrg 	}
11939fe995a9Smrg
11949fe995a9Smrg	if (!used_stdin) (void) fclose (fp);
11959fe995a9Smrg    }
11969fe995a9Smrg
11979fe995a9Smrg    /*
11989fe995a9Smrg     * if we have new entries, merge them in (freeing any duplicates)
11999fe995a9Smrg     */
12009fe995a9Smrg    if (listhead) {
1201772b5186Smrg        int nentries, nnew, nrepl, ndup;
1202772b5186Smrg
12039fe995a9Smrg	nentries = merge_entries (&iceauth_head, listhead,
12049fe995a9Smrg	    &nnew, &nrepl, &ndup);
12059fe995a9Smrg	if (verbose)
12069fe995a9Smrg	  printf ("%d entries read in:  %d new, %d replacement%s\n",
12079fe995a9Smrg	  	  nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
12089fe995a9Smrg	if (nentries > 0) iceauth_modified = True;
12099fe995a9Smrg    }
12109fe995a9Smrg
12119fe995a9Smrg    return 0;
12129fe995a9Smrg}
12139fe995a9Smrg
12149fe995a9Smrg/*
12159fe995a9Smrg * extract filename displayname [displayname ...]
12169fe995a9Smrg */
12179fe995a9Smrgstatic int do_extract (
12189fe995a9Smrg    const char *inputfilename,
12199fe995a9Smrg    int lineno,
12209fe995a9Smrg    int argc,
1221e8ac26b0Smrg    const char **argv)
12229fe995a9Smrg{
12239fe995a9Smrg    int errors;
12249fe995a9Smrg    struct _extract_data ed;
12259fe995a9Smrg
12269fe995a9Smrg    if (argc < 3) {
12279fe995a9Smrg	prefix (inputfilename, lineno);
12289fe995a9Smrg	badcommandline (argv[0]);
12299fe995a9Smrg	return 1;
12309fe995a9Smrg    }
12319fe995a9Smrg
12329fe995a9Smrg    ed.fp = NULL;
12339fe995a9Smrg    ed.filename = argv[1];
12349fe995a9Smrg    ed.nwritten = 0;
12359fe995a9Smrg    ed.cmd = argv[0];
12369fe995a9Smrg
12379fe995a9Smrg    errors = search_and_do (inputfilename, lineno, 2, argc, argv,
12389d794632Smrg	extract_entry, &ed);
12399fe995a9Smrg
12409fe995a9Smrg    if (!ed.fp) {
12419fe995a9Smrg	fprintf (stderr,
12429fe995a9Smrg		 "No matches found, authority file \"%s\" not written\n",
12439fe995a9Smrg		 ed.filename);
12449fe995a9Smrg    } else {
12459fe995a9Smrg	if (verbose) {
12469fe995a9Smrg	    printf ("%d entries written to \"%s\"\n",
12479fe995a9Smrg		    ed.nwritten, ed.filename);
12489fe995a9Smrg	}
12499fe995a9Smrg	if (!ed.used_stdout) {
12509fe995a9Smrg	    (void) fclose (ed.fp);
12519fe995a9Smrg	}
12529fe995a9Smrg    }
12539fe995a9Smrg
12549fe995a9Smrg    return errors;
12559fe995a9Smrg}
12569fe995a9Smrg
12579fe995a9Smrg
12589fe995a9Smrg/*
12599fe995a9Smrg * add protoname protodata netid authname authdata
12609fe995a9Smrg */
12619fe995a9Smrgstatic int do_add (
12629fe995a9Smrg    const char *inputfilename,
12639fe995a9Smrg    int lineno,
12649fe995a9Smrg    int argc,
1265e8ac26b0Smrg    const char **argv)
12669fe995a9Smrg{
12679fe995a9Smrg    int n, nnew, nrepl, ndup;
1268e8ac26b0Smrg    const char *protoname;
1269e8ac26b0Smrg    const char *protodata_hex;
12709fe995a9Smrg    char *protodata = NULL; /* not required */
1271e8ac26b0Smrg    const char *netid;
1272e8ac26b0Smrg    const char *authname;
1273e8ac26b0Smrg    const char *authdata_hex;
12749fe995a9Smrg    char *authdata = NULL;
12759fe995a9Smrg    int protodata_len, authdata_len;
12769fe995a9Smrg    IceAuthFileEntry *auth = NULL;
12779fe995a9Smrg    AuthList *list;
12789fe995a9Smrg    int status = 0;
12799fe995a9Smrg
12809fe995a9Smrg    if (argc != 6 || !argv[1] || !argv[2] ||
12819fe995a9Smrg	!argv[3] || !argv[4] || !argv[5])
12829fe995a9Smrg    {
12839fe995a9Smrg	prefix (inputfilename, lineno);
12849fe995a9Smrg	badcommandline (argv[0]);
12859fe995a9Smrg	return 1;
12869fe995a9Smrg    }
12879fe995a9Smrg
12889fe995a9Smrg    protoname = argv[1];
12899fe995a9Smrg    protodata_hex = argv[2];
12909fe995a9Smrg    netid = argv[3];
12919fe995a9Smrg    authname = argv[4];
12929fe995a9Smrg    authdata_hex = argv[5];
12939fe995a9Smrg
12949fe995a9Smrg    protodata_len = strlen (protodata_hex);
12959fe995a9Smrg    if (protodata_len > 0)
12969fe995a9Smrg    {
1297c048b52eSmrg	if (protodata_len > 1 &&
1298c048b52eSmrg	    protodata_hex[0] == '"' && protodata_hex[protodata_len - 1] == '"')
12999fe995a9Smrg	{
13009fe995a9Smrg	    protodata = malloc (protodata_len - 1);
13019fe995a9Smrg	    if (protodata)
13029fe995a9Smrg	    {
13039fe995a9Smrg		strncpy (protodata, protodata_hex + 1, protodata_len - 2);
13049fe995a9Smrg		protodata_len -= 2;
13059fe995a9Smrg	    }
13069fe995a9Smrg	    else
13079fe995a9Smrg		goto add_bad_malloc;
13089fe995a9Smrg	}
13099fe995a9Smrg	else
13109fe995a9Smrg	{
13119fe995a9Smrg	    protodata_len = cvthexkey (protodata_hex, &protodata);
13129fe995a9Smrg	    if (protodata_len < 0)
13139fe995a9Smrg	    {
13149fe995a9Smrg		prefix (inputfilename, lineno);
13159fe995a9Smrg		fprintf (stderr,
13169fe995a9Smrg	       "protodata_hex contains odd number of or non-hex characters\n");
13179fe995a9Smrg		return (1);
13189fe995a9Smrg	    }
13199fe995a9Smrg	}
13209fe995a9Smrg    }
13219fe995a9Smrg
13229fe995a9Smrg    authdata_len = strlen (authdata_hex);
1323c048b52eSmrg    if (authdata_len > 1 &&
1324c048b52eSmrg	authdata_hex[0] == '"' && authdata_hex[authdata_len - 1] == '"')
13259fe995a9Smrg    {
13269fe995a9Smrg	authdata = malloc (authdata_len - 1);
13279fe995a9Smrg	if (authdata)
13289fe995a9Smrg	{
13299fe995a9Smrg	    strncpy (authdata, authdata_hex + 1, authdata_len - 2);
13309fe995a9Smrg	    authdata_len -= 2;
13319fe995a9Smrg	}
13329fe995a9Smrg	else
13339fe995a9Smrg	    goto add_bad_malloc;
13349fe995a9Smrg    }
13359fe995a9Smrg    else if (!strcmp (protoname, SECURERPC) || !strcmp (protoname, K5AUTH))
13369fe995a9Smrg    {
13379fe995a9Smrg	authdata = malloc (authdata_len + 1);
13389fe995a9Smrg	if (authdata)
13399fe995a9Smrg	    strcpy (authdata, authdata_hex);
13409fe995a9Smrg	else
13419fe995a9Smrg	    goto add_bad_malloc;
13429fe995a9Smrg    }
13439fe995a9Smrg    else
13449fe995a9Smrg    {
13459fe995a9Smrg	authdata_len = cvthexkey (authdata_hex, &authdata);
13469fe995a9Smrg	if (authdata_len < 0)
13479fe995a9Smrg	{
13489fe995a9Smrg	    prefix (inputfilename, lineno);
13499fe995a9Smrg	    fprintf (stderr,
13509fe995a9Smrg	       "authdata_hex contains odd number of or non-hex characters\n");
13519fe995a9Smrg	    free (protodata);
13529fe995a9Smrg	    return (1);
13539fe995a9Smrg	}
13549fe995a9Smrg    }
13559fe995a9Smrg
13569fe995a9Smrg    auth = (IceAuthFileEntry *) malloc (sizeof (IceAuthFileEntry));
13579fe995a9Smrg
13589fe995a9Smrg    if (!auth)
13599fe995a9Smrg	goto add_bad_malloc;
13609fe995a9Smrg
13619fe995a9Smrg    auth->protocol_name = copystring (protoname);
13629fe995a9Smrg    auth->protocol_data_length = protodata_len;
13639fe995a9Smrg    auth->protocol_data = protodata;
13649fe995a9Smrg    auth->network_id = copystring (netid);
13659fe995a9Smrg    auth->auth_name = copystring (authname);
13669fe995a9Smrg    auth->auth_data_length = authdata_len;
13679fe995a9Smrg    auth->auth_data = authdata;
13689fe995a9Smrg
13699fe995a9Smrg    if (!auth->protocol_name ||
13709fe995a9Smrg	(!auth->protocol_data && auth->protocol_data_length > 0) ||
13719fe995a9Smrg        !auth->network_id || !auth->auth_name ||
13729fe995a9Smrg	(!auth->auth_data && auth->auth_data_length > 0))
13739fe995a9Smrg    {
13749fe995a9Smrg	goto add_bad_malloc;
13759fe995a9Smrg    }
13769fe995a9Smrg
13779fe995a9Smrg    list = (AuthList *) malloc (sizeof (AuthList));
13789fe995a9Smrg
13799fe995a9Smrg    if (!list)
13809fe995a9Smrg	goto add_bad_malloc;
13819fe995a9Smrg
13829fe995a9Smrg    list->next = NULL;
13839fe995a9Smrg    list->auth = auth;
13849fe995a9Smrg
13859fe995a9Smrg    /*
13869fe995a9Smrg     * merge it in; note that merge will deal with allocation
13879fe995a9Smrg     */
13889fe995a9Smrg
13899fe995a9Smrg    n = merge_entries (&iceauth_head, list, &nnew, &nrepl, &ndup);
13909fe995a9Smrg
13919fe995a9Smrg    if (n > 0)
13929fe995a9Smrg	iceauth_modified = True;
13939fe995a9Smrg    else
13949fe995a9Smrg    {
13959fe995a9Smrg	prefix (inputfilename, lineno);
13969fe995a9Smrg	if (ndup > 0)
13979fe995a9Smrg	{
13989fe995a9Smrg	    status = 0;
13999fe995a9Smrg	    fprintf (stderr, "no records added - all duplicate\n");
14009fe995a9Smrg	}
14019fe995a9Smrg	else
14029fe995a9Smrg	{
14039fe995a9Smrg	    status = 1;
14049fe995a9Smrg	    fprintf (stderr, "unable to merge in added record\n");
14059fe995a9Smrg	}
14069fe995a9Smrg	goto cant_add;
14079fe995a9Smrg    }
14089fe995a9Smrg
14099fe995a9Smrg    return 0;
14109fe995a9Smrg
14119fe995a9Smrg
14129fe995a9Smrgadd_bad_malloc:
14139fe995a9Smrg
14149fe995a9Smrg    status = 1;
14159fe995a9Smrg    prefix (inputfilename, lineno);
14169fe995a9Smrg    fprintf (stderr, "unable to allocate memory to add an entry\n");
14179fe995a9Smrg
14189fe995a9Smrgcant_add:
14199fe995a9Smrg
14209fe995a9Smrg    if (protodata)
14219fe995a9Smrg	free (protodata);
14229fe995a9Smrg    if (authdata)
14239fe995a9Smrg	free (authdata);
14249fe995a9Smrg    if (auth)
14259fe995a9Smrg    {
14269fe995a9Smrg	if (auth->protocol_name)
14279fe995a9Smrg	    free (auth->protocol_name);
14289fe995a9Smrg	/* auth->protocol_data already freed,
14299fe995a9Smrg	   since it's the same as protodata */
14309fe995a9Smrg	if (auth->network_id)
14319fe995a9Smrg	    free (auth->network_id);
14329fe995a9Smrg	if (auth->auth_name)
14339fe995a9Smrg	    free (auth->auth_name);
14349fe995a9Smrg	/* auth->auth_data already freed,
14359fe995a9Smrg	   since it's the same as authdata */
14369fe995a9Smrg	free ((char *) auth);
14379fe995a9Smrg    }
14389fe995a9Smrg
14399fe995a9Smrg    return status;
14409fe995a9Smrg}
14419fe995a9Smrg
14429fe995a9Smrg/*
14439fe995a9Smrg * remove displayname
14449fe995a9Smrg */
14459fe995a9Smrgstatic int do_remove (
14469fe995a9Smrg    const char *inputfilename,
14479fe995a9Smrg    int lineno,
14489fe995a9Smrg    int argc,
1449e8ac26b0Smrg    const char **argv)
14509fe995a9Smrg{
14519fe995a9Smrg    int nremoved = 0;
14529fe995a9Smrg    int errors;
14539fe995a9Smrg
14549fe995a9Smrg    if (argc < 2) {
14559fe995a9Smrg	prefix (inputfilename, lineno);
14569fe995a9Smrg	badcommandline (argv[0]);
14579fe995a9Smrg	return 1;
14589fe995a9Smrg    }
14599fe995a9Smrg
14609fe995a9Smrg    errors = search_and_do (inputfilename, lineno, 1, argc, argv,
14619d794632Smrg	remove_entry, &nremoved);
14629fe995a9Smrg    if (verbose) printf ("%d entries removed\n", nremoved);
14639fe995a9Smrg    return errors;
14649fe995a9Smrg}
14659fe995a9Smrg
14669fe995a9Smrg/*
14679fe995a9Smrg * info
14689fe995a9Smrg */
14699fe995a9Smrgstatic int do_info (
14709fe995a9Smrg    const char *inputfilename,
14719fe995a9Smrg    int lineno,
14729fe995a9Smrg    int argc,
1473e8ac26b0Smrg    const char **argv)
14749fe995a9Smrg{
14759fe995a9Smrg    int n;
14769fe995a9Smrg    AuthList *l;
14779fe995a9Smrg
14789fe995a9Smrg    if (argc != 1) {
14799fe995a9Smrg	prefix (inputfilename, lineno);
14809fe995a9Smrg	badcommandline (argv[0]);
14819fe995a9Smrg	return 1;
14829fe995a9Smrg    }
14839fe995a9Smrg
14849fe995a9Smrg    for (l = iceauth_head, n = 0; l; l = l->next, n++) ;
14859fe995a9Smrg
14869fe995a9Smrg    printf ("Authority file:       %s\n",
14879fe995a9Smrg	    iceauth_filename ? iceauth_filename : "(none)");
14889fe995a9Smrg    printf ("File new:             %s\n", iceauth_existed ? No : Yes);
14899fe995a9Smrg    printf ("File locked:          %s\n", ignore_locks ? No : Yes);
14909fe995a9Smrg    printf ("Number of entries:    %d\n", n);
14919fe995a9Smrg    printf ("Changes honored:      %s\n", iceauth_allowed ? Yes : No);
14929fe995a9Smrg    printf ("Changes made:         %s\n", iceauth_modified ? Yes : No);
14939fe995a9Smrg    printf ("Current input:        %s:%d\n", inputfilename, lineno);
14949fe995a9Smrg    return 0;
14959fe995a9Smrg}
14969fe995a9Smrg
14979fe995a9Smrg
14989fe995a9Smrg/*
14999fe995a9Smrg * exit
15009fe995a9Smrg */
15019fe995a9Smrgstatic Bool alldone = False;
15029fe995a9Smrg
15039fe995a9Smrg/* ARGSUSED */
15049fe995a9Smrgstatic int do_exit (
15059d794632Smrg    const char *inputfilename _X_UNUSED,
15069d794632Smrg    int lineno _X_UNUSED,
15079d794632Smrg    int argc _X_UNUSED,
1508e8ac26b0Smrg    const char **argv _X_UNUSED)
15099fe995a9Smrg{
15109fe995a9Smrg    /* allow bogus stuff */
15119fe995a9Smrg    alldone = True;
15129fe995a9Smrg    return 0;
15139fe995a9Smrg}
15149fe995a9Smrg
15159fe995a9Smrg/*
15169fe995a9Smrg * quit
15179fe995a9Smrg */
15189fe995a9Smrg/* ARGSUSED */
15199fe995a9Smrgstatic int do_quit (
15209d794632Smrg    const char *inputfilename _X_UNUSED,
15219d794632Smrg    int lineno _X_UNUSED,
15229d794632Smrg    int argc _X_UNUSED,
1523e8ac26b0Smrg    const char **argv _X_UNUSED)
15249fe995a9Smrg{
15259fe995a9Smrg    /* allow bogus stuff */
15269fe995a9Smrg    die (0);
15279fe995a9Smrg    /* NOTREACHED */
15289fe995a9Smrg    return -1;				/* for picky compilers */
15299fe995a9Smrg}
15309fe995a9Smrg
15319fe995a9Smrg
15329fe995a9Smrg/*
15339fe995a9Smrg * source filename
15349fe995a9Smrg */
15359fe995a9Smrgstatic int do_source (
15369fe995a9Smrg    const char *inputfilename,
15379fe995a9Smrg    int lineno,
15389fe995a9Smrg    int argc,
1539e8ac26b0Smrg    const char **argv)
15409fe995a9Smrg{
15419d794632Smrg    const char *script;
15429fe995a9Smrg    FILE *fp;
15439fe995a9Smrg    Bool used_stdin = False;
1544772b5186Smrg    int errors = 0;
15459fe995a9Smrg    int sublineno = 0;
15469fe995a9Smrg    Bool prompt = False;		/* only true if reading from tty */
15479fe995a9Smrg
15489fe995a9Smrg    if (argc != 2 || !argv[1]) {
15499fe995a9Smrg	prefix (inputfilename, lineno);
15509fe995a9Smrg	badcommandline (argv[0]);
15519fe995a9Smrg	return 1;
15529fe995a9Smrg    }
15539fe995a9Smrg
15549fe995a9Smrg    script = argv[1];
15559fe995a9Smrg
15569fe995a9Smrg    fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
15579fe995a9Smrg    if (!fp) {
15589fe995a9Smrg	return 1;
15599fe995a9Smrg    }
15609fe995a9Smrg
15619fe995a9Smrg    if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
15629fe995a9Smrg
15639fe995a9Smrg    while (!alldone) {
1564772b5186Smrg	char buf[BUFSIZ];
1565772b5186Smrg	size_t len;
1566772b5186Smrg	char **subargv;
1567772b5186Smrg	int subargc;
1568772b5186Smrg
15699fe995a9Smrg	buf[0] = '\0';
15709fe995a9Smrg	if (prompt) {
15719fe995a9Smrg	    printf ("iceauth> ");
15729fe995a9Smrg	    fflush (stdout);
15739fe995a9Smrg	}
15749fe995a9Smrg	if (fgets (buf, sizeof buf, fp) == NULL) break;
15759fe995a9Smrg	sublineno++;
15769fe995a9Smrg	len = strlen (buf);
15779fe995a9Smrg	if (len == 0 || buf[0] == '#') continue;
15789fe995a9Smrg	if (buf[len-1] != '\n') {
15799fe995a9Smrg	    prefix (script, sublineno);
15809fe995a9Smrg	    fprintf (stderr, "line too long\n");
15819fe995a9Smrg	    errors++;
15829fe995a9Smrg	    break;
15839fe995a9Smrg	}
15849fe995a9Smrg	buf[--len] = '\0';		/* remove new line */
15859fe995a9Smrg	subargv = split_into_words (buf, &subargc);
15869fe995a9Smrg	if (subargv) {
1587772b5186Smrg	    int status = process_command (script, sublineno, subargc,
1588772b5186Smrg                                          (const char **) subargv);
15899fe995a9Smrg	    free ((char *) subargv);
15909fe995a9Smrg	    errors += status;
15919fe995a9Smrg	} else {
15929fe995a9Smrg	    prefix (script, sublineno);
15939fe995a9Smrg	    fprintf (stderr, "unable to break line into words\n");
15949fe995a9Smrg	    errors++;
15959fe995a9Smrg	}
15969fe995a9Smrg    }
15979fe995a9Smrg
15989fe995a9Smrg    if (!used_stdin) {
15999fe995a9Smrg	(void) fclose (fp);
16009fe995a9Smrg    }
16019fe995a9Smrg    return errors;
16029fe995a9Smrg}
1603