process.c revision 9d794632
11.198Senami/*
21.147Simp *
31.1SchristosCopyright 1989, 1998  The Open Group
41.14Schristos
51.14SchristosPermission to use, copy, modify, distribute, and sell this software and its
61.1Schristosdocumentation for any purpose is hereby granted without fee, provided that
71.1Schristosthe above copyright notice appear in all copies and that both that
81.14Schristoscopyright notice and this permission notice appear in supporting
91.14Schristosdocumentation.
101.14Schristos
111.1SchristosThe above copyright notice and this permission notice shall be included in
121.1Schristosall copies or substantial portions of the Software.
131.1Schristos
141.1SchristosTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
151.1SchristosIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161.1SchristosFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
171.1SchristosOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
181.1SchristosAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
191.1SchristosCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
201.1Schristos
211.14SchristosExcept as contained in this notice, the name of The Open Group shall not be
221.14Schristosused in advertising or otherwise to promote the sale, use or other dealings
231.14Schristosin this Software without prior written authorization from The Open Group.
241.14Schristos * *
251.14Schristos * Original Author of "xauth" : Jim Fulton, MIT X Consortium
261.1Schristos * Modified into "iceauth"    : Ralph Mor, X Consortium
271.14Schristos */
281.14Schristos
291.14Schristos#include "iceauth.h"
301.14Schristos#include <ctype.h>
311.14Schristos#include <errno.h>
321.14Schristos#include <sys/types.h>
331.14Schristos#include <sys/stat.h>
341.14Schristos#include <signal.h>
351.14Schristos
361.14Schristos#define SECURERPC "SUN-DES-1"
371.14Schristos#define K5AUTH "KERBEROS-V5-1"
381.1Schristos
391.1Schristos#define ICEAUTH_DEFAULT_RETRIES 10	/* number of competitors we expect */
401.1Schristos#define ICEAUTH_DEFAULT_TIMEOUT 2	/* in seconds, be quick */
411.140Simp#define ICEAUTH_DEFAULT_DEADTIME 600L	/* 10 minutes in seconds */
421.1Schristos
431.1Schristostypedef struct _AuthList {		/* linked list of entries */
441.31Snathanw    struct _AuthList *next;
451.176Smason    IceAuthFileEntry *auth;
461.83Smycroft} AuthList;
471.15Skenh
481.40Shwr#define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);}
491.65Sjoda
501.1Schristostypedef int (*ProcessFunc)(const char *, int, int, char **);
511.183Sgmcgarrytypedef int (*DoFunc)(const char *, int, IceAuthFileEntry *, void *);
521.1Schristos
531.1Schristostypedef struct _CommandTable {		/* commands that are understood */
541.1Schristos    const char *name;			/* full name */
551.1Schristos    unsigned int minlen;		/* unique prefix */
561.65Sjoda    unsigned int maxlen;		/* strlen(name) */
571.11Sthorpej    ProcessFunc processfunc;		/* handler */
581.147Simp    const char *helptext;		/* what to print for help */
591.128Sichiro} CommandTable;
601.1Schristos
611.140Simpstruct _extract_data {			/* for iterating */
621.147Simp    FILE *fp;				/* input source */
631.1Schristos    const char *filename;		/* name of input */
641.1Schristos    Bool used_stdout;			/* whether or not need to close */
651.147Simp    int nwritten;			/* number of entries written */
661.65Sjoda    const char *cmd;			/* for error messages */
671.175Srjs};
681.140Simp
691.171Sjonathanstruct _list_data {			/* for iterating */
701.1Schristos    FILE *fp;				/* output file */
711.147Simp};
721.4Sthorpej
731.147Simp
741.39Ssommerfe/*
751.66Sjlam * private data
761.158Sjoda */
771.135Spookastatic const char *stdin_filename = "(stdin)";  /* for messages */
781.65Sjodastatic const char *stdout_filename = "(stdout)";  /* for messages */
791.111Simpstatic const char *Yes = "yes";		/* for messages */
801.1Schristosstatic const char *No = "no";			/* for messages */
811.67Schopps
821.98Simpstatic int binaryEqual ( const char *a, const char *b, unsigned len );
831.55Ssommerfestatic void prefix ( const char *fn, int n );
841.92Sonoestatic void badcommandline ( const char *cmd );
851.99Smsaitohstatic char *skip_space ( char *s );
861.85Smycroftstatic char *skip_nonspace ( char *s );
871.97Sonoestatic char **split_into_words ( char *src, int *argcp );
881.189Sichirostatic FILE *open_file ( const char **filenamep, const char *mode, Bool *usedstdp, const char *srcfn, int srcln, const char *cmd );
891.196Smycroftstatic int read_auth_entries ( FILE *fp, AuthList **headp, AuthList **tailp );
901.136Sichirostatic int cvthexkey ( const char *hexstr, char **ptrp );
911.125Sichirostatic int dispatch_command ( const char *inputfilename, int lineno, int argc, char **argv, const CommandTable *tab, int *statusp );
921.159Saymericstatic void die ( int sig ) _X_NORETURN;
931.122Sichirostatic void catchsig ( int sig ) _X_NORETURN;
941.147Simpstatic void register_signals ( void );
951.147Simpstatic int write_auth_file ( char *tmp_nam, size_t tmp_nam_len );
961.172Smartinstatic void fprintfhex ( FILE *fp, unsigned int len, const char *cp );
971.38Smjlstatic int dump_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
981.72Ssorenstatic int extract_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
991.147Simpstatic int match_auth ( IceAuthFileEntry *a, IceAuthFileEntry *b, int *authDataSame );
1001.147Simpstatic int merge_entries ( AuthList **firstp, AuthList *second, int *nnewp, int *nreplp, int *ndupp );
1011.159Saymericstatic int search_and_do ( const char *inputfilename, int lineno, int start, int argc, char *argv[], DoFunc do_func, void *data );
1021.25Sthorpejstatic int remove_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
1031.78Senamistatic int do_help ( const char *inputfilename, int lineno, int argc, char **argv );
1041.134Schristosstatic int do_questionmark ( const char *inputfilename, int lineno, int argc, char **argv );
1051.43Stronstatic int do_list ( const char *inputfilename, int lineno, int argc, char **argv );
1061.99Smsaitohstatic int do_merge ( const char *inputfilename, int lineno, int argc, char **argv );
1071.110Snonakastatic int do_extract ( const char *inputfilename, int lineno, int argc, char **argv );
1081.22Sthorpejstatic int do_add ( const char *inputfilename, int lineno, int argc, char **argv );
1091.43Stronstatic int do_remove ( const char *inputfilename, int lineno, int argc, char **argv );
1101.15Skenhstatic int do_info ( const char *inputfilename, int lineno, int argc, char **argv );
1111.89Sisstatic int do_exit ( const char *inputfilename, int lineno, int argc, char **argv );
1121.195Smycroftstatic int do_quit ( const char *inputfilename, int lineno, int argc, char **argv );
1131.108Sichirostatic int do_source ( const char *inputfilename, int lineno, int argc, char **argv );
1141.191Sitohy
1151.1Schristosstatic const CommandTable command_table[] = {	/* table of known commands */
1161.1Schristos{ "add", 2, 3, do_add,
1171.140Simp"\
1181.140Simpadd       add an entry\n\
1191.1Schristos          add protoname protodata netid authname authdata"
1201.58Ssoren},
1211.1Schristos
1221.94Sjoda{ "exit", 3, 4, do_exit,
1231.140Simp"\
1241.140Simpexit      save changes and exit program"
1251.140Simp},
1261.140Simp
1271.1Schristos{ "extract", 3, 7, do_extract,
1281.1Schristos"\
1291.13Sthorpejextract   extract entries into file\n\
1301.147Simp          extract filename <protoname=$> <protodata=$> <netid=$> <authname=$>"
1311.132Sitojun},
1321.172Smartin
1331.172Smartin{ "help", 1, 4, do_help,
1341.172Smartin"\
1351.24Sthorpejhelp      print help\n\
1361.140Simp          help <topic>"
1371.140Simp},
1381.140Simp
1391.140Simp{ "info", 1, 4, do_info,
1401.140Simp"\
1411.140Simpinfo      print information about entries"
1421.140Simp},
1431.140Simp
1441.140Simp{ "list", 1, 4, do_list,
1451.140Simp"\
1461.140Simplist      list entries\n\
1471.189Sichiro          list <protoname=$> <protodata=$> <netid=$> <authname=$>"
1481.189Sichiro},
1491.189Sichiro
1501.189Sichiro{ "merge", 1, 5, do_merge,
1511.140Simp"\
1521.147Simpmerge     merge entries from files\n\
1531.147Simp          merge filename1 <filename2> <filename3> ..."
1541.147Simp},
1551.196Smycroft
1561.196Smycroft{ "quit", 1, 4, do_quit,
1571.196Smycroft"\
1581.140Simpquit      abort changes and exit program" },
1591.140Simp
1601.140Simp{ "remove", 1, 6, do_remove,
1611.140Simp"\
1621.169Smycroftremove    remove entries\n\
1631.140Simp          remove <protoname=$> <protodata=$> <netid=$> <authname=$>"
1641.147Simp},
1651.147Simp
1661.147Simp{ "source", 1, 6, do_source,
1671.140Simp"\
1681.140Simpsource    read commands from file\n\
1691.198Senami          source filename"
1701.198Senami},
1711.150Senami
1721.140Simp{ "?", 1, 1, do_questionmark,
1731.90Sgmcgarry"\
1741.140Simp?         list available commands" },
1751.90Sgmcgarry
1761.90Sgmcgarry{ NULL, 0, 0, NULL, NULL },
1771.24Sthorpej};
1781.147Simp
1791.24Sthorpej#define COMMAND_NAMES_PADDED_WIDTH 10	/* wider than anything above */
1801.37Smjl
1811.140Simp
1821.140Simpstatic Bool okay_to_use_stdin = True;	/* set to false after using */
1831.140Simp
1841.1Schristosstatic const char * const hex_table[] = {	/* for printing hex digits */
1851.1Schristos    "00", "01", "02", "03", "04", "05", "06", "07",
1861.16Sdbj    "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
1871.16Sdbj    "10", "11", "12", "13", "14", "15", "16", "17",
1881.1Schristos    "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
1891.15Skenh    "20", "21", "22", "23", "24", "25", "26", "27",
1901.15Skenh    "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
1911.120Sthorpej    "30", "31", "32", "33", "34", "35", "36", "37",
1921.120Sthorpej    "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
1931.120Sthorpej    "40", "41", "42", "43", "44", "45", "46", "47",
1941.101Shubertf    "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
1951.147Simp    "50", "51", "52", "53", "54", "55", "56", "57",
1961.147Simp    "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
1971.157Saymeric    "60", "61", "62", "63", "64", "65", "66", "67",
1981.157Saymeric    "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
1991.157Saymeric    "70", "71", "72", "73", "74", "75", "76", "77",
2001.147Simp    "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
2011.101Shubertf    "80", "81", "82", "83", "84", "85", "86", "87",
2021.101Shubertf    "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
2031.101Shubertf    "90", "91", "92", "93", "94", "95", "96", "97",
2041.144Sichiro    "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
2051.173Smartin    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
2061.31Snathanw    "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
2071.140Simp    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
2081.140Simp    "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
2091.158Sjoda    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
2101.158Sjoda    "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
2111.158Sjoda    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
2121.140Simp    "d8", "d9", "da", "db", "dc", "dd", "de", "df",
2131.140Simp    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
2141.140Simp    "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
2151.140Simp    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
2161.31Snathanw    "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
2171.32Snathanw};
2181.140Simp
2191.34Sthorpejstatic unsigned int hexvalues[256];	/* for parsing hex input */
2201.191Sitohy
2211.1Schristosstatic mode_t original_umask = 0;	/* for restoring */
2221.1Schristos
2231.103Sdrochner
2241.93Ssoren/*
2251.93Ssoren * private utility procedures
2261.93Ssoren */
2271.93Ssoren
2281.149Syamt#define copystring(s)	( s != NULL ? strdup(s) : NULL )
2291.93Ssoren
2301.1Schristosstatic int
2311.191SitohybinaryEqual (
2321.155Sichiro    register const char	*a,
2331.59Ssoren    register const char	*b,
2341.1Schristos    register unsigned	len)
2351.90Sgmcgarry
2361.140Simp{
2371.90Sgmcgarry    while (len--)
2381.90Sgmcgarry	if (*a++ != *b++)
2391.1Schristos	    return 0;
2401.56Senami    return 1;
2411.122Sichiro}
2421.192Ssekiya
2431.92Sonoestatic void prefix (const char *fn, int n)
2441.140Simp{
2451.140Simp    fprintf (stderr, "%s: %s:%d:  ", ProgramName, fn, n);
2461.140Simp}
2471.140Simp
2481.140Simpstatic void badcommandline (const char *cmd)
2491.72Ssoren{
2501.72Ssoren    fprintf (stderr, "bad \"%s\" command line\n", cmd);
2511.102Ssoren}
2521.1Schristos
2531.1Schristosstatic char *skip_space (register char *s)
2541.140Simp{
2551.73Sthorpej    if (!s) return NULL;
2561.21Sitohy
2571.1Schristos    for ( ; *s && isascii(*s) && isspace(*s); s++)
2581.147Simp	;
2591.164Sichiro    return s;
2601.167Sonoe}
2611.140Simp
2621.140Simp
2631.140Simpstatic char *skip_nonspace (register char *s)
2641.140Simp{
2651.140Simp    if (!s) return NULL;
2661.140Simp
2671.1Schristos    /* put quoting into loop if need be */
2681.1Schristos    for ( ; *s && isascii(*s) && !isspace(*s); s++)
2691.191Sitohy	;
2701.1Schristos    return s;
2711.58Ssoren}
2721.18Sthorpej
2731.147Simpstatic char **split_into_words (  /* argvify string */
2741.1Schristos    char *src,
2751.1Schristos    int *argcp)
2761.78Senami{
2771.191Sitohy    char *jword;
2781.128Sichiro    char savec;
2791.140Simp    char **argv;
2801.140Simp    int cur, total;
2811.140Simp
2821.147Simp    *argcp = 0;
2831.140Simp#define WORDSTOALLOC 4			/* most lines are short */
2841.140Simp    argv = (char **) malloc (WORDSTOALLOC * sizeof (char *));
2851.140Simp    if (!argv) return NULL;
2861.147Simp    cur = 0;
2871.147Simp    total = WORDSTOALLOC;
2881.147Simp
2891.140Simp    /*
2901.147Simp     * split the line up into separate, nul-terminated tokens; the last
2911.147Simp     * "token" will point to the empty string so that it can be bashed into
2921.147Simp     * a null pointer.
2931.147Simp     */
2941.175Srjs
2951.147Simp    do {
2961.166Schris	jword = skip_space (src);
2971.176Smason	src = skip_nonspace (jword);
2981.140Simp	savec = *src;
2991.128Sichiro	*src = '\0';
3001.191Sitohy	if (cur == total) {
3011.85Smycroft	    total += WORDSTOALLOC;
3021.195Smycroft	    argv = (char **) realloc (argv, total * sizeof (char *));
3031.195Smycroft	    if (!argv) return NULL;
3041.195Smycroft	}
3051.85Smycroft	argv[cur++] = jword;
3061.85Smycroft	if (savec) src++;		/* if not last on line advance */
3071.91Ssoren    } while (jword != src);
3081.91Ssoren
3091.91Ssoren    argv[--cur] = NULL;			/* smash empty token to end list */
3101.175Srjs    *argcp = cur;
3111.175Srjs    return argv;
3121.175Srjs}
3131.83Smycroft
3141.83Smycroft
3151.83Smycroftstatic FILE *open_file (
3161.88Sjoda    const char **filenamep,
3171.141Schristos    const char *mode,
3181.147Simp    Bool *usedstdp,
3191.147Simp    const char *srcfn,
3201.147Simp    int srcln,
3211.147Simp    const char *cmd)
3221.147Simp{
3231.135Spooka    FILE *fp;
3241.135Spooka
3251.135Spooka    if (strcmp (*filenamep, "-") == 0) {
3261.78Senami	*usedstdp = True;
3271.147Simp					/* select std descriptor to use */
3281.185Sichiro	if (mode[0] == 'r') {
3291.147Simp	    if (okay_to_use_stdin) {
3301.147Simp		okay_to_use_stdin = False;
3311.140Simp		*filenamep = stdin_filename;
3321.140Simp		return stdin;
3331.140Simp	    } else {
3341.140Simp		prefix (srcfn, srcln);
3351.140Simp		fprintf (stderr, "%s:  stdin already in use\n", cmd);
3361.140Simp		return NULL;
3371.140Simp	    }
3381.140Simp	} else {
3391.4Sthorpej	    *filenamep = stdout_filename;
3401.15Skenh	    return stdout;		/* always okay to use stdout */
3411.15Skenh	}
3421.183Sgmcgarry    }
3431.183Sgmcgarry
3441.183Sgmcgarry    fp = fopen (*filenamep, mode);
3451.15Skenh    if (!fp) {
3461.4Sthorpej	prefix (srcfn, srcln);
3471.4Sthorpej	fprintf (stderr, "%s:  unable to open file %s\n", cmd, *filenamep);
3481.39Ssommerfe    }
3491.39Ssommerfe    return fp;
3501.1Schristos}
3511.140Simp
3521.140Simp
3531.140Simpstatic int read_auth_entries (FILE *fp, AuthList **headp, AuthList **tailp)
3541.140Simp{
3551.1Schristos    IceAuthFileEntry *auth;
3561.127Sjhawk    AuthList *head, *tail;
3571.156Spooka    int n;
3581.1Schristos
3591.19Sthorpej    head = tail = NULL;
3601.140Simp    n = 0;
3611.100Stoddpw					/* put all records into linked list */
3621.184Smartin    while ((auth = IceReadAuthFileEntry (fp)) != NULL) {
3631.140Simp	AuthList *l = (AuthList *) malloc (sizeof (AuthList));
3641.140Simp	if (!l) {
3651.140Simp	    fprintf (stderr,
3661.1Schristos		     "%s:  unable to alloc entry reading auth file\n",
3671.1Schristos		     ProgramName);
3681.140Simp	    exit (1);
3691.1Schristos	}
3701.140Simp	l->next = NULL;
3711.163Smartin	l->auth = auth;
3721.1Schristos	if (tail) 			/* if not first time through append */
3731.140Simp	  tail->next = l;
3741.140Simp	else
3751.140Simp	  head = l;			/* first time through, so assign */
3761.140Simp	tail = l;
3771.140Simp	n++;
3781.140Simp    }
3791.20Sthorpej    *headp = head;
3801.90Sgmcgarry    *tailp = tail;
3811.90Sgmcgarry    return n;
3821.147Simp}
3831.90Sgmcgarry
3841.145Schristos
3851.140Simpstatic int cvthexkey (	/* turn hex key string into octets */
3861.140Simp    const char *hexstr,
3871.114Sthorpej    char **ptrp)
3881.90Sgmcgarry{
3891.140Simp    unsigned int i;
3901.90Sgmcgarry    unsigned int len = 0;
3911.96Sgmcgarry    char *retval;
3921.96Sgmcgarry    const char *s;
3931.134Schristos    unsigned char *us;
3941.134Schristos    char c;
3951.134Schristos    char savec = '\0';
3961.134Schristos
3971.140Simp    /* count */
3981.140Simp    for (s = hexstr; *s; s++) {
3991.140Simp	if (!isascii(*s)) return -1;
4001.195Smycroft	if (isspace(*s)) continue;
4011.140Simp	if (!isxdigit(*s)) return -1;
4021.140Simp	len++;
4031.140Simp    }
4041.140Simp
4051.191Sitohy    /* if 0 or odd, then there was an error */
4061.191Sitohy    if (len == 0 || (len & 1) == 1) return -1;
4071.174Smjl
4081.140Simp
4091.62Sdanw    /* now we know that the input is good */
4101.64Saugustss    len >>= 1;
4111.147Simp    retval = malloc (len);
4121.196Smycroft    if (!retval) {
4131.76Senami	fprintf (stderr, "%s:  unable to allocate %d bytes for hexkey\n",
4141.95Sonoe		 ProgramName, len);
4151.160Sis	return -1;
4161.140Simp    }
4171.147Simp
4181.191Sitohy    for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
4191.140Simp	c = *hexstr;
4201.191Sitohy	if (isspace(c)) continue;	 /* already know it is ascii */
4211.191Sitohy	if (isupper(c))
4221.140Simp	    c = tolower(c);
4231.121Saymeric	if (savec) {
4241.193Suwe#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
4251.140Simp	    *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
4261.191Sitohy#undef atoh
4271.3Schristos	    savec = 0;		/* ready for next character */
4281.1Schristos	    us++;
4291.177Sbouyer	    i--;
4301.140Simp	} else {
4311.197Smycroft	    savec = c;
4321.140Simp	}
4331.182Schristos    }
4341.140Simp    *ptrp = retval;
4351.140Simp    return (int) len;
4361.74Senami}
4371.143Smjl
4381.188Shamajimastatic int dispatch_command (
4391.170Sitojun    const char *inputfilename,
4401.74Senami    int lineno,
4411.74Senami    int argc,
4421.124Sichiro    char **argv,
4431.130Sichiro    const CommandTable *tab,
4441.194Sitohy    int *statusp)
4451.86Sitojun{
4461.118Sichiro    const CommandTable *ct;
4471.142Smjl    const char *cmd;
4481.181Sperry    size_t n;
4491.190Snonaka					/* scan table for command */
4501.142Smjl    cmd = argv[0];
4511.140Simp    n = strlen (cmd);
4521.140Simp    for (ct = tab; ct->name; ct++) {
4531.140Simp					/* look for unique prefix */
4541.140Simp	if (n >= ct->minlen && n <= ct->maxlen &&
4551.171Sjonathan	    strncmp (cmd, ct->name, n) == 0) {
4561.178Sjdc	    *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
4571.174Smjl	    return 1;
4581.174Smjl	}
4591.70Smycroft    }
4601.140Simp
4611.140Simp    *statusp = 1;
4621.70Smycroft    return 0;
4631.140Simp}
4641.62Sdanw
4651.64Saugustss
4661.193Suwestatic AuthList *iceauth_head = NULL;	/* list of auth entries */
4671.193Suwestatic Bool iceauth_existed = False;	/* if was present at initialize */
4681.193Suwestatic Bool iceauth_modified = False;	/* if added, removed, or merged */
4691.193Suwestatic Bool iceauth_allowed = True;	/* if allowed to write auth file */
4701.140Simpstatic char *iceauth_filename = NULL;
4711.196Smycroftstatic volatile Bool dieing = False;
4721.76Senami
4731.106Sjhawk/* poor man's puts(), for under signal handlers */
4741.140Simp#define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
4751.140Simp
4761.162Sis/* ARGSUSED */
4771.140Simpstatic void die (_X_UNUSED int sig)
4781.191Sitohy{
4791.99Smsaitoh    dieing = True;
4801.191Sitohy    _exit (auth_finalize ());
4811.109Sichiro    /* NOTREACHED */
4821.140Simp}
4831.118Sichiro
4841.118Sichirostatic void catchsig (int sig)
4851.140Simp{
4861.140Simp#ifdef SYSV
4871.140Simp    if (sig > 0) signal (sig, die);	/* re-establish signal handler */
4881.140Simp#endif
4891.140Simp    /*
4901.140Simp     * fileno() might not be reentrant, avoid it if possible, and use
4911.140Simp     * stderr instead of stdout
4921.168Stshiozak     */
4931.191Sitohy#ifdef STDERR_FILENO
4941.191Sitohy    if (verbose && iceauth_modified) WRITES(STDERR_FILENO, "\r\n");
4951.191Sitohy#else
4961.191Sitohy    if (verbose && iceauth_modified) WRITES(fileno(stderr), "\r\n");
4971.191Sitohy#endif
4981.191Sitohy    die (sig);
4991.191Sitohy    /* NOTREACHED */
5001.191Sitohy}
5011.191Sitohy
5021.191Sitohystatic void register_signals (void)
5031.140Simp{
5041.140Simp    signal (SIGINT, catchsig);
5051.140Simp    signal (SIGTERM, catchsig);
5061.151Schristos#ifdef SIGHUP
5071.140Simp    signal (SIGHUP, catchsig);
5081.179Skanaoka#endif
5091.140Simp    return;
5101.140Simp}
5111.139Saugustss
5121.140Simp
5131.140Simp/*
5141.139Saugustss * public procedures for parsing lines of input
5151.140Simp */
5161.140Simp
5171.193Suweint auth_initialize ( char *authfilename )
5181.140Simp{
5191.193Suwe    int n;
5201.140Simp    AuthList *head, *tail;
5211.140Simp    FILE *authfp;
5221.147Simp    Bool exists;
523
524    register_signals ();
525
526    bzero ((char *) hexvalues, sizeof hexvalues);
527    hexvalues['0'] = 0;
528    hexvalues['1'] = 1;
529    hexvalues['2'] = 2;
530    hexvalues['3'] = 3;
531    hexvalues['4'] = 4;
532    hexvalues['5'] = 5;
533    hexvalues['6'] = 6;
534    hexvalues['7'] = 7;
535    hexvalues['8'] = 8;
536    hexvalues['9'] = 9;
537    hexvalues['a'] = hexvalues['A'] = 0xa;
538    hexvalues['b'] = hexvalues['B'] = 0xb;
539    hexvalues['c'] = hexvalues['C'] = 0xc;
540    hexvalues['d'] = hexvalues['D'] = 0xd;
541    hexvalues['e'] = hexvalues['E'] = 0xe;
542    hexvalues['f'] = hexvalues['F'] = 0xf;
543
544    if (break_locks && verbose) {
545	printf ("Attempting to break locks on authority file %s\n",
546		authfilename);
547    }
548
549    iceauth_filename = strdup(authfilename);
550
551    if (ignore_locks) {
552	if (break_locks) IceUnlockAuthFile (authfilename);
553    } else {
554	n = IceLockAuthFile (authfilename, ICEAUTH_DEFAULT_RETRIES,
555			 ICEAUTH_DEFAULT_TIMEOUT,
556			 (break_locks ? 0L : ICEAUTH_DEFAULT_DEADTIME));
557	if (n != IceAuthLockSuccess) {
558	    const char *reason = "unknown error";
559	    switch (n) {
560	      case IceAuthLockError:
561		reason = "error";
562		break;
563	      case IceAuthLockTimeout:
564		reason = "timeout";
565		break;
566	    }
567	    fprintf (stderr, "%s:  %s in locking authority file %s\n",
568		     ProgramName, reason, authfilename);
569	    return -1;
570	}
571    }
572
573    /* these checks can only be done reliably after the file is locked */
574    exists = (access (authfilename, F_OK) == 0);
575    if (exists && access (authfilename, W_OK) != 0) {
576	fprintf (stderr,
577	 "%s:  %s not writable, changes will be ignored\n",
578		 ProgramName, authfilename);
579	iceauth_allowed = False;
580    }
581
582    original_umask = umask (0077);	/* disallow non-owner access */
583
584    authfp = fopen (authfilename, "rb");
585    if (!authfp) {
586	int olderrno = errno;
587
588					/* if file there then error */
589	if (access (authfilename, F_OK) == 0) {	 /* then file does exist! */
590	    errno = olderrno;
591	    return -1;
592	}				/* else ignore it */
593	fprintf (stderr,
594		 "%s:  creating new authority file %s\n",
595		 ProgramName, authfilename);
596    } else {
597	iceauth_existed = True;
598	n = read_auth_entries (authfp, &head, &tail);
599	(void) fclose (authfp);
600	if (n < 0) {
601	    fprintf (stderr,
602		     "%s:  unable to read auth entries from file \"%s\"\n",
603		     ProgramName, authfilename);
604	    return -1;
605	}
606	iceauth_head = head;
607    }
608
609    iceauth_modified = False;
610
611    if (verbose) {
612	printf ("%s authority file %s\n",
613		ignore_locks ? "Ignoring locks on" : "Using", authfilename);
614    }
615    return 0;
616}
617
618static int write_auth_file (char *tmp_nam, size_t tmp_nam_len)
619{
620    FILE *fp;
621    AuthList *list;
622
623    if ((strlen(iceauth_filename) + 3) > tmp_nam_len) {
624	strncpy(tmp_nam, "filename too long", tmp_nam_len);
625	tmp_nam[tmp_nam_len - 1] = '\0';
626	return -1;
627    }
628
629    strcpy (tmp_nam, iceauth_filename);
630    strcat (tmp_nam, "-n");		/* for new */
631    (void) unlink (tmp_nam);
632    fp = fopen (tmp_nam, "wb");		/* umask is still set to 0077 */
633    if (!fp) {
634	fprintf (stderr, "%s:  unable to open tmp file \"%s\"\n",
635		 ProgramName, tmp_nam);
636	return -1;
637    }
638
639    for (list = iceauth_head; list; list = list->next)
640	IceWriteAuthFileEntry (fp, list->auth);
641
642    (void) fclose (fp);
643    return 0;
644}
645
646int auth_finalize (void)
647{
648    char temp_name[1024];			/* large filename size */
649
650    if (iceauth_modified) {
651	if (dieing) {
652	    if (verbose) {
653		/*
654		 * called from a signal handler -- printf is *not* reentrant; also
655		 * fileno() might not be reentrant, avoid it if possible, and use
656		 * stderr instead of stdout
657		 */
658#ifdef STDERR_FILENO
659		WRITES(STDERR_FILENO, "\nAborting changes to authority file ");
660		WRITES(STDERR_FILENO, iceauth_filename);
661		WRITES(STDERR_FILENO, "\n");
662#else
663		WRITES(fileno(stderr), "\nAborting changes to authority file ");
664		WRITES(fileno(stderr), iceauth_filename);
665		WRITES(fileno(stderr), "\n");
666#endif
667	    }
668	} else if (!iceauth_allowed) {
669	    fprintf (stderr,
670		     "%s:  %s not writable, changes ignored\n",
671		     ProgramName, iceauth_filename);
672	} else {
673	    if (verbose) {
674		printf ("%s authority file %s\n",
675			ignore_locks ? "Ignoring locks and writing" :
676			"Writing", iceauth_filename);
677	    }
678	    temp_name[0] = '\0';
679	    if (write_auth_file (temp_name, sizeof(temp_name)) == -1) {
680		fprintf (stderr,
681			 "%s:  unable to write authority file %s\n",
682			 ProgramName, temp_name);
683	    } else {
684		(void) unlink (iceauth_filename);
685#if defined(WIN32) || defined(__UNIXOS2__)
686		if (rename(temp_name, iceauth_filename) == -1)
687#else
688		/* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */
689		if (link (temp_name, iceauth_filename) == -1 && rename(temp_name, iceauth_filename) == -1)
690#endif
691		{
692		    fprintf (stderr,
693		     "%s:  unable to link authority file %s, use %s\n",
694			     ProgramName, iceauth_filename, temp_name);
695		} else {
696		    (void) unlink (temp_name);
697		}
698	    }
699	}
700    }
701
702    if (!ignore_locks && (iceauth_filename != NULL)) {
703	IceUnlockAuthFile (iceauth_filename);
704    }
705    (void) umask (original_umask);
706    return 0;
707}
708
709int process_command (
710    const char *inputfilename,
711    int lineno,
712    int argc,
713    char **argv)
714{
715    int status;
716
717    if (argc < 1 || !argv || !argv[0]) return 1;
718
719    if (dispatch_command (inputfilename, lineno, argc, argv,
720			  command_table, &status))
721      return status;
722
723    prefix (inputfilename, lineno);
724    fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
725    return 1;
726}
727
728
729/*
730 * utility routines
731 */
732
733static void fprintfhex (
734    register FILE *fp,
735    unsigned int len,
736    const char *cp)
737{
738    const unsigned char *ucp = (const unsigned char *) cp;
739
740    for (; len > 0; len--, ucp++) {
741	register const char *s = hex_table[*ucp];
742	putc (s[0], fp);
743	putc (s[1], fp);
744    }
745    return;
746}
747
748/* ARGSUSED */
749static int dump_entry (
750    const char *inputfilename _X_UNUSED,
751    int lineno _X_UNUSED,
752    IceAuthFileEntry *auth,
753    void *data)
754{
755    struct _list_data *ld = (struct _list_data *) data;
756    FILE *fp = ld->fp;
757
758    fprintf (fp, "%s", auth->protocol_name);
759    putc (' ', fp);
760    if (auth->protocol_data_length > 0)
761	fprintfhex (fp, auth->protocol_data_length, auth->protocol_data);
762    else
763	fprintf (fp, "\"\"");
764    putc (' ', fp);
765    fprintf (fp, "%s", auth->network_id);
766    putc (' ', fp);
767    fprintf (fp, "%s", auth->auth_name);
768    putc (' ', fp);
769
770    if (auth->auth_data_length == 0)
771	fprintf (fp, "\"\"");
772    else if (!strcmp(auth->auth_name, SECURERPC) ||
773	!strcmp(auth->auth_name, K5AUTH))
774	fwrite (auth->auth_data, sizeof (char), auth->auth_data_length, fp);
775    else
776	fprintfhex (fp, auth->auth_data_length, auth->auth_data);
777    putc ('\n', fp);
778
779    return 0;
780}
781
782static int extract_entry (
783    const char *inputfilename,
784    int lineno,
785    IceAuthFileEntry *auth,
786    void *data)
787{
788    struct _extract_data *ed = (struct _extract_data *) data;
789
790    if (!ed->fp) {
791	ed->fp = open_file (&ed->filename, "wb",
792			    &ed->used_stdout,
793			    inputfilename, lineno, ed->cmd);
794	if (!ed->fp) {
795	    prefix (inputfilename, lineno);
796	    fprintf (stderr,
797		     "unable to open extraction file \"%s\"\n",
798		     ed->filename);
799	    return -1;
800	}
801    }
802    IceWriteAuthFileEntry (ed->fp, auth);
803    ed->nwritten++;
804
805    return 0;
806}
807
808
809static int match_auth (
810    register IceAuthFileEntry *a,
811    register IceAuthFileEntry *b,
812    int *authDataSame)
813{
814    int match = strcmp (a->protocol_name, b->protocol_name) == 0 &&
815	    strcmp (a->network_id, b->network_id) == 0 &&
816            strcmp (a->auth_name, b->auth_name) == 0;
817
818    if (match)
819    {
820	*authDataSame = (a->auth_data_length == b->auth_data_length &&
821	    binaryEqual (a->auth_data, b->auth_data, a->auth_data_length));
822    }
823    else
824	*authDataSame = 0;
825
826    return (match);
827}
828
829
830static int merge_entries (
831    AuthList **firstp, AuthList *second,
832    int *nnewp, int *nreplp, int *ndupp)
833{
834    AuthList *a, *b, *first, *tail;
835    int n = 0, nnew = 0, nrepl = 0, ndup = 0;
836
837    if (!second) return 0;
838
839    if (!*firstp) {			/* if nothing to merge into */
840	*firstp = second;
841	for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
842	*nnewp = n;
843	*nreplp = 0;
844	*ndupp = 0;
845	return n;
846    }
847
848    first = *firstp;
849    /*
850     * find end of first list and stick second list on it
851     */
852    for (tail = first; tail->next; tail = tail->next) ;
853    tail->next = second;
854
855    /*
856     * run down list freeing duplicate entries; if an entry is okay, then
857     * bump the tail up to include it, otherwise, cut the entry out of
858     * the chain.
859     */
860    for (b = second; b; ) {
861	AuthList *next = b->next;	/* in case we free it */
862	int duplicate;
863
864	duplicate = 0;
865	a = first;
866	for (;;) {
867	    int authDataSame;
868	    if (match_auth (a->auth, b->auth, &authDataSame)) {
869		if (authDataSame)
870		{
871		    /* found a complete duplicate, ignore */
872		    duplicate = 1;
873		    break;
874		}
875		else
876		{
877		    /* found a duplicate, but auth data differs */
878
879		    AuthList tmp;		/* swap it in for old one */
880		    tmp = *a;
881		    *a = *b;
882		    *b = tmp;
883		    a->next = b->next;
884		    IceFreeAuthFileEntry (b->auth);
885		    free ((char *) b);
886		    b = NULL;
887		    tail->next = next;
888		    nrepl++;
889		    nnew--;
890		    break;
891		}
892	    }
893	    if (a == tail) break;	/* if have looked at left side */
894	    a = a->next;
895	}
896	if (!duplicate && b) {		/* if we didn't remove it */
897	    tail = b;			/* bump end of first list */
898	}
899	b = next;
900
901	if (duplicate)
902	    ndup++;
903	else
904	{
905	    n++;
906	    nnew++;
907	}
908    }
909
910    *nnewp = nnew;
911    *nreplp = nrepl;
912    *ndupp = ndup;
913    return n;
914
915}
916
917
918static int search_and_do (
919    const char *inputfilename,
920    int lineno,
921    int start,
922    int argc,
923    char *argv[],
924    DoFunc do_func,
925    void *data)
926{
927    int i;
928    int status = 0;
929    int errors = 0;
930    AuthList *l, *next;
931    char *protoname, *protodata, *netid, *authname;
932
933    for (l = iceauth_head; l; l = next)
934    {
935	next = l->next;
936
937	protoname = protodata = netid = authname = NULL;
938
939	for (i = start; i < argc; i++)
940	{
941	    if (!strncmp ("protoname=", argv[i], 10))
942		protoname = argv[i] + 10;
943	    else if (!strncmp ("protodata=", argv[i], 10))
944		protodata = argv[i] + 10;
945	    else if (!strncmp ("netid=", argv[i], 6))
946		netid = argv[i] + 6;
947	    else if (!strncmp ("authname=", argv[i], 9))
948		authname = argv[i] + 9;
949	}
950
951	status = 0;
952
953	if (protoname || protodata || netid || authname)
954	{
955	    if (protoname && strcmp (protoname, l->auth->protocol_name))
956		continue;
957
958	    if (protodata && !binaryEqual (protodata,
959		l->auth->protocol_data, l->auth->protocol_data_length))
960		continue;
961
962	    if (netid && strcmp (netid, l->auth->network_id))
963		continue;
964
965	    if (authname && strcmp (authname, l->auth->auth_name))
966		continue;
967
968	    status = (*do_func) (inputfilename, lineno, l->auth, data);
969
970	    if (status < 0)
971		break;
972	}
973    }
974
975    if (status < 0)
976	errors -= status;		/* since status is negative */
977
978    return (errors);
979}
980
981
982/* ARGSUSED */
983static int remove_entry (
984    const char *inputfilename _X_UNUSED,
985    int lineno _X_UNUSED,
986    IceAuthFileEntry *auth,
987    void *data)
988{
989    int *nremovedp = (int *) data;
990    AuthList **listp = &iceauth_head;
991    AuthList *list;
992
993    /*
994     * unlink the auth we were asked to
995     */
996    while ((list = *listp)->auth != auth)
997	listp = &list->next;
998    *listp = list->next;
999    IceFreeAuthFileEntry (list->auth);                    /* free the auth */
1000    free (list);				    /* free the link */
1001    iceauth_modified = True;
1002    (*nremovedp)++;
1003    return 1;
1004}
1005
1006/*
1007 * action routines
1008 */
1009
1010/*
1011 * help
1012 */
1013int print_help (
1014    FILE *fp,
1015    const char *cmd)
1016{
1017    const CommandTable *ct;
1018    int n = 0;
1019
1020    fprintf (fp, "\n");
1021    if (!cmd) {				/* if no cmd, print all help */
1022	for (ct = command_table; ct->name; ct++) {
1023	    fprintf (fp, "%s\n\n", ct->helptext);
1024	    n++;
1025	}
1026    } else {
1027	size_t len = strlen (cmd);
1028	for (ct = command_table; ct->name; ct++) {
1029	    if (strncmp (cmd, ct->name, len) == 0) {
1030		fprintf (fp, "%s\n\n", ct->helptext);
1031		n++;
1032	    }
1033	}
1034    }
1035
1036    return n;
1037}
1038
1039static int do_help (
1040    const char *inputfilename,
1041    int lineno,
1042    int argc,
1043    char **argv)
1044{
1045    char *cmd = (argc > 1 ? argv[1] : NULL);
1046    int n;
1047
1048    n = print_help (stdout, cmd);
1049
1050    if (n < 0 || (n == 0 && !cmd)) {
1051	prefix (inputfilename, lineno);
1052	fprintf (stderr, "internal error with help");
1053	if (cmd) {
1054	    fprintf (stderr, " on command \"%s\"", cmd);
1055	}
1056	fprintf (stderr, "\n");
1057	return 1;
1058    }
1059
1060    if (n == 0) {
1061	prefix (inputfilename, lineno);
1062	/* already know that cmd is set in this case */
1063	fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd);
1064    }
1065
1066    return 0;
1067}
1068
1069/*
1070 * questionmark
1071 */
1072/* ARGSUSED */
1073static int do_questionmark (
1074    const char *inputfilename _X_UNUSED,
1075    int lineno _X_UNUSED,
1076    int argc _X_UNUSED,
1077    char **argv _X_UNUSED)
1078{
1079    const CommandTable *ct;
1080    unsigned int i;
1081#define WIDEST_COLUMN 72
1082    unsigned int col = WIDEST_COLUMN;
1083
1084    printf ("Commands:\n");
1085    for (ct = command_table; ct->name; ct++) {
1086	if ((col + ct->maxlen) > WIDEST_COLUMN) {
1087	    if (ct != command_table) {
1088		putc ('\n', stdout);
1089	    }
1090	    fputs ("        ", stdout);
1091	    col = 8;			/* length of string above */
1092	}
1093	fputs (ct->name, stdout);
1094	col += ct->maxlen;
1095	for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
1096	    putc (' ', stdout);
1097	    col++;
1098	}
1099    }
1100    if (col != 0) {
1101	putc ('\n', stdout);
1102    }
1103
1104    /* allow bad lines since this is help */
1105    return 0;
1106}
1107
1108/*
1109 * list [displayname ...]
1110 */
1111static int do_list (
1112    const char *inputfilename,
1113    int lineno,
1114    int argc,
1115    char **argv)
1116{
1117    struct _list_data ld;
1118
1119    ld.fp = stdout;
1120
1121    if (argc == 1) {
1122	register AuthList *l;
1123
1124	if (iceauth_head) {
1125	    for (l = iceauth_head; l; l = l->next) {
1126		dump_entry (inputfilename, lineno, l->auth, &ld);
1127	    }
1128	}
1129	return 0;
1130    }
1131    else
1132    {
1133	return (search_and_do (inputfilename, lineno, 1, argc, argv,
1134	    dump_entry, &ld));
1135    }
1136}
1137
1138/*
1139 * merge filename [filename ...]
1140 */
1141static int do_merge (
1142    const char *inputfilename,
1143    int lineno,
1144    int argc,
1145    char **argv)
1146{
1147    int i;
1148    int errors = 0;
1149    AuthList *head, *tail, *listhead, *listtail;
1150    int nentries, nnew, nrepl, ndup;
1151
1152    if (argc < 2) {
1153	prefix (inputfilename, lineno);
1154	badcommandline (argv[0]);
1155	return 1;
1156    }
1157
1158    listhead = listtail = NULL;
1159
1160    for (i = 1; i < argc; i++) {
1161	const char *filename = argv[i];
1162	FILE *fp;
1163	Bool used_stdin = False;
1164
1165	fp = open_file (&filename, "rb",
1166			&used_stdin, inputfilename, lineno,
1167			argv[0]);
1168	if (!fp) {
1169	    errors++;
1170	    continue;
1171	}
1172
1173	head = tail = NULL;
1174	nentries = read_auth_entries (fp, &head, &tail);
1175	if (nentries == 0) {
1176	    prefix (inputfilename, lineno);
1177	    fprintf (stderr, "unable to read any entries from file \"%s\"\n",
1178		     filename);
1179	    errors++;
1180	} else {			/* link it in */
1181	    add_to_list (listhead, listtail, head);
1182 	}
1183
1184	if (!used_stdin) (void) fclose (fp);
1185    }
1186
1187    /*
1188     * if we have new entries, merge them in (freeing any duplicates)
1189     */
1190    if (listhead) {
1191	nentries = merge_entries (&iceauth_head, listhead,
1192	    &nnew, &nrepl, &ndup);
1193	if (verbose)
1194	  printf ("%d entries read in:  %d new, %d replacement%s\n",
1195	  	  nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
1196	if (nentries > 0) iceauth_modified = True;
1197    }
1198
1199    return 0;
1200}
1201
1202/*
1203 * extract filename displayname [displayname ...]
1204 */
1205static int do_extract (
1206    const char *inputfilename,
1207    int lineno,
1208    int argc,
1209    char **argv)
1210{
1211    int errors;
1212    struct _extract_data ed;
1213
1214    if (argc < 3) {
1215	prefix (inputfilename, lineno);
1216	badcommandline (argv[0]);
1217	return 1;
1218    }
1219
1220    ed.fp = NULL;
1221    ed.filename = argv[1];
1222    ed.nwritten = 0;
1223    ed.cmd = argv[0];
1224
1225    errors = search_and_do (inputfilename, lineno, 2, argc, argv,
1226	extract_entry, &ed);
1227
1228    if (!ed.fp) {
1229	fprintf (stderr,
1230		 "No matches found, authority file \"%s\" not written\n",
1231		 ed.filename);
1232    } else {
1233	if (verbose) {
1234	    printf ("%d entries written to \"%s\"\n",
1235		    ed.nwritten, ed.filename);
1236	}
1237	if (!ed.used_stdout) {
1238	    (void) fclose (ed.fp);
1239	}
1240    }
1241
1242    return errors;
1243}
1244
1245
1246/*
1247 * add protoname protodata netid authname authdata
1248 */
1249static int do_add (
1250    const char *inputfilename,
1251    int lineno,
1252    int argc,
1253    char **argv)
1254{
1255    int n, nnew, nrepl, ndup;
1256    char *protoname;
1257    char *protodata_hex;
1258    char *protodata = NULL; /* not required */
1259    char *netid;
1260    char *authname;
1261    char *authdata_hex;
1262    char *authdata = NULL;
1263    int protodata_len, authdata_len;
1264    IceAuthFileEntry *auth = NULL;
1265    AuthList *list;
1266    int status = 0;
1267
1268    if (argc != 6 || !argv[1] || !argv[2] ||
1269	!argv[3] || !argv[4] || !argv[5])
1270    {
1271	prefix (inputfilename, lineno);
1272	badcommandline (argv[0]);
1273	return 1;
1274    }
1275
1276    protoname = argv[1];
1277    protodata_hex = argv[2];
1278    netid = argv[3];
1279    authname = argv[4];
1280    authdata_hex = argv[5];
1281
1282    protodata_len = strlen (protodata_hex);
1283    if (protodata_len > 0)
1284    {
1285	if (protodata_hex[0] == '"' && protodata_hex[protodata_len - 1] == '"')
1286	{
1287	    protodata = malloc (protodata_len - 1);
1288	    if (protodata)
1289	    {
1290		strncpy (protodata, protodata_hex + 1, protodata_len - 2);
1291		protodata_len -= 2;
1292	    }
1293	    else
1294		goto add_bad_malloc;
1295	}
1296	else
1297	{
1298	    protodata_len = cvthexkey (protodata_hex, &protodata);
1299	    if (protodata_len < 0)
1300	    {
1301		prefix (inputfilename, lineno);
1302		fprintf (stderr,
1303	       "protodata_hex contains odd number of or non-hex characters\n");
1304		return (1);
1305	    }
1306	}
1307    }
1308
1309    authdata_len = strlen (authdata_hex);
1310    if (authdata_hex[0] == '"' && authdata_hex[authdata_len - 1] == '"')
1311    {
1312	authdata = malloc (authdata_len - 1);
1313	if (authdata)
1314	{
1315	    strncpy (authdata, authdata_hex + 1, authdata_len - 2);
1316	    authdata_len -= 2;
1317	}
1318	else
1319	    goto add_bad_malloc;
1320    }
1321    else if (!strcmp (protoname, SECURERPC) || !strcmp (protoname, K5AUTH))
1322    {
1323	authdata = malloc (authdata_len + 1);
1324	if (authdata)
1325	    strcpy (authdata, authdata_hex);
1326	else
1327	    goto add_bad_malloc;
1328    }
1329    else
1330    {
1331	authdata_len = cvthexkey (authdata_hex, &authdata);
1332	if (authdata_len < 0)
1333	{
1334	    prefix (inputfilename, lineno);
1335	    fprintf (stderr,
1336	       "authdata_hex contains odd number of or non-hex characters\n");
1337	    free (protodata);
1338	    return (1);
1339	}
1340    }
1341
1342    auth = (IceAuthFileEntry *) malloc (sizeof (IceAuthFileEntry));
1343
1344    if (!auth)
1345	goto add_bad_malloc;
1346
1347    auth->protocol_name = copystring (protoname);
1348    auth->protocol_data_length = protodata_len;
1349    auth->protocol_data = protodata;
1350    auth->network_id = copystring (netid);
1351    auth->auth_name = copystring (authname);
1352    auth->auth_data_length = authdata_len;
1353    auth->auth_data = authdata;
1354
1355    if (!auth->protocol_name ||
1356	(!auth->protocol_data && auth->protocol_data_length > 0) ||
1357        !auth->network_id || !auth->auth_name ||
1358	(!auth->auth_data && auth->auth_data_length > 0))
1359    {
1360	goto add_bad_malloc;
1361    }
1362
1363    list = (AuthList *) malloc (sizeof (AuthList));
1364
1365    if (!list)
1366	goto add_bad_malloc;
1367
1368    list->next = NULL;
1369    list->auth = auth;
1370
1371    /*
1372     * merge it in; note that merge will deal with allocation
1373     */
1374
1375    n = merge_entries (&iceauth_head, list, &nnew, &nrepl, &ndup);
1376
1377    if (n > 0)
1378	iceauth_modified = True;
1379    else
1380    {
1381	prefix (inputfilename, lineno);
1382	if (ndup > 0)
1383	{
1384	    status = 0;
1385	    fprintf (stderr, "no records added - all duplicate\n");
1386	}
1387	else
1388	{
1389	    status = 1;
1390	    fprintf (stderr, "unable to merge in added record\n");
1391	}
1392	goto cant_add;
1393    }
1394
1395    return 0;
1396
1397
1398add_bad_malloc:
1399
1400    status = 1;
1401    prefix (inputfilename, lineno);
1402    fprintf (stderr, "unable to allocate memory to add an entry\n");
1403
1404cant_add:
1405
1406    if (protodata)
1407	free (protodata);
1408    if (authdata)
1409	free (authdata);
1410    if (auth)
1411    {
1412	if (auth->protocol_name)
1413	    free (auth->protocol_name);
1414	/* auth->protocol_data already freed,
1415	   since it's the same as protodata */
1416	if (auth->network_id)
1417	    free (auth->network_id);
1418	if (auth->auth_name)
1419	    free (auth->auth_name);
1420	/* auth->auth_data already freed,
1421	   since it's the same as authdata */
1422	free ((char *) auth);
1423    }
1424
1425    return status;
1426}
1427
1428/*
1429 * remove displayname
1430 */
1431static int do_remove (
1432    const char *inputfilename,
1433    int lineno,
1434    int argc,
1435    char **argv)
1436{
1437    int nremoved = 0;
1438    int errors;
1439
1440    if (argc < 2) {
1441	prefix (inputfilename, lineno);
1442	badcommandline (argv[0]);
1443	return 1;
1444    }
1445
1446    errors = search_and_do (inputfilename, lineno, 1, argc, argv,
1447	remove_entry, &nremoved);
1448    if (verbose) printf ("%d entries removed\n", nremoved);
1449    return errors;
1450}
1451
1452/*
1453 * info
1454 */
1455static int do_info (
1456    const char *inputfilename,
1457    int lineno,
1458    int argc,
1459    char **argv)
1460{
1461    int n;
1462    AuthList *l;
1463
1464    if (argc != 1) {
1465	prefix (inputfilename, lineno);
1466	badcommandline (argv[0]);
1467	return 1;
1468    }
1469
1470    for (l = iceauth_head, n = 0; l; l = l->next, n++) ;
1471
1472    printf ("Authority file:       %s\n",
1473	    iceauth_filename ? iceauth_filename : "(none)");
1474    printf ("File new:             %s\n", iceauth_existed ? No : Yes);
1475    printf ("File locked:          %s\n", ignore_locks ? No : Yes);
1476    printf ("Number of entries:    %d\n", n);
1477    printf ("Changes honored:      %s\n", iceauth_allowed ? Yes : No);
1478    printf ("Changes made:         %s\n", iceauth_modified ? Yes : No);
1479    printf ("Current input:        %s:%d\n", inputfilename, lineno);
1480    return 0;
1481}
1482
1483
1484/*
1485 * exit
1486 */
1487static Bool alldone = False;
1488
1489/* ARGSUSED */
1490static int do_exit (
1491    const char *inputfilename _X_UNUSED,
1492    int lineno _X_UNUSED,
1493    int argc _X_UNUSED,
1494    char **argv _X_UNUSED)
1495{
1496    /* allow bogus stuff */
1497    alldone = True;
1498    return 0;
1499}
1500
1501/*
1502 * quit
1503 */
1504/* ARGSUSED */
1505static int do_quit (
1506    const char *inputfilename _X_UNUSED,
1507    int lineno _X_UNUSED,
1508    int argc _X_UNUSED,
1509    char **argv _X_UNUSED)
1510{
1511    /* allow bogus stuff */
1512    die (0);
1513    /* NOTREACHED */
1514    return -1;				/* for picky compilers */
1515}
1516
1517
1518/*
1519 * source filename
1520 */
1521static int do_source (
1522    const char *inputfilename,
1523    int lineno,
1524    int argc,
1525    char **argv)
1526{
1527    const char *script;
1528    char buf[BUFSIZ];
1529    FILE *fp;
1530    Bool used_stdin = False;
1531    size_t len;
1532    int errors = 0, status;
1533    int sublineno = 0;
1534    char **subargv;
1535    int subargc;
1536    Bool prompt = False;		/* only true if reading from tty */
1537
1538    if (argc != 2 || !argv[1]) {
1539	prefix (inputfilename, lineno);
1540	badcommandline (argv[0]);
1541	return 1;
1542    }
1543
1544    script = argv[1];
1545
1546    fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
1547    if (!fp) {
1548	return 1;
1549    }
1550
1551    if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
1552
1553    while (!alldone) {
1554	buf[0] = '\0';
1555	if (prompt) {
1556	    printf ("iceauth> ");
1557	    fflush (stdout);
1558	}
1559	if (fgets (buf, sizeof buf, fp) == NULL) break;
1560	sublineno++;
1561	len = strlen (buf);
1562	if (len == 0 || buf[0] == '#') continue;
1563	if (buf[len-1] != '\n') {
1564	    prefix (script, sublineno);
1565	    fprintf (stderr, "line too long\n");
1566	    errors++;
1567	    break;
1568	}
1569	buf[--len] = '\0';		/* remove new line */
1570	subargv = split_into_words (buf, &subargc);
1571	if (subargv) {
1572	    status = process_command (script, sublineno, subargc, subargv);
1573	    free ((char *) subargv);
1574	    errors += status;
1575	} else {
1576	    prefix (script, sublineno);
1577	    fprintf (stderr, "unable to break line into words\n");
1578	    errors++;
1579	}
1580    }
1581
1582    if (!used_stdin) {
1583	(void) fclose (fp);
1584    }
1585    return errors;
1586}
1587