1 /*
2  *
3 Copyright 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24  * *
25  * Original Author of "xauth" : Jim Fulton, MIT X Consortium
26  * Modified into "iceauth"    : Ralph Mor, X Consortium
27  */
28 
29 #include "iceauth.h"
30 #include <ctype.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <signal.h>
35 
36 #define SECURERPC "SUN-DES-1"
37 #define K5AUTH "KERBEROS-V5-1"
38 
39 #define ICEAUTH_DEFAULT_RETRIES 10	/* number of competitors we expect */
40 #define ICEAUTH_DEFAULT_TIMEOUT 2	/* in seconds, be quick */
41 #define ICEAUTH_DEFAULT_DEADTIME 600L	/* 10 minutes in seconds */
42 
43 typedef struct _AuthList {		/* linked list of entries */
44     struct _AuthList *next;
45     IceAuthFileEntry *auth;
46 } AuthList;
47 
48 #define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);}
49 
50 typedef int (*ProcessFunc)(const char *, int, int, const char **);
51 typedef int (*DoFunc)(const char *, int, IceAuthFileEntry *, void *);
52 
53 typedef struct _CommandTable {		/* commands that are understood */
54     const char *name;			/* full name */
55     unsigned int minlen;		/* unique prefix */
56     unsigned int maxlen;		/* strlen(name) */
57     ProcessFunc processfunc;		/* handler */
58     const char *helptext;		/* what to print for help */
59 } CommandTable;
60 
61 struct _extract_data {			/* for iterating */
62     FILE *fp;				/* input source */
63     const char *filename;		/* name of input */
64     Bool used_stdout;			/* whether or not need to close */
65     int nwritten;			/* number of entries written */
66     const char *cmd;			/* for error messages */
67 };
68 
69 struct _list_data {			/* for iterating */
70     FILE *fp;				/* output file */
71 };
72 
73 
74 /*
75  * private data
76  */
77 static const char *stdin_filename = "(stdin)";  /* for messages */
78 static const char *stdout_filename = "(stdout)";  /* for messages */
79 static const char *Yes = "yes";		/* for messages */
80 static const char *No = "no";			/* for messages */
81 
82 static int binaryEqual ( const char *a, const char *b, unsigned len );
83 static void prefix ( const char *fn, int n );
84 static void badcommandline ( const char *cmd );
85 static char *skip_space ( char *s );
86 static char *skip_nonspace ( char *s );
87 static char **split_into_words ( char *src, int *argcp );
88 static FILE *open_file ( const char **filenamep, const char *mode, Bool *usedstdp, const char *srcfn, int srcln, const char *cmd );
89 static int read_auth_entries ( FILE *fp, AuthList **headp, AuthList **tailp );
90 static int cvthexkey ( const char *hexstr, char **ptrp );
91 static int dispatch_command ( const char *inputfilename, int lineno, int argc, const char **argv, const CommandTable *tab, int *statusp );
92 static void die ( int sig ) _X_NORETURN;
93 static void catchsig ( int sig ) _X_NORETURN;
94 static void register_signals ( void );
95 static int write_auth_file ( char *tmp_nam, size_t tmp_nam_len );
96 static void fprintfhex ( FILE *fp, unsigned int len, const char *cp );
97 static int dump_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
98 static int extract_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
99 static int match_auth ( IceAuthFileEntry *a, IceAuthFileEntry *b, int *authDataSame );
100 static int merge_entries ( AuthList **firstp, AuthList *second, int *nnewp, int *nreplp, int *ndupp );
101 static int search_and_do ( const char *inputfilename, int lineno, int start, int argc, const char *argv[], DoFunc do_func, void *data );
102 static int remove_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, void *data );
103 static int do_help ( const char *inputfilename, int lineno, int argc, const char **argv );
104 static int do_questionmark ( const char *inputfilename, int lineno, int argc, const char **argv );
105 static int do_list ( const char *inputfilename, int lineno, int argc, const char **argv );
106 static int do_merge ( const char *inputfilename, int lineno, int argc, const char **argv );
107 static int do_extract ( const char *inputfilename, int lineno, int argc, const char **argv );
108 static int do_add ( const char *inputfilename, int lineno, int argc, const char **argv );
109 static int do_remove ( const char *inputfilename, int lineno, int argc, const char **argv );
110 static int do_info ( const char *inputfilename, int lineno, int argc, const char **argv );
111 static int do_exit ( const char *inputfilename, int lineno, int argc, const char **argv );
112 static int do_quit ( const char *inputfilename, int lineno, int argc, const char **argv );
113 static int do_source ( const char *inputfilename, int lineno, int argc, const char **argv );
114 
115 static const CommandTable command_table[] = {	/* table of known commands */
116 { "add", 2, 3, do_add,
117 "\
118 add       add an entry\n\
119           add protoname protodata netid authname authdata"
120 },
121 
122 { "exit", 3, 4, do_exit,
123 "\
124 exit      save changes and exit program"
125 },
126 
127 { "extract", 3, 7, do_extract,
128 "\
129 extract   extract entries into file\n\
130           extract filename <protoname=$> <protodata=$> <netid=$> <authname=$>"
131 },
132 
133 { "help", 1, 4, do_help,
134 "\
135 help      print help\n\
136           help <topic>"
137 },
138 
139 { "info", 1, 4, do_info,
140 "\
141 info      print information about entries"
142 },
143 
144 { "list", 1, 4, do_list,
145 "\
146 list      list entries\n\
147           list <protoname=$> <protodata=$> <netid=$> <authname=$>"
148 },
149 
150 { "merge", 1, 5, do_merge,
151 "\
152 merge     merge entries from files\n\
153           merge filename1 <filename2> <filename3> ..."
154 },
155 
156 { "quit", 1, 4, do_quit,
157 "\
158 quit      abort changes and exit program" },
159 
160 { "remove", 1, 6, do_remove,
161 "\
162 remove    remove entries\n\
163           remove <protoname=$> <protodata=$> <netid=$> <authname=$>"
164 },
165 
166 { "source", 1, 6, do_source,
167 "\
168 source    read commands from file\n\
169           source filename"
170 },
171 
172 { "?", 1, 1, do_questionmark,
173 "\
174 ?         list available commands" },
175 
176 { NULL, 0, 0, NULL, NULL },
177 };
178 
179 #define COMMAND_NAMES_PADDED_WIDTH 10	/* wider than anything above */
180 
181 
182 static Bool okay_to_use_stdin = True;	/* set to false after using */
183 
184 static const char * const hex_table[] = {	/* for printing hex digits */
185     "00", "01", "02", "03", "04", "05", "06", "07",
186     "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
187     "10", "11", "12", "13", "14", "15", "16", "17",
188     "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
189     "20", "21", "22", "23", "24", "25", "26", "27",
190     "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
191     "30", "31", "32", "33", "34", "35", "36", "37",
192     "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
193     "40", "41", "42", "43", "44", "45", "46", "47",
194     "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
195     "50", "51", "52", "53", "54", "55", "56", "57",
196     "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
197     "60", "61", "62", "63", "64", "65", "66", "67",
198     "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
199     "70", "71", "72", "73", "74", "75", "76", "77",
200     "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
201     "80", "81", "82", "83", "84", "85", "86", "87",
202     "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
203     "90", "91", "92", "93", "94", "95", "96", "97",
204     "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
205     "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
206     "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
207     "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
208     "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
209     "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
210     "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
211     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
212     "d8", "d9", "da", "db", "dc", "dd", "de", "df",
213     "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
214     "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
215     "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
216     "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
217 };
218 
219 static unsigned int hexvalues[256];	/* for parsing hex input */
220 
221 static mode_t original_umask = 0;	/* for restoring */
222 
223 
224 /*
225  * private utility procedures
226  */
227 
228 #define copystring(s)	( s != NULL ? strdup(s) : NULL )
229 
230 static int
binaryEqual(register const char * a,register const char * b,register unsigned len)231 binaryEqual (
232     register const char	*a,
233     register const char	*b,
234     register unsigned	len)
235 
236 {
237     while (len--)
238 	if (*a++ != *b++)
239 	    return 0;
240     return 1;
241 }
242 
prefix(const char * fn,int n)243 static void prefix (const char *fn, int n)
244 {
245     fprintf (stderr, "%s: %s:%d:  ", ProgramName, fn, n);
246 }
247 
badcommandline(const char * cmd)248 static void badcommandline (const char *cmd)
249 {
250     fprintf (stderr, "bad \"%s\" command line\n", cmd);
251 }
252 
skip_space(register char * s)253 static char *skip_space (register char *s)
254 {
255     if (!s) return NULL;
256 
257     for ( ; *s && isascii(*s) && isspace(*s); s++)
258 	;
259     return s;
260 }
261 
262 
skip_nonspace(register char * s)263 static char *skip_nonspace (register char *s)
264 {
265     if (!s) return NULL;
266 
267     /* put quoting into loop if need be */
268     for ( ; *s && isascii(*s) && !isspace(*s); s++)
269 	;
270     return s;
271 }
272 
split_into_words(char * src,int * argcp)273 static char **split_into_words (  /* argvify string */
274     char *src,
275     int *argcp)
276 {
277     char *jword;
278     char savec;
279     char **argv;
280     int cur, total;
281 
282     *argcp = 0;
283 #define WORDSTOALLOC 4			/* most lines are short */
284     argv = (char **) malloc (WORDSTOALLOC * sizeof (char *));
285     if (!argv) return NULL;
286     cur = 0;
287     total = WORDSTOALLOC;
288 
289     /*
290      * split the line up into separate, nul-terminated tokens; the last
291      * "token" will point to the empty string so that it can be bashed into
292      * a null pointer.
293      */
294 
295     do {
296 	jword = skip_space (src);
297 	src = skip_nonspace (jword);
298 	savec = *src;
299 	*src = '\0';
300 	if (cur == total) {
301 	    char **prevargv = argv;
302 	    total += WORDSTOALLOC;
303 	    argv = (char **) realloc (argv, total * sizeof (char *));
304 	    if (!argv) {
305 		free (prevargv);
306 		return NULL;
307 	    }
308 	}
309 	argv[cur++] = jword;
310 	if (savec) src++;		/* if not last on line advance */
311     } while (jword != src);
312 
313     argv[--cur] = NULL;			/* smash empty token to end list */
314     *argcp = cur;
315     return argv;
316 }
317 
318 
open_file(const char ** filenamep,const char * mode,Bool * usedstdp,const char * srcfn,int srcln,const char * cmd)319 static FILE *open_file (
320     const char **filenamep,
321     const char *mode,
322     Bool *usedstdp,
323     const char *srcfn,
324     int srcln,
325     const char *cmd)
326 {
327     FILE *fp;
328 
329     if (strcmp (*filenamep, "-") == 0) {
330 	*usedstdp = True;
331 					/* select std descriptor to use */
332 	if (mode[0] == 'r') {
333 	    if (okay_to_use_stdin) {
334 		okay_to_use_stdin = False;
335 		*filenamep = stdin_filename;
336 		return stdin;
337 	    } else {
338 		prefix (srcfn, srcln);
339 		fprintf (stderr, "%s:  stdin already in use\n", cmd);
340 		return NULL;
341 	    }
342 	} else {
343 	    *filenamep = stdout_filename;
344 	    return stdout;		/* always okay to use stdout */
345 	}
346     }
347 
348     fp = fopen (*filenamep, mode);
349     if (!fp) {
350 	prefix (srcfn, srcln);
351 	fprintf (stderr, "%s:  unable to open file %s\n", cmd, *filenamep);
352     }
353     return fp;
354 }
355 
356 
read_auth_entries(FILE * fp,AuthList ** headp,AuthList ** tailp)357 static int read_auth_entries (FILE *fp, AuthList **headp, AuthList **tailp)
358 {
359     IceAuthFileEntry *auth;
360     AuthList *head, *tail;
361     int n;
362 
363     head = tail = NULL;
364     n = 0;
365 					/* put all records into linked list */
366     while ((auth = IceReadAuthFileEntry (fp)) != NULL) {
367 	AuthList *l = (AuthList *) malloc (sizeof (AuthList));
368 	if (!l) {
369 	    fprintf (stderr,
370 		     "%s:  unable to alloc entry reading auth file\n",
371 		     ProgramName);
372 	    exit (1);
373 	}
374 	l->next = NULL;
375 	l->auth = auth;
376 	if (tail) 			/* if not first time through append */
377 	  tail->next = l;
378 	else
379 	  head = l;			/* first time through, so assign */
380 	tail = l;
381 	n++;
382     }
383     *headp = head;
384     *tailp = tail;
385     return n;
386 }
387 
388 
cvthexkey(const char * hexstr,char ** ptrp)389 static int cvthexkey (	/* turn hex key string into octets */
390     const char *hexstr,
391     char **ptrp)
392 {
393     unsigned int i;
394     unsigned int len = 0;
395     char *retval;
396     const char *s;
397     unsigned char *us;
398     char c;
399     char savec = '\0';
400 
401     /* count */
402     for (s = hexstr; *s; s++) {
403 	if (!isascii(*s)) return -1;
404 	if (isspace(*s)) continue;
405 	if (!isxdigit(*s)) return -1;
406 	len++;
407     }
408 
409     /* if 0 or odd, then there was an error */
410     if (len == 0 || (len & 1) == 1) return -1;
411 
412 
413     /* now we know that the input is good */
414     len >>= 1;
415     retval = malloc (len);
416     if (!retval) {
417 	fprintf (stderr, "%s:  unable to allocate %d bytes for hexkey\n",
418 		 ProgramName, len);
419 	return -1;
420     }
421 
422     for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
423 	c = *hexstr;
424 	if (isspace(c)) continue;	 /* already know it is ascii */
425 	if (isupper(c))
426 	    c = tolower(c);
427 	if (savec) {
428 #define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
429 	    *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
430 #undef atoh
431 	    savec = 0;		/* ready for next character */
432 	    us++;
433 	    i--;
434 	} else {
435 	    savec = c;
436 	}
437     }
438     *ptrp = retval;
439     return (int) len;
440 }
441 
dispatch_command(const char * inputfilename,int lineno,int argc,const char ** argv,const CommandTable * tab,int * statusp)442 static int dispatch_command (
443     const char *inputfilename,
444     int lineno,
445     int argc,
446     const char **argv,
447     const CommandTable *tab,
448     int *statusp)
449 {
450     const CommandTable *ct;
451     const char *cmd;
452     size_t n;
453 					/* scan table for command */
454     cmd = argv[0];
455     n = strlen (cmd);
456     for (ct = tab; ct->name; ct++) {
457 					/* look for unique prefix */
458 	if (n >= ct->minlen && n <= ct->maxlen &&
459 	    strncmp (cmd, ct->name, n) == 0) {
460 	    *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
461 	    return 1;
462 	}
463     }
464 
465     *statusp = 1;
466     return 0;
467 }
468 
469 
470 static AuthList *iceauth_head = NULL;	/* list of auth entries */
471 static Bool iceauth_existed = False;	/* if was present at initialize */
472 static Bool iceauth_modified = False;	/* if added, removed, or merged */
473 static Bool iceauth_allowed = True;	/* if allowed to write auth file */
474 static char *iceauth_filename = NULL;
475 static volatile Bool dieing = False;
476 
477 /* poor man's puts(), for under signal handlers */
478 #define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
479 
480 /* ARGSUSED */
die(_X_UNUSED int sig)481 static void die (_X_UNUSED int sig)
482 {
483     dieing = True;
484     _exit (auth_finalize ());
485     /* NOTREACHED */
486 }
487 
catchsig(int sig)488 static void catchsig (int sig)
489 {
490 #ifdef SYSV
491     if (sig > 0) signal (sig, die);	/* re-establish signal handler */
492 #endif
493     /*
494      * fileno() might not be reentrant, avoid it if possible, and use
495      * stderr instead of stdout
496      */
497 #ifdef STDERR_FILENO
498     if (verbose && iceauth_modified) WRITES(STDERR_FILENO, "\r\n");
499 #else
500     if (verbose && iceauth_modified) WRITES(fileno(stderr), "\r\n");
501 #endif
502     die (sig);
503     /* NOTREACHED */
504 }
505 
register_signals(void)506 static void register_signals (void)
507 {
508     signal (SIGINT, catchsig);
509     signal (SIGTERM, catchsig);
510 #ifdef SIGHUP
511     signal (SIGHUP, catchsig);
512 #endif
513     return;
514 }
515 
516 
517 /*
518  * public procedures for parsing lines of input
519  */
520 
auth_initialize(char * authfilename)521 int auth_initialize ( char *authfilename )
522 {
523     int n;
524     AuthList *head, *tail;
525     FILE *authfp;
526     Bool exists;
527 
528     register_signals ();
529 
530     bzero ((char *) hexvalues, sizeof hexvalues);
531     hexvalues['0'] = 0;
532     hexvalues['1'] = 1;
533     hexvalues['2'] = 2;
534     hexvalues['3'] = 3;
535     hexvalues['4'] = 4;
536     hexvalues['5'] = 5;
537     hexvalues['6'] = 6;
538     hexvalues['7'] = 7;
539     hexvalues['8'] = 8;
540     hexvalues['9'] = 9;
541     hexvalues['a'] = hexvalues['A'] = 0xa;
542     hexvalues['b'] = hexvalues['B'] = 0xb;
543     hexvalues['c'] = hexvalues['C'] = 0xc;
544     hexvalues['d'] = hexvalues['D'] = 0xd;
545     hexvalues['e'] = hexvalues['E'] = 0xe;
546     hexvalues['f'] = hexvalues['F'] = 0xf;
547 
548     if (break_locks && verbose) {
549 	printf ("Attempting to break locks on authority file %s\n",
550 		authfilename);
551     }
552 
553     iceauth_filename = strdup(authfilename);
554 
555     if (ignore_locks) {
556 	if (break_locks) IceUnlockAuthFile (authfilename);
557     } else {
558 	n = IceLockAuthFile (authfilename, ICEAUTH_DEFAULT_RETRIES,
559 			 ICEAUTH_DEFAULT_TIMEOUT,
560 			 (break_locks ? 0L : ICEAUTH_DEFAULT_DEADTIME));
561 	if (n != IceAuthLockSuccess) {
562 	    const char *reason = "unknown error";
563 	    switch (n) {
564 	      case IceAuthLockError:
565 		reason = "error";
566 		break;
567 	      case IceAuthLockTimeout:
568 		reason = "timeout";
569 		break;
570 	    }
571 	    fprintf (stderr, "%s:  %s in locking authority file %s\n",
572 		     ProgramName, reason, authfilename);
573 	    return -1;
574 	}
575     }
576 
577     /* these checks can only be done reliably after the file is locked */
578     exists = (access (authfilename, F_OK) == 0);
579     if (exists && access (authfilename, W_OK) != 0) {
580 	fprintf (stderr,
581 	 "%s:  %s not writable, changes will be ignored\n",
582 		 ProgramName, authfilename);
583 	iceauth_allowed = False;
584     }
585 
586     original_umask = umask (0077);	/* disallow non-owner access */
587 
588     authfp = fopen (authfilename, "rb");
589     if (!authfp) {
590 	int olderrno = errno;
591 
592 					/* if file there then error */
593 	if (access (authfilename, F_OK) == 0) {	 /* then file does exist! */
594 	    errno = olderrno;
595 	    return -1;
596 	}				/* else ignore it */
597 	fprintf (stderr,
598 		 "%s:  creating new authority file %s\n",
599 		 ProgramName, authfilename);
600     } else {
601 	iceauth_existed = True;
602 	n = read_auth_entries (authfp, &head, &tail);
603 	(void) fclose (authfp);
604 	if (n < 0) {
605 	    fprintf (stderr,
606 		     "%s:  unable to read auth entries from file \"%s\"\n",
607 		     ProgramName, authfilename);
608 	    return -1;
609 	}
610 	iceauth_head = head;
611     }
612 
613     iceauth_modified = False;
614 
615     if (verbose) {
616 	printf ("%s authority file %s\n",
617 		ignore_locks ? "Ignoring locks on" : "Using", authfilename);
618     }
619     return 0;
620 }
621 
write_auth_file(char * tmp_nam,size_t tmp_nam_len)622 static int write_auth_file (char *tmp_nam, size_t tmp_nam_len)
623 {
624     FILE *fp;
625     AuthList *list;
626 
627     if ((strlen(iceauth_filename) + 3) > tmp_nam_len) {
628 	strncpy(tmp_nam, "filename too long", tmp_nam_len);
629 	tmp_nam[tmp_nam_len - 1] = '\0';
630 	return -1;
631     }
632 
633     strcpy (tmp_nam, iceauth_filename);
634     strcat (tmp_nam, "-n");		/* for new */
635     (void) unlink (tmp_nam);
636     fp = fopen (tmp_nam, "wb");		/* umask is still set to 0077 */
637     if (!fp) {
638 	fprintf (stderr, "%s:  unable to open tmp file \"%s\"\n",
639 		 ProgramName, tmp_nam);
640 	return -1;
641     }
642 
643     for (list = iceauth_head; list; list = list->next)
644 	IceWriteAuthFileEntry (fp, list->auth);
645 
646     (void) fclose (fp);
647     return 0;
648 }
649 
auth_finalize(void)650 int auth_finalize (void)
651 {
652     char temp_name[1024];			/* large filename size */
653 
654     if (iceauth_modified) {
655 	if (dieing) {
656 	    if (verbose) {
657 		/*
658 		 * called from a signal handler -- printf is *not* reentrant; also
659 		 * fileno() might not be reentrant, avoid it if possible, and use
660 		 * stderr instead of stdout
661 		 */
662 #ifdef STDERR_FILENO
663 		WRITES(STDERR_FILENO, "\nAborting changes to authority file ");
664 		WRITES(STDERR_FILENO, iceauth_filename);
665 		WRITES(STDERR_FILENO, "\n");
666 #else
667 		WRITES(fileno(stderr), "\nAborting changes to authority file ");
668 		WRITES(fileno(stderr), iceauth_filename);
669 		WRITES(fileno(stderr), "\n");
670 #endif
671 	    }
672 	} else if (!iceauth_allowed) {
673 	    fprintf (stderr,
674 		     "%s:  %s not writable, changes ignored\n",
675 		     ProgramName, iceauth_filename);
676 	} else {
677 	    if (verbose) {
678 		printf ("%s authority file %s\n",
679 			ignore_locks ? "Ignoring locks and writing" :
680 			"Writing", iceauth_filename);
681 	    }
682 	    temp_name[0] = '\0';
683 	    if (write_auth_file (temp_name, sizeof(temp_name)) == -1) {
684 		fprintf (stderr,
685 			 "%s:  unable to write authority file %s\n",
686 			 ProgramName, temp_name);
687 	    } else {
688 		(void) unlink (iceauth_filename);
689 #if defined(WIN32) || defined(__UNIXOS2__)
690 		if (rename(temp_name, iceauth_filename) == -1)
691 #else
692 		/* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */
693 		if (link (temp_name, iceauth_filename) == -1 && rename(temp_name, iceauth_filename) == -1)
694 #endif
695 		{
696 		    fprintf (stderr,
697 		     "%s:  unable to link authority file %s, use %s\n",
698 			     ProgramName, iceauth_filename, temp_name);
699 		} else {
700 		    (void) unlink (temp_name);
701 		}
702 	    }
703 	}
704     }
705 
706     if (!ignore_locks && (iceauth_filename != NULL)) {
707 	IceUnlockAuthFile (iceauth_filename);
708     }
709     (void) umask (original_umask);
710     return 0;
711 }
712 
process_command(const char * inputfilename,int lineno,int argc,const char ** argv)713 int process_command (
714     const char *inputfilename,
715     int lineno,
716     int argc,
717     const char **argv)
718 {
719     int status;
720 
721     if (argc < 1 || !argv || !argv[0]) return 1;
722 
723     if (dispatch_command (inputfilename, lineno, argc, argv,
724 			  command_table, &status))
725       return status;
726 
727     prefix (inputfilename, lineno);
728     fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
729     return 1;
730 }
731 
732 
733 /*
734  * utility routines
735  */
736 
fprintfhex(register FILE * fp,unsigned int len,const char * cp)737 static void fprintfhex (
738     register FILE *fp,
739     unsigned int len,
740     const char *cp)
741 {
742     const unsigned char *ucp = (const unsigned char *) cp;
743 
744     for (; len > 0; len--, ucp++) {
745 	register const char *s = hex_table[*ucp];
746 	putc (s[0], fp);
747 	putc (s[1], fp);
748     }
749     return;
750 }
751 
752 /* ARGSUSED */
dump_entry(const char * inputfilename _X_UNUSED,int lineno _X_UNUSED,IceAuthFileEntry * auth,void * data)753 static int dump_entry (
754     const char *inputfilename _X_UNUSED,
755     int lineno _X_UNUSED,
756     IceAuthFileEntry *auth,
757     void *data)
758 {
759     struct _list_data *ld = (struct _list_data *) data;
760     FILE *fp = ld->fp;
761 
762     fprintf (fp, "%s", auth->protocol_name);
763     putc (' ', fp);
764     if (auth->protocol_data_length > 0)
765 	fprintfhex (fp, auth->protocol_data_length, auth->protocol_data);
766     else
767 	fprintf (fp, "\"\"");
768     putc (' ', fp);
769     fprintf (fp, "%s", auth->network_id);
770     putc (' ', fp);
771     fprintf (fp, "%s", auth->auth_name);
772     putc (' ', fp);
773 
774     if (auth->auth_data_length == 0)
775 	fprintf (fp, "\"\"");
776     else if (!strcmp(auth->auth_name, SECURERPC) ||
777 	!strcmp(auth->auth_name, K5AUTH))
778 	fwrite (auth->auth_data, sizeof (char), auth->auth_data_length, fp);
779     else
780 	fprintfhex (fp, auth->auth_data_length, auth->auth_data);
781     putc ('\n', fp);
782 
783     return 0;
784 }
785 
extract_entry(const char * inputfilename,int lineno,IceAuthFileEntry * auth,void * data)786 static int extract_entry (
787     const char *inputfilename,
788     int lineno,
789     IceAuthFileEntry *auth,
790     void *data)
791 {
792     struct _extract_data *ed = (struct _extract_data *) data;
793 
794     if (!ed->fp) {
795 	ed->fp = open_file (&ed->filename, "wb",
796 			    &ed->used_stdout,
797 			    inputfilename, lineno, ed->cmd);
798 	if (!ed->fp) {
799 	    prefix (inputfilename, lineno);
800 	    fprintf (stderr,
801 		     "unable to open extraction file \"%s\"\n",
802 		     ed->filename);
803 	    return -1;
804 	}
805     }
806     IceWriteAuthFileEntry (ed->fp, auth);
807     ed->nwritten++;
808 
809     return 0;
810 }
811 
812 
match_auth(register IceAuthFileEntry * a,register IceAuthFileEntry * b,int * authDataSame)813 static int match_auth (
814     register IceAuthFileEntry *a,
815     register IceAuthFileEntry *b,
816     int *authDataSame)
817 {
818     int match = strcmp (a->protocol_name, b->protocol_name) == 0 &&
819 	    strcmp (a->network_id, b->network_id) == 0 &&
820             strcmp (a->auth_name, b->auth_name) == 0;
821 
822     if (match)
823     {
824 	*authDataSame = (a->auth_data_length == b->auth_data_length &&
825 	    binaryEqual (a->auth_data, b->auth_data, a->auth_data_length));
826     }
827     else
828 	*authDataSame = 0;
829 
830     return (match);
831 }
832 
833 
merge_entries(AuthList ** firstp,AuthList * second,int * nnewp,int * nreplp,int * ndupp)834 static int merge_entries (
835     AuthList **firstp, AuthList *second,
836     int *nnewp, int *nreplp, int *ndupp)
837 {
838     AuthList *a, *b, *first, *tail;
839     int n = 0, nnew = 0, nrepl = 0, ndup = 0;
840 
841     if (!second) return 0;
842 
843     if (!*firstp) {			/* if nothing to merge into */
844 	*firstp = second;
845 	for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
846 	*nnewp = n;
847 	*nreplp = 0;
848 	*ndupp = 0;
849 	return n;
850     }
851 
852     first = *firstp;
853     /*
854      * find end of first list and stick second list on it
855      */
856     for (tail = first; tail->next; tail = tail->next) ;
857     tail->next = second;
858 
859     /*
860      * run down list freeing duplicate entries; if an entry is okay, then
861      * bump the tail up to include it, otherwise, cut the entry out of
862      * the chain.
863      */
864     for (b = second; b; ) {
865 	AuthList *next = b->next;	/* in case we free it */
866 	int duplicate;
867 
868 	duplicate = 0;
869 	a = first;
870 	for (;;) {
871 	    int authDataSame;
872 	    if (match_auth (a->auth, b->auth, &authDataSame)) {
873 		if (authDataSame)
874 		{
875 		    /* found a complete duplicate, ignore */
876 		    duplicate = 1;
877 		    break;
878 		}
879 		else
880 		{
881 		    /* found a duplicate, but auth data differs */
882 
883 		    AuthList tmp;		/* swap it in for old one */
884 		    tmp = *a;
885 		    *a = *b;
886 		    *b = tmp;
887 		    a->next = b->next;
888 		    IceFreeAuthFileEntry (b->auth);
889 		    free ((char *) b);
890 		    b = NULL;
891 		    tail->next = next;
892 		    nrepl++;
893 		    nnew--;
894 		    break;
895 		}
896 	    }
897 	    if (a == tail) break;	/* if have looked at left side */
898 	    a = a->next;
899 	}
900 	if (!duplicate && b) {		/* if we didn't remove it */
901 	    tail = b;			/* bump end of first list */
902 	}
903 	b = next;
904 
905 	if (duplicate)
906 	    ndup++;
907 	else
908 	{
909 	    n++;
910 	    nnew++;
911 	}
912     }
913 
914     *nnewp = nnew;
915     *nreplp = nrepl;
916     *ndupp = ndup;
917     return n;
918 
919 }
920 
921 
search_and_do(const char * inputfilename,int lineno,int start,int argc,const char * argv[],DoFunc do_func,void * data)922 static int search_and_do (
923     const char *inputfilename,
924     int lineno,
925     int start,
926     int argc,
927     const char *argv[],
928     DoFunc do_func,
929     void *data)
930 {
931     int i;
932     int status = 0;
933     int errors = 0;
934     AuthList *l, *next;
935     const char *protoname, *protodata, *netid, *authname;
936 
937     for (l = iceauth_head; l; l = next)
938     {
939 	next = l->next;
940 
941 	protoname = protodata = netid = authname = NULL;
942 
943 	for (i = start; i < argc; i++)
944 	{
945 	    if (!strncmp ("protoname=", argv[i], 10))
946 		protoname = argv[i] + 10;
947 	    else if (!strncmp ("protodata=", argv[i], 10))
948 		protodata = argv[i] + 10;
949 	    else if (!strncmp ("netid=", argv[i], 6))
950 		netid = argv[i] + 6;
951 	    else if (!strncmp ("authname=", argv[i], 9))
952 		authname = argv[i] + 9;
953 	}
954 
955 	status = 0;
956 
957 	if (protoname || protodata || netid || authname)
958 	{
959 	    if (protoname && strcmp (protoname, l->auth->protocol_name))
960 		continue;
961 
962 	    if (protodata && !binaryEqual (protodata,
963 		l->auth->protocol_data, l->auth->protocol_data_length))
964 		continue;
965 
966 	    if (netid && strcmp (netid, l->auth->network_id))
967 		continue;
968 
969 	    if (authname && strcmp (authname, l->auth->auth_name))
970 		continue;
971 
972 	    status = (*do_func) (inputfilename, lineno, l->auth, data);
973 
974 	    if (status < 0)
975 		break;
976 	}
977     }
978 
979     if (status < 0)
980 	errors -= status;		/* since status is negative */
981 
982     return (errors);
983 }
984 
985 
986 /* ARGSUSED */
remove_entry(const char * inputfilename _X_UNUSED,int lineno _X_UNUSED,IceAuthFileEntry * auth,void * data)987 static int remove_entry (
988     const char *inputfilename _X_UNUSED,
989     int lineno _X_UNUSED,
990     IceAuthFileEntry *auth,
991     void *data)
992 {
993     int *nremovedp = (int *) data;
994     AuthList **listp = &iceauth_head;
995     AuthList *list;
996 
997     /*
998      * unlink the auth we were asked to
999      */
1000     while ((list = *listp)->auth != auth)
1001 	listp = &list->next;
1002     *listp = list->next;
1003     IceFreeAuthFileEntry (list->auth);                    /* free the auth */
1004     free (list);				    /* free the link */
1005     iceauth_modified = True;
1006     (*nremovedp)++;
1007     return 1;
1008 }
1009 
1010 /*
1011  * action routines
1012  */
1013 
1014 /*
1015  * help
1016  */
print_help(FILE * fp,const char * cmd)1017 int print_help (
1018     FILE *fp,
1019     const char *cmd)
1020 {
1021     const CommandTable *ct;
1022     int n = 0;
1023 
1024     fprintf (fp, "\n");
1025     if (!cmd) {				/* if no cmd, print all help */
1026 	for (ct = command_table; ct->name; ct++) {
1027 	    fprintf (fp, "%s\n\n", ct->helptext);
1028 	    n++;
1029 	}
1030     } else {
1031 	size_t len = strlen (cmd);
1032 	for (ct = command_table; ct->name; ct++) {
1033 	    if (strncmp (cmd, ct->name, len) == 0) {
1034 		fprintf (fp, "%s\n\n", ct->helptext);
1035 		n++;
1036 	    }
1037 	}
1038     }
1039 
1040     return n;
1041 }
1042 
do_help(const char * inputfilename,int lineno,int argc,const char ** argv)1043 static int do_help (
1044     const char *inputfilename,
1045     int lineno,
1046     int argc,
1047     const char **argv)
1048 {
1049     const char *cmd = (argc > 1 ? argv[1] : NULL);
1050     int n;
1051 
1052     n = print_help (stdout, cmd);
1053 
1054     if (n < 0 || (n == 0 && !cmd)) {
1055 	prefix (inputfilename, lineno);
1056 	fprintf (stderr, "internal error with help");
1057 	if (cmd) {
1058 	    fprintf (stderr, " on command \"%s\"", cmd);
1059 	}
1060 	fprintf (stderr, "\n");
1061 	return 1;
1062     }
1063 
1064     if (n == 0) {
1065 	prefix (inputfilename, lineno);
1066 	/* already know that cmd is set in this case */
1067 	fprintf (stderr, "no help for nonexistent command \"%s\"\n", cmd);
1068     }
1069 
1070     return 0;
1071 }
1072 
1073 /*
1074  * questionmark
1075  */
1076 /* ARGSUSED */
do_questionmark(const char * inputfilename _X_UNUSED,int lineno _X_UNUSED,int argc _X_UNUSED,const char ** argv _X_UNUSED)1077 static int do_questionmark (
1078     const char *inputfilename _X_UNUSED,
1079     int lineno _X_UNUSED,
1080     int argc _X_UNUSED,
1081     const char **argv _X_UNUSED)
1082 {
1083     const CommandTable *ct;
1084     unsigned int i;
1085 #define WIDEST_COLUMN 72
1086     unsigned int col = WIDEST_COLUMN;
1087 
1088     printf ("Commands:\n");
1089     for (ct = command_table; ct->name; ct++) {
1090 	if ((col + ct->maxlen) > WIDEST_COLUMN) {
1091 	    if (ct != command_table) {
1092 		putc ('\n', stdout);
1093 	    }
1094 	    fputs ("        ", stdout);
1095 	    col = 8;			/* length of string above */
1096 	}
1097 	fputs (ct->name, stdout);
1098 	col += ct->maxlen;
1099 	for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
1100 	    putc (' ', stdout);
1101 	    col++;
1102 	}
1103     }
1104     if (col != 0) {
1105 	putc ('\n', stdout);
1106     }
1107 
1108     /* allow bad lines since this is help */
1109     return 0;
1110 }
1111 
1112 /*
1113  * list [displayname ...]
1114  */
do_list(const char * inputfilename,int lineno,int argc,const char ** argv)1115 static int do_list (
1116     const char *inputfilename,
1117     int lineno,
1118     int argc,
1119     const char **argv)
1120 {
1121     struct _list_data ld;
1122 
1123     ld.fp = stdout;
1124 
1125     if (argc == 1) {
1126 	register AuthList *l;
1127 
1128 	if (iceauth_head) {
1129 	    for (l = iceauth_head; l; l = l->next) {
1130 		dump_entry (inputfilename, lineno, l->auth, &ld);
1131 	    }
1132 	}
1133 	return 0;
1134     }
1135     else
1136     {
1137 	return (search_and_do (inputfilename, lineno, 1, argc, argv,
1138 	    dump_entry, &ld));
1139     }
1140 }
1141 
1142 /*
1143  * merge filename [filename ...]
1144  */
do_merge(const char * inputfilename,int lineno,int argc,const char ** argv)1145 static int do_merge (
1146     const char *inputfilename,
1147     int lineno,
1148     int argc,
1149     const char **argv)
1150 {
1151     int i;
1152     int errors = 0;
1153     AuthList *head, *tail, *listhead, *listtail;
1154     int nentries, nnew, nrepl, ndup;
1155 
1156     if (argc < 2) {
1157 	prefix (inputfilename, lineno);
1158 	badcommandline (argv[0]);
1159 	return 1;
1160     }
1161 
1162     listhead = listtail = NULL;
1163 
1164     for (i = 1; i < argc; i++) {
1165 	const char *filename = argv[i];
1166 	FILE *fp;
1167 	Bool used_stdin = False;
1168 
1169 	fp = open_file (&filename, "rb",
1170 			&used_stdin, inputfilename, lineno,
1171 			argv[0]);
1172 	if (!fp) {
1173 	    errors++;
1174 	    continue;
1175 	}
1176 
1177 	head = tail = NULL;
1178 	nentries = read_auth_entries (fp, &head, &tail);
1179 	if (nentries == 0) {
1180 	    prefix (inputfilename, lineno);
1181 	    fprintf (stderr, "unable to read any entries from file \"%s\"\n",
1182 		     filename);
1183 	    errors++;
1184 	} else {			/* link it in */
1185 	    add_to_list (listhead, listtail, head);
1186  	}
1187 
1188 	if (!used_stdin) (void) fclose (fp);
1189     }
1190 
1191     /*
1192      * if we have new entries, merge them in (freeing any duplicates)
1193      */
1194     if (listhead) {
1195 	nentries = merge_entries (&iceauth_head, listhead,
1196 	    &nnew, &nrepl, &ndup);
1197 	if (verbose)
1198 	  printf ("%d entries read in:  %d new, %d replacement%s\n",
1199 	  	  nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
1200 	if (nentries > 0) iceauth_modified = True;
1201     }
1202 
1203     return 0;
1204 }
1205 
1206 /*
1207  * extract filename displayname [displayname ...]
1208  */
do_extract(const char * inputfilename,int lineno,int argc,const char ** argv)1209 static int do_extract (
1210     const char *inputfilename,
1211     int lineno,
1212     int argc,
1213     const char **argv)
1214 {
1215     int errors;
1216     struct _extract_data ed;
1217 
1218     if (argc < 3) {
1219 	prefix (inputfilename, lineno);
1220 	badcommandline (argv[0]);
1221 	return 1;
1222     }
1223 
1224     ed.fp = NULL;
1225     ed.filename = argv[1];
1226     ed.nwritten = 0;
1227     ed.cmd = argv[0];
1228 
1229     errors = search_and_do (inputfilename, lineno, 2, argc, argv,
1230 	extract_entry, &ed);
1231 
1232     if (!ed.fp) {
1233 	fprintf (stderr,
1234 		 "No matches found, authority file \"%s\" not written\n",
1235 		 ed.filename);
1236     } else {
1237 	if (verbose) {
1238 	    printf ("%d entries written to \"%s\"\n",
1239 		    ed.nwritten, ed.filename);
1240 	}
1241 	if (!ed.used_stdout) {
1242 	    (void) fclose (ed.fp);
1243 	}
1244     }
1245 
1246     return errors;
1247 }
1248 
1249 
1250 /*
1251  * add protoname protodata netid authname authdata
1252  */
do_add(const char * inputfilename,int lineno,int argc,const char ** argv)1253 static int do_add (
1254     const char *inputfilename,
1255     int lineno,
1256     int argc,
1257     const char **argv)
1258 {
1259     int n, nnew, nrepl, ndup;
1260     const char *protoname;
1261     const char *protodata_hex;
1262     char *protodata = NULL; /* not required */
1263     const char *netid;
1264     const char *authname;
1265     const char *authdata_hex;
1266     char *authdata = NULL;
1267     int protodata_len, authdata_len;
1268     IceAuthFileEntry *auth = NULL;
1269     AuthList *list;
1270     int status = 0;
1271 
1272     if (argc != 6 || !argv[1] || !argv[2] ||
1273 	!argv[3] || !argv[4] || !argv[5])
1274     {
1275 	prefix (inputfilename, lineno);
1276 	badcommandline (argv[0]);
1277 	return 1;
1278     }
1279 
1280     protoname = argv[1];
1281     protodata_hex = argv[2];
1282     netid = argv[3];
1283     authname = argv[4];
1284     authdata_hex = argv[5];
1285 
1286     protodata_len = strlen (protodata_hex);
1287     if (protodata_len > 0)
1288     {
1289 	if (protodata_hex[0] == '"' && protodata_hex[protodata_len - 1] == '"')
1290 	{
1291 	    protodata = malloc (protodata_len - 1);
1292 	    if (protodata)
1293 	    {
1294 		strncpy (protodata, protodata_hex + 1, protodata_len - 2);
1295 		protodata_len -= 2;
1296 	    }
1297 	    else
1298 		goto add_bad_malloc;
1299 	}
1300 	else
1301 	{
1302 	    protodata_len = cvthexkey (protodata_hex, &protodata);
1303 	    if (protodata_len < 0)
1304 	    {
1305 		prefix (inputfilename, lineno);
1306 		fprintf (stderr,
1307 	       "protodata_hex contains odd number of or non-hex characters\n");
1308 		return (1);
1309 	    }
1310 	}
1311     }
1312 
1313     authdata_len = strlen (authdata_hex);
1314     if (authdata_hex[0] == '"' && authdata_hex[authdata_len - 1] == '"')
1315     {
1316 	authdata = malloc (authdata_len - 1);
1317 	if (authdata)
1318 	{
1319 	    strncpy (authdata, authdata_hex + 1, authdata_len - 2);
1320 	    authdata_len -= 2;
1321 	}
1322 	else
1323 	    goto add_bad_malloc;
1324     }
1325     else if (!strcmp (protoname, SECURERPC) || !strcmp (protoname, K5AUTH))
1326     {
1327 	authdata = malloc (authdata_len + 1);
1328 	if (authdata)
1329 	    strcpy (authdata, authdata_hex);
1330 	else
1331 	    goto add_bad_malloc;
1332     }
1333     else
1334     {
1335 	authdata_len = cvthexkey (authdata_hex, &authdata);
1336 	if (authdata_len < 0)
1337 	{
1338 	    prefix (inputfilename, lineno);
1339 	    fprintf (stderr,
1340 	       "authdata_hex contains odd number of or non-hex characters\n");
1341 	    free (protodata);
1342 	    return (1);
1343 	}
1344     }
1345 
1346     auth = (IceAuthFileEntry *) malloc (sizeof (IceAuthFileEntry));
1347 
1348     if (!auth)
1349 	goto add_bad_malloc;
1350 
1351     auth->protocol_name = copystring (protoname);
1352     auth->protocol_data_length = protodata_len;
1353     auth->protocol_data = protodata;
1354     auth->network_id = copystring (netid);
1355     auth->auth_name = copystring (authname);
1356     auth->auth_data_length = authdata_len;
1357     auth->auth_data = authdata;
1358 
1359     if (!auth->protocol_name ||
1360 	(!auth->protocol_data && auth->protocol_data_length > 0) ||
1361         !auth->network_id || !auth->auth_name ||
1362 	(!auth->auth_data && auth->auth_data_length > 0))
1363     {
1364 	goto add_bad_malloc;
1365     }
1366 
1367     list = (AuthList *) malloc (sizeof (AuthList));
1368 
1369     if (!list)
1370 	goto add_bad_malloc;
1371 
1372     list->next = NULL;
1373     list->auth = auth;
1374 
1375     /*
1376      * merge it in; note that merge will deal with allocation
1377      */
1378 
1379     n = merge_entries (&iceauth_head, list, &nnew, &nrepl, &ndup);
1380 
1381     if (n > 0)
1382 	iceauth_modified = True;
1383     else
1384     {
1385 	prefix (inputfilename, lineno);
1386 	if (ndup > 0)
1387 	{
1388 	    status = 0;
1389 	    fprintf (stderr, "no records added - all duplicate\n");
1390 	}
1391 	else
1392 	{
1393 	    status = 1;
1394 	    fprintf (stderr, "unable to merge in added record\n");
1395 	}
1396 	goto cant_add;
1397     }
1398 
1399     return 0;
1400 
1401 
1402 add_bad_malloc:
1403 
1404     status = 1;
1405     prefix (inputfilename, lineno);
1406     fprintf (stderr, "unable to allocate memory to add an entry\n");
1407 
1408 cant_add:
1409 
1410     if (protodata)
1411 	free (protodata);
1412     if (authdata)
1413 	free (authdata);
1414     if (auth)
1415     {
1416 	if (auth->protocol_name)
1417 	    free (auth->protocol_name);
1418 	/* auth->protocol_data already freed,
1419 	   since it's the same as protodata */
1420 	if (auth->network_id)
1421 	    free (auth->network_id);
1422 	if (auth->auth_name)
1423 	    free (auth->auth_name);
1424 	/* auth->auth_data already freed,
1425 	   since it's the same as authdata */
1426 	free ((char *) auth);
1427     }
1428 
1429     return status;
1430 }
1431 
1432 /*
1433  * remove displayname
1434  */
do_remove(const char * inputfilename,int lineno,int argc,const char ** argv)1435 static int do_remove (
1436     const char *inputfilename,
1437     int lineno,
1438     int argc,
1439     const char **argv)
1440 {
1441     int nremoved = 0;
1442     int errors;
1443 
1444     if (argc < 2) {
1445 	prefix (inputfilename, lineno);
1446 	badcommandline (argv[0]);
1447 	return 1;
1448     }
1449 
1450     errors = search_and_do (inputfilename, lineno, 1, argc, argv,
1451 	remove_entry, &nremoved);
1452     if (verbose) printf ("%d entries removed\n", nremoved);
1453     return errors;
1454 }
1455 
1456 /*
1457  * info
1458  */
do_info(const char * inputfilename,int lineno,int argc,const char ** argv)1459 static int do_info (
1460     const char *inputfilename,
1461     int lineno,
1462     int argc,
1463     const char **argv)
1464 {
1465     int n;
1466     AuthList *l;
1467 
1468     if (argc != 1) {
1469 	prefix (inputfilename, lineno);
1470 	badcommandline (argv[0]);
1471 	return 1;
1472     }
1473 
1474     for (l = iceauth_head, n = 0; l; l = l->next, n++) ;
1475 
1476     printf ("Authority file:       %s\n",
1477 	    iceauth_filename ? iceauth_filename : "(none)");
1478     printf ("File new:             %s\n", iceauth_existed ? No : Yes);
1479     printf ("File locked:          %s\n", ignore_locks ? No : Yes);
1480     printf ("Number of entries:    %d\n", n);
1481     printf ("Changes honored:      %s\n", iceauth_allowed ? Yes : No);
1482     printf ("Changes made:         %s\n", iceauth_modified ? Yes : No);
1483     printf ("Current input:        %s:%d\n", inputfilename, lineno);
1484     return 0;
1485 }
1486 
1487 
1488 /*
1489  * exit
1490  */
1491 static Bool alldone = False;
1492 
1493 /* ARGSUSED */
do_exit(const char * inputfilename _X_UNUSED,int lineno _X_UNUSED,int argc _X_UNUSED,const char ** argv _X_UNUSED)1494 static int do_exit (
1495     const char *inputfilename _X_UNUSED,
1496     int lineno _X_UNUSED,
1497     int argc _X_UNUSED,
1498     const char **argv _X_UNUSED)
1499 {
1500     /* allow bogus stuff */
1501     alldone = True;
1502     return 0;
1503 }
1504 
1505 /*
1506  * quit
1507  */
1508 /* ARGSUSED */
do_quit(const char * inputfilename _X_UNUSED,int lineno _X_UNUSED,int argc _X_UNUSED,const char ** argv _X_UNUSED)1509 static int do_quit (
1510     const char *inputfilename _X_UNUSED,
1511     int lineno _X_UNUSED,
1512     int argc _X_UNUSED,
1513     const char **argv _X_UNUSED)
1514 {
1515     /* allow bogus stuff */
1516     die (0);
1517     /* NOTREACHED */
1518     return -1;				/* for picky compilers */
1519 }
1520 
1521 
1522 /*
1523  * source filename
1524  */
do_source(const char * inputfilename,int lineno,int argc,const char ** argv)1525 static int do_source (
1526     const char *inputfilename,
1527     int lineno,
1528     int argc,
1529     const char **argv)
1530 {
1531     const char *script;
1532     char buf[BUFSIZ];
1533     FILE *fp;
1534     Bool used_stdin = False;
1535     size_t len;
1536     int errors = 0, status;
1537     int sublineno = 0;
1538     char **subargv;
1539     int subargc;
1540     Bool prompt = False;		/* only true if reading from tty */
1541 
1542     if (argc != 2 || !argv[1]) {
1543 	prefix (inputfilename, lineno);
1544 	badcommandline (argv[0]);
1545 	return 1;
1546     }
1547 
1548     script = argv[1];
1549 
1550     fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
1551     if (!fp) {
1552 	return 1;
1553     }
1554 
1555     if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
1556 
1557     while (!alldone) {
1558 	buf[0] = '\0';
1559 	if (prompt) {
1560 	    printf ("iceauth> ");
1561 	    fflush (stdout);
1562 	}
1563 	if (fgets (buf, sizeof buf, fp) == NULL) break;
1564 	sublineno++;
1565 	len = strlen (buf);
1566 	if (len == 0 || buf[0] == '#') continue;
1567 	if (buf[len-1] != '\n') {
1568 	    prefix (script, sublineno);
1569 	    fprintf (stderr, "line too long\n");
1570 	    errors++;
1571 	    break;
1572 	}
1573 	buf[--len] = '\0';		/* remove new line */
1574 	subargv = split_into_words (buf, &subargc);
1575 	if (subargv) {
1576 	    status = process_command (script, sublineno, subargc,
1577                                       (const char **) subargv);
1578 	    free ((char *) subargv);
1579 	    errors += status;
1580 	} else {
1581 	    prefix (script, sublineno);
1582 	    fprintf (stderr, "unable to break line into words\n");
1583 	    errors++;
1584 	}
1585     }
1586 
1587     if (!used_stdin) {
1588 	(void) fclose (fp);
1589     }
1590     return errors;
1591 }
1592