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