Tizen 2.0 Release
[framework/uifw/xorg/util/x11-xserver-utils.git] / iceauth / process.c
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, char **);
51 typedef int (*DoFunc)(const char *, int, IceAuthFileEntry *, char *);
52
53 typedef struct _CommandTable {          /* commands that are understood */
54     char *name;                         /* full name */
55     int minlen;                         /* unique prefix */
56     int maxlen;                         /* strlen(name) */
57     ProcessFunc processfunc;            /* handler */
58     char *helptext;                     /* what to print for help */
59 } CommandTable;
60
61 struct _extract_data {                  /* for iterating */
62     FILE *fp;                           /* input source */
63     char *filename;                     /* name of input */
64     Bool used_stdout;                   /* whether or not need to close */
65     int nwritten;                       /* number of entries written */
66     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 char *stdin_filename = "(stdin)";  /* for messages */
78 static 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 ( 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 ( char *hexstr, char **ptrp );
91 static int dispatch_command ( const char *inputfilename, int lineno, int argc, char **argv, const CommandTable *tab, int *statusp );
92 static void die ( int sig );
93 static void catchsig ( int sig );
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, char *data );
98 static int extract_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, char *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, char *argv[], DoFunc do_func, char *data );
102 static int remove_entry ( const char *inputfilename, int lineno, IceAuthFileEntry *auth, char *data );
103 static int do_help ( const char *inputfilename, int lineno, int argc, char **argv );
104 static int do_questionmark ( const char *inputfilename, int lineno, int argc, char **argv );
105 static int do_list ( const char *inputfilename, int lineno, int argc, char **argv );
106 static int do_merge ( const char *inputfilename, int lineno, int argc, char **argv );
107 static int do_extract ( const char *inputfilename, int lineno, int argc, char **argv );
108 static int do_add ( const char *inputfilename, int lineno, int argc, char **argv );
109 static int do_remove ( const char *inputfilename, int lineno, int argc, char **argv );
110 static int do_info ( const char *inputfilename, int lineno, int argc, char **argv );
111 static int do_exit ( const char *inputfilename, int lineno, int argc, char **argv );
112 static int do_quit ( const char *inputfilename, int lineno, int argc, char **argv );
113 static int do_source ( const char *inputfilename, int lineno, int argc, 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
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
243 static void prefix (const char *fn, int n)
244 {
245     fprintf (stderr, "%s: %s:%d:  ", ProgramName, fn, n);
246 }
247
248 static void badcommandline (const char *cmd)
249 {
250     fprintf (stderr, "bad \"%s\" command line\n", cmd);
251 }
252
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
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
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             total += WORDSTOALLOC;
302             argv = (char **) realloc (argv, total * sizeof (char *));
303             if (!argv) return NULL;
304         }
305         argv[cur++] = jword;
306         if (savec) src++;               /* if not last on line advance */
307     } while (jword != src);
308
309     argv[--cur] = NULL;                 /* smash empty token to end list */
310     *argcp = cur;
311     return argv;
312 }
313
314
315 static FILE *open_file (
316     char **filenamep,
317     const char *mode,
318     Bool *usedstdp,
319     const char *srcfn,
320     int srcln,
321     const char *cmd)
322 {
323     FILE *fp;
324
325     if (strcmp (*filenamep, "-") == 0) {
326         *usedstdp = True;
327                                         /* select std descriptor to use */
328         if (mode[0] == 'r') {
329             if (okay_to_use_stdin) {
330                 okay_to_use_stdin = False;
331                 *filenamep = stdin_filename;
332                 return stdin;
333             } else {
334                 prefix (srcfn, srcln);
335                 fprintf (stderr, "%s:  stdin already in use\n", cmd);
336                 return NULL;
337             }
338         } else {
339             *filenamep = stdout_filename;
340             return stdout;              /* always okay to use stdout */
341         }
342     }
343
344     fp = fopen (*filenamep, mode);
345     if (!fp) {
346         prefix (srcfn, srcln);
347         fprintf (stderr, "%s:  unable to open file %s\n", cmd, *filenamep);
348     }
349     return fp;
350 }
351
352
353 static int read_auth_entries (FILE *fp, AuthList **headp, AuthList **tailp)
354 {
355     IceAuthFileEntry *auth;
356     AuthList *head, *tail;
357     int n;
358
359     head = tail = NULL;
360     n = 0;
361                                         /* put all records into linked list */
362     while ((auth = IceReadAuthFileEntry (fp)) != NULL) {
363         AuthList *l = (AuthList *) malloc (sizeof (AuthList));
364         if (!l) {
365             fprintf (stderr,
366                      "%s:  unable to alloc entry reading auth file\n",
367                      ProgramName);
368             exit (1);
369         }
370         l->next = NULL;
371         l->auth = auth;
372         if (tail)                       /* if not first time through append */
373           tail->next = l;
374         else
375           head = l;                     /* first time through, so assign */
376         tail = l;
377         n++;
378     }
379     *headp = head;
380     *tailp = tail;
381     return n;
382 }
383
384
385 static int cvthexkey (  /* turn hex key string into octets */
386     char *hexstr,
387     char **ptrp)
388 {
389     int i;
390     int len = 0;
391     char *retval, *s;
392     unsigned char *us;
393     char c;
394     char savec = '\0';
395
396     /* count */
397     for (s = hexstr; *s; s++) {
398         if (!isascii(*s)) return -1;
399         if (isspace(*s)) continue;
400         if (!isxdigit(*s)) return -1;
401         len++;
402     }
403
404     /* if 0 or odd, then there was an error */
405     if (len == 0 || (len & 1) == 1) return -1;
406
407
408     /* now we know that the input is good */
409     len >>= 1;
410     retval = malloc (len);
411     if (!retval) {
412         fprintf (stderr, "%s:  unable to allocate %d bytes for hexkey\n",
413                  ProgramName, len);
414         return -1;
415     }
416
417     for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
418         c = *hexstr;
419         if (isspace(c)) continue;        /* already know it is ascii */
420         if (isupper(c))
421             c = tolower(c);
422         if (savec) {
423 #define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
424             *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
425 #undef atoh
426             savec = 0;          /* ready for next character */
427             us++;
428             i--;
429         } else {
430             savec = c;
431         }
432     }
433     *ptrp = retval;
434     return len;
435 }
436
437 static int dispatch_command (
438     const char *inputfilename,
439     int lineno,
440     int argc,
441     char **argv,
442     const CommandTable *tab,
443     int *statusp)
444 {
445     const CommandTable *ct;
446     char *cmd;
447     int n;
448                                         /* scan table for command */
449     cmd = argv[0];
450     n = strlen (cmd);
451     for (ct = tab; ct->name; ct++) {
452                                         /* look for unique prefix */
453         if (n >= ct->minlen && n <= ct->maxlen &&
454             strncmp (cmd, ct->name, n) == 0) {
455             *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
456             return 1;
457         }
458     }
459
460     *statusp = 1;
461     return 0;
462 }
463
464
465 static AuthList *iceauth_head = NULL;   /* list of auth entries */
466 static Bool iceauth_existed = False;    /* if was present at initialize */
467 static Bool iceauth_modified = False;   /* if added, removed, or merged */
468 static Bool iceauth_allowed = True;     /* if allowed to write auth file */
469 static char *iceauth_filename = NULL;
470 static volatile Bool dieing = False;
471
472 #ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */
473 # define _signal_t RETSIGTYPE
474 #else /* Imake */
475 #ifdef SIGNALRETURNSINT
476 #define _signal_t int
477 #else
478 #define _signal_t void
479 #endif
480 #endif /* RETSIGTYPE */
481
482 /* poor man's puts(), for under signal handlers */
483 #define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
484
485 /* ARGSUSED */
486 static _signal_t die (int sig)
487 {
488     dieing = True;
489     _exit (auth_finalize ());
490     /* NOTREACHED */
491 #ifdef SIGNALRETURNSINT
492     return -1;                          /* for picky compilers */
493 #endif
494 }
495
496 static _signal_t catchsig (int sig)
497 {
498 #ifdef SYSV
499     if (sig > 0) signal (sig, die);     /* re-establish signal handler */
500 #endif
501     /*
502      * fileno() might not be reentrant, avoid it if possible, and use
503      * stderr instead of stdout
504      */
505 #ifdef STDERR_FILENO
506     if (verbose && iceauth_modified) WRITES(STDERR_FILENO, "\r\n");
507 #else
508     if (verbose && iceauth_modified) WRITES(fileno(stderr), "\r\n");
509 #endif
510     die (sig);
511     /* NOTREACHED */
512 #ifdef SIGNALRETURNSINT
513     return -1;                          /* for picky compilers */
514 #endif
515 }
516
517 static void register_signals (void)
518 {
519     signal (SIGINT, catchsig);
520     signal (SIGTERM, catchsig);
521 #ifdef SIGHUP
522     signal (SIGHUP, catchsig);
523 #endif
524     return;
525 }
526
527
528 /*
529  * public procedures for parsing lines of input
530  */
531
532 int auth_initialize ( char *authfilename )
533 {
534     int n;
535     AuthList *head, *tail;
536     FILE *authfp;
537     Bool exists;
538
539     register_signals ();
540
541     bzero ((char *) hexvalues, sizeof hexvalues);
542     hexvalues['0'] = 0;
543     hexvalues['1'] = 1;
544     hexvalues['2'] = 2;
545     hexvalues['3'] = 3;
546     hexvalues['4'] = 4;
547     hexvalues['5'] = 5;
548     hexvalues['6'] = 6;
549     hexvalues['7'] = 7;
550     hexvalues['8'] = 8;
551     hexvalues['9'] = 9;
552     hexvalues['a'] = hexvalues['A'] = 0xa;
553     hexvalues['b'] = hexvalues['B'] = 0xb;
554     hexvalues['c'] = hexvalues['C'] = 0xc;
555     hexvalues['d'] = hexvalues['D'] = 0xd;
556     hexvalues['e'] = hexvalues['E'] = 0xe;
557     hexvalues['f'] = hexvalues['F'] = 0xf;
558
559     if (break_locks && verbose) {
560         printf ("Attempting to break locks on authority file %s\n",
561                 authfilename);
562     }
563
564     iceauth_filename = strdup(authfilename);
565     
566     if (ignore_locks) {
567         if (break_locks) IceUnlockAuthFile (authfilename);
568     } else {
569         n = IceLockAuthFile (authfilename, ICEAUTH_DEFAULT_RETRIES,
570                          ICEAUTH_DEFAULT_TIMEOUT, 
571                          (break_locks ? 0L : ICEAUTH_DEFAULT_DEADTIME));
572         if (n != IceAuthLockSuccess) {
573             char *reason = "unknown error";
574             switch (n) {
575               case IceAuthLockError:
576                 reason = "error";
577                 break;
578               case IceAuthLockTimeout:
579                 reason = "timeout";
580                 break;
581             }
582             fprintf (stderr, "%s:  %s in locking authority file %s\n",
583                      ProgramName, reason, authfilename);
584             return -1;
585         }
586     }
587
588     /* these checks can only be done reliably after the file is locked */
589     exists = (access (authfilename, F_OK) == 0);
590     if (exists && access (authfilename, W_OK) != 0) {
591         fprintf (stderr,
592          "%s:  %s not writable, changes will be ignored\n",
593                  ProgramName, authfilename);
594         iceauth_allowed = False;
595     }
596
597     original_umask = umask (0077);      /* disallow non-owner access */
598
599     authfp = fopen (authfilename, "rb");
600     if (!authfp) {
601         int olderrno = errno;
602
603                                         /* if file there then error */
604         if (access (authfilename, F_OK) == 0) {  /* then file does exist! */
605             errno = olderrno;
606             return -1;
607         }                               /* else ignore it */
608         fprintf (stderr, 
609                  "%s:  creating new authority file %s\n",
610                  ProgramName, authfilename);
611     } else {
612         iceauth_existed = True;
613         n = read_auth_entries (authfp, &head, &tail);
614         (void) fclose (authfp);
615         if (n < 0) {
616             fprintf (stderr,
617                      "%s:  unable to read auth entries from file \"%s\"\n",
618                      ProgramName, authfilename);
619             return -1;
620         }
621         iceauth_head = head;
622     }
623
624     iceauth_modified = False;
625
626     if (verbose) {
627         printf ("%s authority file %s\n", 
628                 ignore_locks ? "Ignoring locks on" : "Using", authfilename);
629     }
630     return 0;
631 }
632
633 static int write_auth_file (char *tmp_nam, size_t tmp_nam_len)
634 {
635     FILE *fp;
636     AuthList *list;
637
638     if ((strlen(iceauth_filename) + 3) > tmp_nam_len) {
639         strncpy(tmp_nam, "filename too long", tmp_nam_len);
640         tmp_nam[tmp_nam_len - 1] = '\0';
641         return -1;
642     }
643     
644     strcpy (tmp_nam, iceauth_filename);
645     strcat (tmp_nam, "-n");             /* for new */
646     (void) unlink (tmp_nam);
647     fp = fopen (tmp_nam, "wb");         /* umask is still set to 0077 */
648     if (!fp) {
649         fprintf (stderr, "%s:  unable to open tmp file \"%s\"\n",
650                  ProgramName, tmp_nam);
651         return -1;
652     } 
653
654     for (list = iceauth_head; list; list = list->next)
655         IceWriteAuthFileEntry (fp, list->auth);
656
657     (void) fclose (fp);
658     return 0;
659 }
660
661 int auth_finalize (void)
662 {
663     char temp_name[1024];                       /* large filename size */
664
665     if (iceauth_modified) {
666         if (dieing) {
667             if (verbose) {
668                 /*
669                  * called from a signal handler -- printf is *not* reentrant; also
670                  * fileno() might not be reentrant, avoid it if possible, and use
671                  * stderr instead of stdout
672                  */
673 #ifdef STDERR_FILENO
674                 WRITES(STDERR_FILENO, "\nAborting changes to authority file ");
675                 WRITES(STDERR_FILENO, iceauth_filename);
676                 WRITES(STDERR_FILENO, "\n");
677 #else
678                 WRITES(fileno(stderr), "\nAborting changes to authority file ");
679                 WRITES(fileno(stderr), iceauth_filename);
680                 WRITES(fileno(stderr), "\n");
681 #endif
682             }
683         } else if (!iceauth_allowed) {
684             fprintf (stderr, 
685                      "%s:  %s not writable, changes ignored\n",
686                      ProgramName, iceauth_filename);
687         } else {
688             if (verbose) {
689                 printf ("%s authority file %s\n", 
690                         ignore_locks ? "Ignoring locks and writing" :
691                         "Writing", iceauth_filename);
692             }
693             temp_name[0] = '\0';
694             if (write_auth_file (temp_name, sizeof(temp_name)) == -1) {
695                 fprintf (stderr,
696                          "%s:  unable to write authority file %s\n",
697                          ProgramName, temp_name);
698             } else {
699                 (void) unlink (iceauth_filename);
700 #if defined(WIN32) || defined(__UNIXOS2__)
701                 if (rename(temp_name, iceauth_filename) == -1)
702 #else
703                 /* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */
704                 if (link (temp_name, iceauth_filename) == -1 && rename(temp_name, iceauth_filename) == -1)
705 #endif
706                 {
707                     fprintf (stderr,
708                      "%s:  unable to link authority file %s, use %s\n",
709                              ProgramName, iceauth_filename, temp_name);
710                 } else {
711                     (void) unlink (temp_name);
712                 }
713             }
714         }
715     }
716
717     if (!ignore_locks && (iceauth_filename != NULL)) {
718         IceUnlockAuthFile (iceauth_filename);
719     }
720     (void) umask (original_umask);
721     return 0;
722 }
723
724 int process_command (
725     const char *inputfilename,
726     int lineno,
727     int argc,
728     char **argv)
729 {
730     int status;
731
732     if (argc < 1 || !argv || !argv[0]) return 1;
733
734     if (dispatch_command (inputfilename, lineno, argc, argv,
735                           command_table, &status))
736       return status;
737
738     prefix (inputfilename, lineno);
739     fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
740     return 1;
741 }
742
743
744 /*
745  * utility routines
746  */
747
748 static void fprintfhex (
749     register FILE *fp,
750     unsigned int len,
751     const char *cp)
752 {
753     const unsigned char *ucp = (const unsigned char *) cp;
754
755     for (; len > 0; len--, ucp++) {
756         register const char *s = hex_table[*ucp];
757         putc (s[0], fp);
758         putc (s[1], fp);
759     }
760     return;
761 }
762
763 /* ARGSUSED */
764 static int dump_entry (
765     const char *inputfilename,
766     int lineno,
767     IceAuthFileEntry *auth,
768     char *data)
769 {
770     struct _list_data *ld = (struct _list_data *) data;
771     FILE *fp = ld->fp;
772
773     fprintf (fp, "%s", auth->protocol_name);
774     putc (' ', fp);
775     if (auth->protocol_data_length > 0)
776         fprintfhex (fp, auth->protocol_data_length, auth->protocol_data);
777     else
778         fprintf (fp, "\"\"");
779     putc (' ', fp);
780     fprintf (fp, "%s", auth->network_id);
781     putc (' ', fp);
782     fprintf (fp, "%s", auth->auth_name);
783     putc (' ', fp);
784
785     if (auth->auth_data_length == 0)
786         fprintf (fp, "\"\"");
787     else if (!strcmp(auth->auth_name, SECURERPC) ||
788         !strcmp(auth->auth_name, K5AUTH))
789         fwrite (auth->auth_data, sizeof (char), auth->auth_data_length, fp);
790     else
791         fprintfhex (fp, auth->auth_data_length, auth->auth_data);
792     putc ('\n', fp);
793
794     return 0;
795 }
796
797 static int extract_entry (
798     const char *inputfilename,
799     int lineno,
800     IceAuthFileEntry *auth,
801     char *data)
802 {
803     struct _extract_data *ed = (struct _extract_data *) data;
804
805     if (!ed->fp) {
806         ed->fp = open_file (&ed->filename, "wb",
807                             &ed->used_stdout,
808                             inputfilename, lineno, ed->cmd);
809         if (!ed->fp) {
810             prefix (inputfilename, lineno);
811             fprintf (stderr,
812                      "unable to open extraction file \"%s\"\n",
813                      ed->filename);
814             return -1;
815         }
816     }
817     IceWriteAuthFileEntry (ed->fp, auth);
818     ed->nwritten++;
819
820     return 0;
821 }
822
823
824 static int match_auth (
825     register IceAuthFileEntry *a,
826     register IceAuthFileEntry *b,
827     int *authDataSame)
828 {
829     int match = strcmp (a->protocol_name, b->protocol_name) == 0 &&
830             strcmp (a->network_id, b->network_id) == 0 &&
831             strcmp (a->auth_name, b->auth_name) == 0;
832
833     if (match)
834     {
835         *authDataSame = (a->auth_data_length == b->auth_data_length &&
836             binaryEqual (a->auth_data, b->auth_data, a->auth_data_length));
837     }
838     else
839         *authDataSame = 0;
840
841     return (match);
842 }
843
844
845 static int merge_entries (
846     AuthList **firstp, AuthList *second,
847     int *nnewp, int *nreplp, int *ndupp)
848 {
849     AuthList *a, *b, *first, *tail;
850     int n = 0, nnew = 0, nrepl = 0, ndup = 0;
851
852     if (!second) return 0;
853
854     if (!*firstp) {                     /* if nothing to merge into */
855         *firstp = second;
856         for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
857         *nnewp = n;
858         *nreplp = 0;
859         *ndupp = 0;
860         return n;
861     }
862
863     first = *firstp;
864     /*
865      * find end of first list and stick second list on it
866      */
867     for (tail = first; tail->next; tail = tail->next) ;
868     tail->next = second;
869
870     /*
871      * run down list freeing duplicate entries; if an entry is okay, then
872      * bump the tail up to include it, otherwise, cut the entry out of
873      * the chain.
874      */
875     for (b = second; b; ) {
876         AuthList *next = b->next;       /* in case we free it */
877         int duplicate;
878
879         duplicate = 0;
880         a = first;
881         for (;;) {
882             int authDataSame;
883             if (match_auth (a->auth, b->auth, &authDataSame)) {
884                 if (authDataSame)
885                 {
886                     /* found a complete duplicate, ignore */
887                     duplicate = 1;
888                     break;
889                 }
890                 else
891                 {
892                     /* found a duplicate, but auth data differs */
893
894                     AuthList tmp;               /* swap it in for old one */
895                     tmp = *a;
896                     *a = *b;
897                     *b = tmp;
898                     a->next = b->next;
899                     IceFreeAuthFileEntry (b->auth);
900                     free ((char *) b);
901                     b = NULL;
902                     tail->next = next;
903                     nrepl++;
904                     nnew--;
905                     break;
906                 }
907             }
908             if (a == tail) break;       /* if have looked at left side */
909             a = a->next;
910         }
911         if (!duplicate && b) {          /* if we didn't remove it */
912             tail = b;                   /* bump end of first list */
913         }
914         b = next;
915
916         if (duplicate)
917             ndup++;
918         else
919         {
920             n++;
921             nnew++;
922         }
923     }
924
925     *nnewp = nnew;
926     *nreplp = nrepl;
927     *ndupp = ndup;
928     return n;
929
930 }
931
932
933 static int search_and_do (
934     const char *inputfilename,
935     int lineno,
936     int start,
937     int argc,
938     char *argv[],
939     DoFunc do_func,
940     char *data)
941 {
942     int i;
943     int status = 0;
944     int errors = 0;
945     AuthList *l, *next;
946     char *protoname, *protodata, *netid, *authname;
947
948     for (l = iceauth_head; l; l = next)
949     {
950         next = l->next;
951
952         protoname = protodata = netid = authname = NULL;
953
954         for (i = start; i < argc; i++)
955         {
956             if (!strncmp ("protoname=", argv[i], 10))
957                 protoname = argv[i] + 10;
958             else if (!strncmp ("protodata=", argv[i], 10))
959                 protodata = argv[i] + 10;
960             else if (!strncmp ("netid=", argv[i], 6))
961                 netid = argv[i] + 6;
962             else if (!strncmp ("authname=", argv[i], 9))
963                 authname = argv[i] + 9;
964         }
965
966         status = 0;
967
968         if (protoname || protodata || netid || authname)
969         {
970             if (protoname && strcmp (protoname, l->auth->protocol_name))
971                 continue;
972
973             if (protodata && !binaryEqual (protodata,
974                 l->auth->protocol_data, l->auth->protocol_data_length))
975                 continue;
976
977             if (netid && strcmp (netid, l->auth->network_id))
978                 continue;
979
980             if (authname && strcmp (authname, l->auth->auth_name))
981                 continue;
982
983             status = (*do_func) (inputfilename, lineno, l->auth, data);
984
985             if (status < 0)
986                 break;
987         }
988     }
989
990     if (status < 0)
991         errors -= status;               /* since status is negative */
992
993     return (errors);
994 }
995
996
997 /* ARGSUSED */
998 static int remove_entry (
999     const char *inputfilename,
1000     int lineno,
1001     IceAuthFileEntry *auth,
1002     char *data)
1003 {
1004     int *nremovedp = (int *) data;
1005     AuthList **listp = &iceauth_head;
1006     AuthList *list;
1007
1008     /*
1009      * unlink the auth we were asked to
1010      */
1011     while ((list = *listp)->auth != auth)
1012         listp = &list->next;
1013     *listp = list->next;
1014     IceFreeAuthFileEntry (list->auth);                    /* free the auth */
1015     free (list);                                    /* free the link */
1016     iceauth_modified = True;
1017     (*nremovedp)++;
1018     return 1;
1019 }
1020
1021 /*
1022  * action routines
1023  */
1024
1025 /*
1026  * help
1027  */
1028 int print_help (
1029     FILE *fp,
1030     const char *cmd)
1031 {
1032     const CommandTable *ct;
1033     int n = 0;
1034
1035     fprintf (fp, "\n");
1036     if (!cmd) {                         /* if no cmd, print all help */
1037         for (ct = command_table; ct->name; ct++) {
1038             fprintf (fp, "%s\n\n", ct->helptext);
1039             n++;
1040         }
1041     } else {
1042         int len = strlen (cmd);
1043         for (ct = command_table; ct->name; ct++) {
1044             if (strncmp (cmd, ct->name, len) == 0) {
1045                 fprintf (fp, "%s\n\n", ct->helptext);
1046                 n++;
1047             }
1048         }
1049     }
1050         
1051     return n;
1052 }
1053
1054 static int do_help (
1055     const char *inputfilename,
1056     int lineno,
1057     int argc,
1058     char **argv)
1059 {
1060     char *cmd = (argc > 1 ? argv[1] : NULL);
1061     int n;
1062
1063     n = print_help (stdout, cmd);
1064
1065     if (n < 0 || (n == 0 && !cmd)) {
1066         prefix (inputfilename, lineno);
1067         fprintf (stderr, "internal error with help");
1068         if (cmd) {
1069             fprintf (stderr, " on command \"%s\"", cmd);
1070         }
1071         fprintf (stderr, "\n");
1072         return 1;
1073     }
1074
1075     if (n == 0) {
1076         prefix (inputfilename, lineno);
1077         /* already know that cmd is set in this case */
1078         fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd);
1079     }
1080
1081     return 0;
1082 }
1083
1084 /*
1085  * questionmark
1086  */
1087 /* ARGSUSED */
1088 static int do_questionmark (
1089     const char *inputfilename,
1090     int lineno,
1091     int argc,
1092     char **argv)
1093 {
1094     const CommandTable *ct;
1095     int i;
1096 #define WIDEST_COLUMN 72
1097     int col = WIDEST_COLUMN;
1098
1099     printf ("Commands:\n");
1100     for (ct = command_table; ct->name; ct++) {
1101         if ((col + ct->maxlen) > WIDEST_COLUMN) {
1102             if (ct != command_table) {
1103                 putc ('\n', stdout);
1104             }
1105             fputs ("        ", stdout);
1106             col = 8;                    /* length of string above */
1107         }
1108         fputs (ct->name, stdout);
1109         col += ct->maxlen;
1110         for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
1111             putc (' ', stdout);
1112             col++;
1113         }
1114     }
1115     if (col != 0) {
1116         putc ('\n', stdout);
1117     }
1118
1119     /* allow bad lines since this is help */
1120     return 0;
1121 }
1122
1123 /*
1124  * list [displayname ...]
1125  */
1126 static int do_list (
1127     const char *inputfilename,
1128     int lineno,
1129     int argc,
1130     char **argv)
1131 {
1132     struct _list_data ld;
1133
1134     ld.fp = stdout;
1135
1136     if (argc == 1) {
1137         register AuthList *l;
1138
1139         if (iceauth_head) {
1140             for (l = iceauth_head; l; l = l->next) {
1141                 dump_entry (inputfilename, lineno, l->auth, (char *) &ld);
1142             }
1143         }
1144         return 0;
1145     }
1146     else
1147     {
1148         return (search_and_do (inputfilename, lineno, 1, argc, argv,
1149             dump_entry, (char *) &ld));
1150     }
1151 }
1152
1153 /*
1154  * merge filename [filename ...]
1155  */
1156 static int do_merge (
1157     const char *inputfilename,
1158     int lineno,
1159     int argc,
1160     char **argv)
1161 {
1162     int i;
1163     int errors = 0;
1164     AuthList *head, *tail, *listhead, *listtail;
1165     int nentries, nnew, nrepl, ndup;
1166
1167     if (argc < 2) {
1168         prefix (inputfilename, lineno);
1169         badcommandline (argv[0]);
1170         return 1;
1171     }
1172
1173     listhead = listtail = NULL;
1174
1175     for (i = 1; i < argc; i++) {
1176         char *filename = argv[i];
1177         FILE *fp;
1178         Bool used_stdin = False;
1179
1180         fp = open_file (&filename, "rb",
1181                         &used_stdin, inputfilename, lineno,
1182                         argv[0]);
1183         if (!fp) {
1184             errors++;
1185             continue;
1186         }
1187
1188         head = tail = NULL;
1189         nentries = read_auth_entries (fp, &head, &tail);
1190         if (nentries == 0) {
1191             prefix (inputfilename, lineno);
1192             fprintf (stderr, "unable to read any entries from file \"%s\"\n",
1193                      filename);
1194             errors++;
1195         } else {                        /* link it in */
1196             add_to_list (listhead, listtail, head);
1197         }
1198
1199         if (!used_stdin) (void) fclose (fp);
1200     }
1201
1202     /*
1203      * if we have new entries, merge them in (freeing any duplicates)
1204      */
1205     if (listhead) {
1206         nentries = merge_entries (&iceauth_head, listhead,
1207             &nnew, &nrepl, &ndup);
1208         if (verbose) 
1209           printf ("%d entries read in:  %d new, %d replacement%s\n", 
1210                   nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
1211         if (nentries > 0) iceauth_modified = True;
1212     }
1213
1214     return 0;
1215 }
1216
1217 /*
1218  * extract filename displayname [displayname ...]
1219  */
1220 static int do_extract (
1221     const char *inputfilename,
1222     int lineno,
1223     int argc,
1224     char **argv)
1225 {
1226     int errors;
1227     struct _extract_data ed;
1228
1229     if (argc < 3) {
1230         prefix (inputfilename, lineno);
1231         badcommandline (argv[0]);
1232         return 1;
1233     }
1234
1235     ed.fp = NULL;
1236     ed.filename = argv[1];
1237     ed.nwritten = 0;
1238     ed.cmd = argv[0];
1239
1240     errors = search_and_do (inputfilename, lineno, 2, argc, argv, 
1241         extract_entry, (char *) &ed);
1242
1243     if (!ed.fp) {
1244         fprintf (stderr, 
1245                  "No matches found, authority file \"%s\" not written\n",
1246                  ed.filename);
1247     } else {
1248         if (verbose) {
1249             printf ("%d entries written to \"%s\"\n", 
1250                     ed.nwritten, ed.filename);
1251         }
1252         if (!ed.used_stdout) {
1253             (void) fclose (ed.fp);
1254         }
1255     }
1256
1257     return errors;
1258 }
1259
1260
1261 /*
1262  * add protoname protodata netid authname authdata
1263  */
1264 static int do_add (
1265     const char *inputfilename,
1266     int lineno,
1267     int argc,
1268     char **argv)
1269
1270     int n, nnew, nrepl, ndup;
1271     char *protoname;
1272     char *protodata_hex;
1273     char *protodata = NULL; /* not required */
1274     char *netid;
1275     char *authname;
1276     char *authdata_hex;
1277     char *authdata = NULL;
1278     int protodata_len, authdata_len;
1279     IceAuthFileEntry *auth = NULL;
1280     AuthList *list;
1281     int status = 0;
1282
1283     if (argc != 6 || !argv[1] || !argv[2] ||
1284         !argv[3] || !argv[4] || !argv[5])
1285     {
1286         prefix (inputfilename, lineno);
1287         badcommandline (argv[0]);
1288         return 1;
1289     }
1290
1291     protoname = argv[1];
1292     protodata_hex = argv[2];
1293     netid = argv[3];
1294     authname = argv[4];
1295     authdata_hex = argv[5];
1296
1297     protodata_len = strlen (protodata_hex);
1298     if (protodata_len > 0)
1299     {
1300         if (protodata_hex[0] == '"' && protodata_hex[protodata_len - 1] == '"')
1301         {
1302             protodata = malloc (protodata_len - 1);
1303             if (protodata)
1304             {
1305                 strncpy (protodata, protodata_hex + 1, protodata_len - 2);
1306                 protodata_len -= 2;
1307             }
1308             else
1309                 goto add_bad_malloc;
1310         }
1311         else
1312         {
1313             protodata_len = cvthexkey (protodata_hex, &protodata);
1314             if (protodata_len < 0)
1315             {
1316                 prefix (inputfilename, lineno);
1317                 fprintf (stderr,
1318                "protodata_hex contains odd number of or non-hex characters\n");
1319                 return (1);
1320             }
1321         }
1322     }
1323
1324     authdata_len = strlen (authdata_hex);
1325     if (authdata_hex[0] == '"' && authdata_hex[authdata_len - 1] == '"')
1326     {
1327         authdata = malloc (authdata_len - 1);
1328         if (authdata)
1329         {
1330             strncpy (authdata, authdata_hex + 1, authdata_len - 2);
1331             authdata_len -= 2;
1332         }
1333         else
1334             goto add_bad_malloc;
1335     }
1336     else if (!strcmp (protoname, SECURERPC) || !strcmp (protoname, K5AUTH))
1337     {
1338         authdata = malloc (authdata_len + 1);
1339         if (authdata)
1340             strcpy (authdata, authdata_hex);
1341         else
1342             goto add_bad_malloc;
1343     }
1344     else
1345     {
1346         authdata_len = cvthexkey (authdata_hex, &authdata);
1347         if (authdata_len < 0)
1348         {
1349             prefix (inputfilename, lineno);
1350             fprintf (stderr,
1351                "authdata_hex contains odd number of or non-hex characters\n");
1352             free (protodata);
1353             return (1);
1354         }
1355     }
1356
1357     auth = (IceAuthFileEntry *) malloc (sizeof (IceAuthFileEntry));
1358
1359     if (!auth)
1360         goto add_bad_malloc;
1361
1362     auth->protocol_name = copystring (protoname);
1363     auth->protocol_data_length = protodata_len;
1364     auth->protocol_data = protodata;
1365     auth->network_id = copystring (netid);
1366     auth->auth_name = copystring (authname);
1367     auth->auth_data_length = authdata_len;
1368     auth->auth_data = authdata;
1369
1370     if (!auth->protocol_name ||
1371         (!auth->protocol_data && auth->protocol_data_length > 0) ||
1372         !auth->network_id || !auth->auth_name ||
1373         (!auth->auth_data && auth->auth_data_length > 0))
1374     {
1375         goto add_bad_malloc;
1376     }
1377
1378     list = (AuthList *) malloc (sizeof (AuthList));
1379
1380     if (!list)
1381         goto add_bad_malloc;
1382
1383     list->next = NULL;
1384     list->auth = auth;
1385
1386     /*
1387      * merge it in; note that merge will deal with allocation
1388      */
1389
1390     n = merge_entries (&iceauth_head, list, &nnew, &nrepl, &ndup);
1391
1392     if (n > 0)
1393         iceauth_modified = True;
1394     else
1395     {
1396         prefix (inputfilename, lineno);
1397         if (ndup > 0)
1398         {
1399             status = 0;
1400             fprintf (stderr, "no records added - all duplicate\n");
1401         }
1402         else
1403         {
1404             status = 1;
1405             fprintf (stderr, "unable to merge in added record\n");
1406         }
1407         goto cant_add;
1408     }
1409
1410     return 0;
1411
1412
1413 add_bad_malloc:
1414
1415     status = 1;
1416     prefix (inputfilename, lineno);
1417     fprintf (stderr, "unable to allocate memory to add an entry\n");
1418
1419 cant_add:
1420
1421     if (protodata)
1422         free (protodata);
1423     if (authdata)
1424         free (authdata);
1425     if (auth)
1426     {
1427         if (auth->protocol_name)
1428             free (auth->protocol_name);
1429         /* auth->protocol_data already freed,
1430            since it's the same as protodata */
1431         if (auth->network_id)
1432             free (auth->network_id);
1433         if (auth->auth_name)
1434             free (auth->auth_name);
1435         /* auth->auth_data already freed,
1436            since it's the same as authdata */
1437         free ((char *) auth);
1438     }
1439
1440     return status;
1441 }
1442
1443 /*
1444  * remove displayname
1445  */
1446 static int do_remove (
1447     const char *inputfilename,
1448     int lineno,
1449     int argc,
1450     char **argv)
1451 {
1452     int nremoved = 0;
1453     int errors;
1454
1455     if (argc < 2) {
1456         prefix (inputfilename, lineno);
1457         badcommandline (argv[0]);
1458         return 1;
1459     }
1460
1461     errors = search_and_do (inputfilename, lineno, 1, argc, argv,
1462         remove_entry, (char *) &nremoved);
1463     if (verbose) printf ("%d entries removed\n", nremoved);
1464     return errors;
1465 }
1466
1467 /*
1468  * info
1469  */
1470 static int do_info (
1471     const char *inputfilename,
1472     int lineno,
1473     int argc,
1474     char **argv)
1475 {
1476     int n;
1477     AuthList *l;
1478
1479     if (argc != 1) {
1480         prefix (inputfilename, lineno);
1481         badcommandline (argv[0]);
1482         return 1;
1483     }
1484
1485     for (l = iceauth_head, n = 0; l; l = l->next, n++) ;
1486
1487     printf ("Authority file:       %s\n",
1488             iceauth_filename ? iceauth_filename : "(none)");
1489     printf ("File new:             %s\n", iceauth_existed ? No : Yes);
1490     printf ("File locked:          %s\n", ignore_locks ? No : Yes);
1491     printf ("Number of entries:    %d\n", n);
1492     printf ("Changes honored:      %s\n", iceauth_allowed ? Yes : No);
1493     printf ("Changes made:         %s\n", iceauth_modified ? Yes : No);
1494     printf ("Current input:        %s:%d\n", inputfilename, lineno);
1495     return 0;
1496 }
1497
1498
1499 /*
1500  * exit
1501  */
1502 static Bool alldone = False;
1503
1504 /* ARGSUSED */
1505 static int do_exit (
1506     const char *inputfilename,
1507     int lineno,
1508     int argc,
1509     char **argv)
1510 {
1511     /* allow bogus stuff */
1512     alldone = True;
1513     return 0;
1514 }
1515
1516 /*
1517  * quit
1518  */
1519 /* ARGSUSED */
1520 static int do_quit (
1521     const char *inputfilename,
1522     int lineno,
1523     int argc,
1524     char **argv)
1525 {
1526     /* allow bogus stuff */
1527     die (0);
1528     /* NOTREACHED */
1529     return -1;                          /* for picky compilers */
1530 }
1531
1532
1533 /*
1534  * source filename
1535  */
1536 static int do_source (
1537     const char *inputfilename,
1538     int lineno,
1539     int argc,
1540     char **argv)
1541 {
1542     char *script;
1543     char buf[BUFSIZ];
1544     FILE *fp;
1545     Bool used_stdin = False;
1546     int len;
1547     int errors = 0, status;
1548     int sublineno = 0;
1549     char **subargv;
1550     int subargc;
1551     Bool prompt = False;                /* only true if reading from tty */
1552
1553     if (argc != 2 || !argv[1]) {
1554         prefix (inputfilename, lineno);
1555         badcommandline (argv[0]);
1556         return 1;
1557     }
1558
1559     script = argv[1];
1560
1561     fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
1562     if (!fp) {
1563         return 1;
1564     }
1565
1566     if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
1567
1568     while (!alldone) {
1569         buf[0] = '\0';
1570         if (prompt) {
1571             printf ("iceauth> ");
1572             fflush (stdout);
1573         }
1574         if (fgets (buf, sizeof buf, fp) == NULL) break;
1575         sublineno++;
1576         len = strlen (buf);
1577         if (len == 0 || buf[0] == '#') continue;
1578         if (buf[len-1] != '\n') {
1579             prefix (script, sublineno);
1580             fprintf (stderr, "line too long\n");
1581             errors++;
1582             break;
1583         }
1584         buf[--len] = '\0';              /* remove new line */
1585         subargv = split_into_words (buf, &subargc);
1586         if (subargv) {
1587             status = process_command (script, sublineno, subargc, subargv);
1588             free ((char *) subargv);
1589             errors += status;
1590         } else {
1591             prefix (script, sublineno);
1592             fprintf (stderr, "unable to break line into words\n");
1593             errors++;
1594         }
1595     }
1596
1597     if (!used_stdin) {
1598         (void) fclose (fp);
1599     }
1600     return errors;
1601 }