process.c revision 96402570
1/* 2 3Copyright 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29/* 30 * Author: Jim Fulton, MIT X Consortium 31 */ 32 33#ifdef HAVE_CONFIG_H 34#include "config.h" 35#endif 36 37#include "xauth.h" 38#include <ctype.h> 39#include <errno.h> 40#include <sys/stat.h> 41#include <sys/socket.h> 42 43#include <signal.h> 44#include <X11/X.h> /* for Family constants */ 45 46#include <X11/Xlib.h> 47#include <X11/extensions/security.h> 48 49#ifndef DEFAULT_PROTOCOL_ABBREV /* to make add command easier */ 50#define DEFAULT_PROTOCOL_ABBREV "." 51#endif 52#ifndef DEFAULT_PROTOCOL /* for protocol abbreviation */ 53#define DEFAULT_PROTOCOL "MIT-MAGIC-COOKIE-1" 54#endif 55 56#define SECURERPC "SUN-DES-1" 57#define K5AUTH "MIT-KERBEROS-5" 58 59#define XAUTH_DEFAULT_RETRIES 10 /* number of competitors we expect */ 60#define XAUTH_DEFAULT_TIMEOUT 2 /* in seconds, be quick */ 61#define XAUTH_DEFAULT_DEADTIME 600L /* 10 minutes in seconds */ 62 63typedef struct _AuthList { /* linked list of entries */ 64 struct _AuthList *next; 65 Xauth *auth; 66} AuthList; 67 68typedef int (*ProcessFunc)(const char *, int, int, const char**); 69 70#define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);} 71 72typedef struct _CommandTable { /* commands that are understood */ 73 const char *name; /* full name */ 74 int minlen; /* unique prefix */ 75 int maxlen; /* strlen(name) */ 76 ProcessFunc processfunc; /* handler */ 77 const char *helptext; /* what to print for help */ 78} CommandTable; 79 80struct _extract_data { /* for iterating */ 81 FILE *fp; /* input source */ 82 const char *filename; /* name of input */ 83 Bool used_stdout; /* whether or not need to close */ 84 Bool numeric; /* format in which to write */ 85 int nwritten; /* number of entries written */ 86 const char *cmd; /* for error messages */ 87}; 88 89struct _list_data { /* for iterating */ 90 FILE *fp; /* output file */ 91 Bool numeric; /* format in which to write */ 92}; 93 94 95/* 96 * private data 97 */ 98static const char *stdin_filename = "(stdin)"; /* for messages */ 99static const char *stdout_filename = "(stdout)"; /* for messages */ 100static const char *Yes = "yes"; /* for messages */ 101static const char *No = "no"; /* for messages */ 102 103static int do_help ( const char *inputfilename, int lineno, int argc, const char **argv ); 104static int do_questionmark ( const char *inputfilename, int lineno, int argc, const char **argv ); 105static int do_list ( const char *inputfilename, int lineno, int argc, const char **argv ); 106static int do_merge ( const char *inputfilename, int lineno, int argc, const char **argv ); 107static int do_extract ( const char *inputfilename, int lineno, int argc, const char **argv ); 108static int do_add ( const char *inputfilename, int lineno, int argc, const char **argv ); 109static int do_remove ( const char *inputfilename, int lineno, int argc, const char **argv ); 110static int do_info ( const char *inputfilename, int lineno, int argc, const char **argv ); 111static int do_exit ( const char *inputfilename, int lineno, int argc, const char **argv ); 112static int do_quit ( const char *inputfilename, int lineno, int argc, const char **argv ); 113static int do_source ( const char *inputfilename, int lineno, int argc, const char **argv ); 114static int do_generate ( const char *inputfilename, int lineno, int argc, const char **argv ); 115 116static CommandTable command_table[] = { /* table of known commands */ 117 { "add", 2, 3, do_add, 118 "add dpyname protoname hexkey add entry" }, 119 { "exit", 3, 4, do_exit, 120 "exit save changes and exit program" }, 121 { "extract", 3, 7, do_extract, 122 "extract filename dpyname... extract entries into file" }, 123 { "help", 1, 4, do_help, 124 "help [topic] print help" }, 125 { "info", 1, 4, do_info, 126 "info print information about entries" }, 127 { "list", 1, 4, do_list, 128 "list [dpyname...] list entries" }, 129 { "merge", 1, 5, do_merge, 130 "merge filename... merge entries from files" }, 131 { "nextract", 2, 8, do_extract, 132 "nextract filename dpyname... numerically extract entries" }, 133 { "nlist", 2, 5, do_list, 134 "nlist [dpyname...] numerically list entries" }, 135 { "nmerge", 2, 6, do_merge, 136 "nmerge filename... numerically merge entries" }, 137 { "quit", 1, 4, do_quit, 138 "quit abort changes and exit program" }, 139 { "remove", 1, 6, do_remove, 140 "remove dpyname... remove entries" }, 141 { "source", 1, 6, do_source, 142 "source filename read commands from file" }, 143 { "?", 1, 1, do_questionmark, 144 "? list available commands" }, 145 { "generate", 1, 8, do_generate, 146 "generate dpyname protoname [options] use server to generate entry\n" 147 " options are:\n" 148 " timeout n authorization expiration time in seconds\n" 149 " trusted clients using this entry are trusted\n" 150 " untrusted clients using this entry are untrusted\n" 151 " group n clients using this entry belong to application group n\n" 152 " data hexkey auth protocol specific data needed to generate the entry\n" 153 }, 154 { NULL, 0, 0, NULL, NULL }, 155}; 156 157#define COMMAND_NAMES_PADDED_WIDTH 10 /* wider than anything above */ 158 159 160static Bool okay_to_use_stdin = True; /* set to false after using */ 161 162static const char *hex_table[] = { /* for printing hex digits */ 163 "00", "01", "02", "03", "04", "05", "06", "07", 164 "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", 165 "10", "11", "12", "13", "14", "15", "16", "17", 166 "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", 167 "20", "21", "22", "23", "24", "25", "26", "27", 168 "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", 169 "30", "31", "32", "33", "34", "35", "36", "37", 170 "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", 171 "40", "41", "42", "43", "44", "45", "46", "47", 172 "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", 173 "50", "51", "52", "53", "54", "55", "56", "57", 174 "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", 175 "60", "61", "62", "63", "64", "65", "66", "67", 176 "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", 177 "70", "71", "72", "73", "74", "75", "76", "77", 178 "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", 179 "80", "81", "82", "83", "84", "85", "86", "87", 180 "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", 181 "90", "91", "92", "93", "94", "95", "96", "97", 182 "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", 183 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", 184 "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", 185 "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", 186 "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", 187 "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", 188 "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", 189 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 190 "d8", "d9", "da", "db", "dc", "dd", "de", "df", 191 "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", 192 "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", 193 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 194 "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff", 195}; 196 197static unsigned int hexvalues[256]; /* for parsing hex input */ 198 199static int original_umask = 0; /* for restoring */ 200 201 202/* 203 * private utility procedures 204 */ 205 206static void 207prefix(const char *fn, int n) 208{ 209 fprintf (stderr, "%s: %s:%d: ", ProgramName, fn, n); 210} 211 212static void 213baddisplayname(const char *dpy, const char *cmd) 214{ 215 fprintf (stderr, "bad display name \"%s\" in \"%s\" command\n", 216 dpy, cmd); 217} 218 219static void 220badcommandline(const char *cmd) 221{ 222 fprintf (stderr, "bad \"%s\" command line\n", cmd); 223} 224 225static char * 226skip_space(register char *s) 227{ 228 if (!s) return NULL; 229 230 for ( ; *s && isascii(*s) && isspace(*s); s++) 231 ; 232 return s; 233} 234 235 236static char * 237skip_nonspace(register char *s) 238{ 239 if (!s) return NULL; 240 241 /* put quoting into loop if need be */ 242 for ( ; *s && isascii(*s) && !isspace(*s); s++) 243 ; 244 return s; 245} 246 247static char ** 248split_into_words(char *src, int *argcp) /* argvify string */ 249{ 250 char *jword; 251 char savec; 252 char **argv; 253 int cur, total; 254 255 *argcp = 0; 256#define WORDSTOALLOC 4 /* most lines are short */ 257 argv = (char **) malloc (WORDSTOALLOC * sizeof (char *)); 258 if (!argv) return NULL; 259 cur = 0; 260 total = WORDSTOALLOC; 261 262 /* 263 * split the line up into separate, nul-terminated tokens; the last 264 * "token" will point to the empty string so that it can be bashed into 265 * a null pointer. 266 */ 267 268 do { 269 jword = skip_space (src); 270 src = skip_nonspace (jword); 271 savec = *src; 272 *src = '\0'; 273 if (cur == total) { 274 total += WORDSTOALLOC; 275 argv = (char **) realloc (argv, total * sizeof (char *)); 276 if (!argv) return NULL; 277 } 278 argv[cur++] = jword; 279 if (savec) src++; /* if not last on line advance */ 280 } while (jword != src); 281 282 argv[--cur] = NULL; /* smash empty token to end list */ 283 *argcp = cur; 284 return argv; 285} 286 287 288static FILE * 289open_file(const char **filenamep, 290 const char *mode, 291 Bool *usedstdp, 292 const char *srcfn, 293 int srcln, 294 const char *cmd) 295{ 296 FILE *fp; 297 298 if (strcmp (*filenamep, "-") == 0) { 299 *usedstdp = True; 300 /* select std descriptor to use */ 301 if (mode[0] == 'r') { 302 if (okay_to_use_stdin) { 303 okay_to_use_stdin = False; 304 *filenamep = stdin_filename; 305 return stdin; 306 } else { 307 prefix (srcfn, srcln); 308 fprintf (stderr, "%s: stdin already in use\n", cmd); 309 return NULL; 310 } 311 } else { 312 *filenamep = stdout_filename; 313 return stdout; /* always okay to use stdout */ 314 } 315 } 316 317 fp = fopen (*filenamep, mode); 318 if (!fp) { 319 prefix (srcfn, srcln); 320 fprintf (stderr, "%s: unable to open file %s\n", cmd, *filenamep); 321 } 322 return fp; 323} 324 325static int 326getinput(FILE *fp) 327{ 328 register int c; 329 330 while ((c = getc (fp)) != EOF && isascii(c) && c != '\n' && isspace(c)) ; 331 return c; 332} 333 334static int 335get_short(FILE *fp, unsigned short *sp) /* for reading numeric input */ 336{ 337 int c; 338 int i; 339 unsigned short us = 0; 340 341 /* 342 * read family: written with %04x 343 */ 344 for (i = 0; i < 4; i++) { 345 switch (c = getinput (fp)) { 346 case EOF: 347 case '\n': 348 return 0; 349 } 350 if (c < 0 || c > 255) return 0; 351 us = (us * 16) + hexvalues[c]; /* since msb */ 352 } 353 *sp = us; 354 return 1; 355} 356 357static int 358get_bytes(FILE *fp, unsigned int n, char **ptr) /* for reading numeric input */ 359{ 360 char *s; 361 register char *cp; 362 int c1, c2; 363 364 cp = s = malloc (n); 365 if (!cp) return 0; 366 367 while (n > 0) { 368 if ((c1 = getinput (fp)) == EOF || c1 == '\n' || 369 (c2 = getinput (fp)) == EOF || c2 == '\n') { 370 free (s); 371 return 0; 372 } 373 *cp = (char) ((hexvalues[c1] * 16) + hexvalues[c2]); 374 cp++; 375 n--; 376 } 377 378 *ptr = s; 379 return 1; 380} 381 382 383static Xauth * 384read_numeric(FILE *fp) 385{ 386 Xauth *auth; 387 388 auth = (Xauth *) malloc (sizeof (Xauth)); 389 if (!auth) goto bad; 390 auth->family = 0; 391 auth->address = NULL; 392 auth->address_length = 0; 393 auth->number = NULL; 394 auth->number_length = 0; 395 auth->name = NULL; 396 auth->name_length = 0; 397 auth->data = NULL; 398 auth->data_length = 0; 399 400 if (!get_short (fp, (unsigned short *) &auth->family)) 401 goto bad; 402 if (!get_short (fp, (unsigned short *) &auth->address_length)) 403 goto bad; 404 if (!get_bytes (fp, (unsigned int) auth->address_length, &auth->address)) 405 goto bad; 406 if (!get_short (fp, (unsigned short *) &auth->number_length)) 407 goto bad; 408 if (!get_bytes (fp, (unsigned int) auth->number_length, &auth->number)) 409 goto bad; 410 if (!get_short (fp, (unsigned short *) &auth->name_length)) 411 goto bad; 412 if (!get_bytes (fp, (unsigned int) auth->name_length, &auth->name)) 413 goto bad; 414 if (!get_short (fp, (unsigned short *) &auth->data_length)) 415 goto bad; 416 if (!get_bytes (fp, (unsigned int) auth->data_length, &auth->data)) 417 goto bad; 418 419 switch (getinput (fp)) { /* get end of line */ 420 case EOF: 421 case '\n': 422 return auth; 423 } 424 425 bad: 426 if (auth) XauDisposeAuth (auth); /* won't free null pointers */ 427 return NULL; 428} 429 430typedef Xauth *(*ReadFunc)(FILE *); 431 432static int 433read_auth_entries(FILE *fp, Bool numeric, AuthList **headp, AuthList **tailp) 434{ 435 ReadFunc readfunc = (numeric ? read_numeric : XauReadAuth); 436 Xauth *auth; 437 AuthList *head, *tail; 438 int n; 439 440 head = tail = NULL; 441 n = 0; 442 /* put all records into linked list */ 443 while ((auth = ((*readfunc) (fp))) != NULL) { 444 AuthList *l = (AuthList *) malloc (sizeof (AuthList)); 445 if (!l) { 446 fprintf (stderr, 447 "%s: unable to alloc entry reading auth file\n", 448 ProgramName); 449 exit (1); 450 } 451 l->next = NULL; 452 l->auth = auth; 453 if (tail) /* if not first time through append */ 454 tail->next = l; 455 else 456 head = l; /* first time through, so assign */ 457 tail = l; 458 n++; 459 } 460 *headp = head; 461 *tailp = tail; 462 return n; 463} 464 465static Bool 466get_displayname_auth(const char *displayname, AuthList **authl) 467{ 468 int family; 469 char *host = NULL, *rest = NULL; 470 int dpynum, scrnum; 471 char *cp; 472 int prelen = 0; 473 struct addrlist *addrlist_head, *addrlist_cur; 474 AuthList *authl_cur = NULL; 475 476 *authl = NULL; 477 /* 478 * check to see if the display name is of the form "host/unix:" 479 * which is how the list routine prints out local connections 480 */ 481 cp = strchr(displayname, '/'); 482 if (cp && strncmp (cp, "/unix:", 6) == 0) 483 prelen = (cp - displayname); 484 485 if (!parse_displayname (displayname + ((prelen > 0) ? prelen + 1 : 0), 486 &family, &host, &dpynum, &scrnum, &rest)) { 487 return False; 488 } 489 490 addrlist_head = get_address_info(family, displayname, prelen, host); 491 if (addrlist_head) { 492 char buf[40]; /* want to hold largest display num */ 493 unsigned short dpylen; 494 495 buf[0] = '\0'; 496 sprintf (buf, "%d", dpynum); 497 dpylen = strlen (buf); 498 if (dpylen > 0) { 499 for (addrlist_cur = addrlist_head; addrlist_cur != NULL; 500 addrlist_cur = addrlist_cur->next) { 501 AuthList *newal = malloc(sizeof(AuthList)); 502 Xauth *auth = malloc(sizeof(Xauth)); 503 504 if ((newal == NULL) || (auth == NULL)) { 505 if (newal != NULL) free(newal); 506 if (auth != NULL) free(auth); 507 break; 508 } 509 510 if (authl_cur == NULL) { 511 *authl = authl_cur = newal; 512 } else { 513 authl_cur->next = newal; 514 authl_cur = newal; 515 } 516 517 newal->next = NULL; 518 newal->auth = auth; 519 520 auth->family = addrlist_cur->family; 521 auth->address = addrlist_cur->address; 522 auth->address_length = addrlist_cur->len; 523 auth->number = copystring(buf, dpylen); 524 auth->number_length = dpylen; 525 auth->name = NULL; 526 auth->name_length = 0; 527 auth->data = NULL; 528 auth->data_length = 0; 529 } 530 } 531 } 532 533 if (host) free (host); 534 if (rest) free (rest); 535 536 if (*authl != NULL) { 537 return True; 538 } else { 539 return False; 540 } 541} 542 543static int 544cvthexkey(const char *hexstr, char **ptrp) /* turn hex key string into octets */ 545{ 546 int i; 547 int len = 0; 548 char *retval; 549 const char *s; 550 unsigned char *us; 551 char c; 552 char savec = '\0'; 553 554 /* count */ 555 for (s = hexstr; *s; s++) { 556 if (!isascii(*s)) return -1; 557 if (isspace(*s)) continue; 558 if (!isxdigit(*s)) return -1; 559 len++; 560 } 561 562 /* if 0 or odd, then there was an error */ 563 if (len == 0 || (len & 1) == 1) return -1; 564 565 566 /* now we know that the input is good */ 567 len >>= 1; 568 retval = malloc (len); 569 if (!retval) { 570 fprintf (stderr, "%s: unable to allocate %d bytes for hexkey\n", 571 ProgramName, len); 572 return -1; 573 } 574 575 for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) { 576 c = *hexstr; 577 if (isspace(c)) continue; /* already know it is ascii */ 578 if (isupper(c)) 579 c = tolower(c); 580 if (savec) { 581#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10))) 582 *us = (unsigned char)((atoh(savec) << 4) + atoh(c)); 583#undef atoh 584 savec = 0; /* ready for next character */ 585 us++; 586 i--; 587 } else { 588 savec = c; 589 } 590 } 591 *ptrp = retval; 592 return len; 593} 594 595static int 596dispatch_command(const char *inputfilename, 597 int lineno, 598 int argc, 599 const char **argv, 600 CommandTable *tab, 601 int *statusp) 602{ 603 CommandTable *ct; 604 const char *cmd; 605 int n; 606 /* scan table for command */ 607 cmd = argv[0]; 608 n = strlen (cmd); 609 for (ct = tab; ct->name; ct++) { 610 /* look for unique prefix */ 611 if (n >= ct->minlen && n <= ct->maxlen && 612 strncmp (cmd, ct->name, n) == 0) { 613 *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv); 614 return 1; 615 } 616 } 617 618 *statusp = 1; 619 return 0; 620} 621 622 623static AuthList *xauth_head = NULL; /* list of auth entries */ 624static Bool xauth_existed = False; /* if was present at initialize */ 625static Bool xauth_modified = False; /* if added, removed, or merged */ 626static Bool xauth_allowed = True; /* if allowed to write auth file */ 627static Bool xauth_locked = False; /* if has been locked */ 628static const char *xauth_filename = NULL; 629static volatile Bool dieing = False; 630 631 632/* poor man's puts(), for under signal handlers */ 633#define WRITES(fd, S) (void)write((fd), (S), strlen((S))) 634 635/* ARGSUSED */ 636static RETSIGTYPE 637die(int sig) 638{ 639 dieing = True; 640 _exit (auth_finalize ()); 641 /* NOTREACHED */ 642#ifdef SIGNALRETURNSINT 643 return -1; /* for picky compilers */ 644#endif 645} 646 647static RETSIGTYPE 648catchsig(int sig) 649{ 650#ifdef SYSV 651 if (sig > 0) signal (sig, die); /* re-establish signal handler */ 652#endif 653 /* 654 * fileno() might not be reentrant, avoid it if possible, and use 655 * stderr instead of stdout 656 */ 657#ifdef STDERR_FILENO 658 if (verbose && xauth_modified) WRITES(STDERR_FILENO, "\r\n"); 659#else 660 if (verbose && xauth_modified) WRITES(fileno(stderr), "\r\n"); 661#endif 662 die (sig); 663 /* NOTREACHED */ 664#ifdef SIGNALRETURNSINT 665 return -1; /* for picky compilers */ 666#endif 667} 668 669static void 670register_signals(void) 671{ 672 signal (SIGINT, catchsig); 673 signal (SIGTERM, catchsig); 674#ifdef SIGHUP 675 signal (SIGHUP, catchsig); 676#endif 677#ifdef SIGPIPE 678 signal (SIGPIPE, catchsig); 679#endif 680 return; 681} 682 683 684/* 685 * public procedures for parsing lines of input 686 */ 687 688int 689auth_initialize(const char *authfilename) 690{ 691 int n; 692 AuthList *head, *tail; 693 FILE *authfp; 694 Bool exists; 695 696 xauth_filename = authfilename; /* used in cleanup, prevent race with 697 signals */ 698 register_signals (); 699 700 bzero ((char *) hexvalues, sizeof hexvalues); 701 hexvalues['0'] = 0; 702 hexvalues['1'] = 1; 703 hexvalues['2'] = 2; 704 hexvalues['3'] = 3; 705 hexvalues['4'] = 4; 706 hexvalues['5'] = 5; 707 hexvalues['6'] = 6; 708 hexvalues['7'] = 7; 709 hexvalues['8'] = 8; 710 hexvalues['9'] = 9; 711 hexvalues['a'] = hexvalues['A'] = 0xa; 712 hexvalues['b'] = hexvalues['B'] = 0xb; 713 hexvalues['c'] = hexvalues['C'] = 0xc; 714 hexvalues['d'] = hexvalues['D'] = 0xd; 715 hexvalues['e'] = hexvalues['E'] = 0xe; 716 hexvalues['f'] = hexvalues['F'] = 0xf; 717 718 if (break_locks && verbose) { 719 printf ("Attempting to break locks on authority file %s\n", 720 authfilename); 721 } 722 723 if (ignore_locks) { 724 if (break_locks) XauUnlockAuth (authfilename); 725 } else { 726 n = XauLockAuth (authfilename, XAUTH_DEFAULT_RETRIES, 727 XAUTH_DEFAULT_TIMEOUT, 728 (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME)); 729 if (n != LOCK_SUCCESS) { 730 const char *reason = "unknown error"; 731 switch (n) { 732 case LOCK_ERROR: 733 reason = "error"; 734 break; 735 case LOCK_TIMEOUT: 736 reason = "timeout"; 737 break; 738 } 739 fprintf (stderr, "%s: %s in locking authority file %s\n", 740 ProgramName, reason, authfilename); 741 return -1; 742 } else 743 xauth_locked = True; 744 } 745 746 /* these checks can only be done reliably after the file is locked */ 747 exists = (access (authfilename, F_OK) == 0); 748 if (exists && access (authfilename, W_OK) != 0) { 749 fprintf (stderr, 750 "%s: %s not writable, changes will be ignored\n", 751 ProgramName, authfilename); 752 xauth_allowed = False; 753 } 754 755 original_umask = umask (0077); /* disallow non-owner access */ 756 757 authfp = fopen (authfilename, "rb"); 758 if (!authfp) { 759 int olderrno = errno; 760 761 /* if file there then error */ 762 if (access (authfilename, F_OK) == 0) { /* then file does exist! */ 763 errno = olderrno; 764 return -1; 765 } /* else ignore it */ 766 fprintf (stderr, 767 "%s: file %s does not exist\n", 768 ProgramName, authfilename); 769 } else { 770 xauth_existed = True; 771 n = read_auth_entries (authfp, False, &head, &tail); 772 (void) fclose (authfp); 773 if (n < 0) { 774 fprintf (stderr, 775 "%s: unable to read auth entries from file \"%s\"\n", 776 ProgramName, authfilename); 777 return -1; 778 } 779 xauth_head = head; 780 } 781 782 xauth_filename = strdup(authfilename); 783 if (!xauth_filename) { 784 fprintf(stderr,"cannot allocate memory\n"); 785 return -1; 786 } 787 788 xauth_modified = False; 789 790 if (verbose) { 791 printf ("%s authority file %s\n", 792 ignore_locks ? "Ignoring locks on" : "Using", authfilename); 793 } 794 return 0; 795} 796 797static int 798write_auth_file(char *tmp_nam) 799{ 800 FILE *fp = NULL; 801 int fd; 802 AuthList *list; 803 804 /* 805 * xdm and auth spec assumes auth file is 12 or fewer characters 806 */ 807 strcpy (tmp_nam, xauth_filename); 808 strcat (tmp_nam, "-n"); /* for new */ 809 (void) unlink (tmp_nam); 810 /* CPhipps 2000/02/12 - fix file unlink/fopen race */ 811 fd = open(tmp_nam, O_WRONLY | O_CREAT | O_EXCL, 0600); 812 if (fd != -1) fp = fdopen (fd, "wb"); 813 if (!fp) { 814 if (fd != -1) close(fd); 815 fprintf (stderr, "%s: unable to open tmp file \"%s\"\n", 816 ProgramName, tmp_nam); 817 return -1; 818 } 819 820 /* 821 * Write MIT-MAGIC-COOKIE-1 first, because R4 Xlib knows 822 * only that and uses the first authorization it finds. 823 */ 824 for (list = xauth_head; list; list = list->next) { 825 if (list->auth->name_length == 18 826 && strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) == 0) { 827 if (!XauWriteAuth(fp, list->auth)) { 828 (void) fclose(fp); 829 return -1; 830 } 831 } 832 } 833 for (list = xauth_head; list; list = list->next) { 834 if (list->auth->name_length != 18 835 || strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) != 0) { 836 if (!XauWriteAuth(fp, list->auth)) { 837 (void) fclose(fp); 838 return -1; 839 } 840 } 841 } 842 843 (void) fclose (fp); 844 return 0; 845} 846 847int 848auth_finalize(void) 849{ 850 char temp_name[1024]; /* large filename size */ 851 852 if (xauth_modified) { 853 if (dieing) { 854 if (verbose) { 855 /* 856 * called from a signal handler -- printf is *not* reentrant; also 857 * fileno() might not be reentrant, avoid it if possible, and use 858 * stderr instead of stdout 859 */ 860#ifdef STDERR_FILENO 861 WRITES(STDERR_FILENO, "\nAborting changes to authority file "); 862 WRITES(STDERR_FILENO, xauth_filename); 863 WRITES(STDERR_FILENO, "\n"); 864#else 865 WRITES(fileno(stderr), "\nAborting changes to authority file "); 866 WRITES(fileno(stderr), xauth_filename); 867 WRITES(fileno(stderr), "\n"); 868#endif 869 } 870 } else if (!xauth_allowed) { 871 fprintf (stderr, 872 "%s: %s not writable, changes ignored\n", 873 ProgramName, xauth_filename); 874 } else { 875 if (verbose) { 876 printf ("%s authority file %s\n", 877 ignore_locks ? "Ignoring locks and writing" : 878 "Writing", xauth_filename); 879 } 880 temp_name[0] = '\0'; 881 if (write_auth_file (temp_name) == -1) { 882 fprintf (stderr, 883 "%s: unable to write authority file %s\n", 884 ProgramName, temp_name); 885 } else { 886 (void) unlink (xauth_filename); 887#if defined(WIN32) || defined(__UNIXOS2__) 888 if (rename(temp_name, xauth_filename) == -1) 889#else 890 /* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */ 891 if (link (temp_name, xauth_filename) == -1 && rename(temp_name, xauth_filename) == -1) 892#endif 893 { 894 fprintf (stderr, 895 "%s: unable to link authority file %s, use %s\n", 896 ProgramName, xauth_filename, temp_name); 897 } else { 898 (void) unlink (temp_name); 899 } 900 } 901 } 902 } 903 904 if (xauth_locked) { 905 XauUnlockAuth (xauth_filename); 906 } 907 (void) umask (original_umask); 908 return 0; 909} 910 911int 912process_command(const char *inputfilename, int lineno, int argc, const char **argv) 913{ 914 int status; 915 916 if (argc < 1 || !argv || !argv[0]) return 1; 917 918 if (dispatch_command (inputfilename, lineno, argc, argv, 919 command_table, &status)) 920 return status; 921 922 prefix (inputfilename, lineno); 923 fprintf (stderr, "unknown command \"%s\"\n", argv[0]); 924 return 1; 925} 926 927 928/* 929 * utility routines 930 */ 931 932static char * 933bintohex(unsigned int len, const char *bindata) 934{ 935 char *hexdata, *starthex; 936 937 /* two chars per byte, plus null termination */ 938 starthex = hexdata = (char *)malloc(2*len + 1); 939 if (!hexdata) 940 return NULL; 941 942 for (; len > 0; len--, bindata++) { 943 register const char *s = hex_table[(unsigned char)*bindata]; 944 *hexdata++ = s[0]; 945 *hexdata++ = s[1]; 946 } 947 *hexdata = '\0'; 948 return starthex; 949} 950 951static void 952fprintfhex(register FILE *fp, int len, char *cp) 953{ 954 char *hex; 955 956 hex = bintohex(len, cp); 957 fprintf(fp, "%s", hex); 958 free(hex); 959} 960 961static int 962dump_numeric(register FILE *fp, register Xauth *auth) 963{ 964 fprintf (fp, "%04x", auth->family); /* unsigned short */ 965 fprintf (fp, " %04x ", auth->address_length); /* short */ 966 fprintfhex (fp, auth->address_length, auth->address); 967 fprintf (fp, " %04x ", auth->number_length); /* short */ 968 fprintfhex (fp, auth->number_length, auth->number); 969 fprintf (fp, " %04x ", auth->name_length); /* short */ 970 fprintfhex (fp, auth->name_length, auth->name); 971 fprintf (fp, " %04x ", auth->data_length); /* short */ 972 fprintfhex (fp, auth->data_length, auth->data); 973 putc ('\n', fp); 974 return 1; 975} 976 977/* ARGSUSED */ 978static int 979dump_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 980{ 981 struct _list_data *ld = (struct _list_data *) data; 982 FILE *fp = ld->fp; 983 984 if (ld->numeric) { 985 dump_numeric (fp, auth); 986 } else { 987 const char *dpyname = NULL; 988 989 switch (auth->family) { 990 case FamilyLocal: 991 fwrite (auth->address, sizeof (char), auth->address_length, fp); 992 fprintf (fp, "/unix"); 993 break; 994 case FamilyInternet: 995#if defined(IPv6) && defined(AF_INET6) 996 case FamilyInternet6: 997#endif 998 case FamilyDECnet: 999 dpyname = get_hostname (auth); 1000 if (dpyname) { 1001 fprintf (fp, "%s", dpyname); 1002 break; 1003 } 1004 /* else fall through to default */ 1005 default: 1006 fprintf (fp, "#%04x#", auth->family); 1007 fprintfhex (fp, auth->address_length, auth->address); 1008 putc ('#', fp); 1009 } 1010 putc (':', fp); 1011 fwrite (auth->number, sizeof (char), auth->number_length, fp); 1012 putc (' ', fp); 1013 putc (' ', fp); 1014 fwrite (auth->name, sizeof (char), auth->name_length, fp); 1015 putc (' ', fp); 1016 putc (' ', fp); 1017 if (!strncmp(auth->name, SECURERPC, auth->name_length) || 1018 !strncmp(auth->name, K5AUTH, auth->name_length)) 1019 fwrite (auth->data, sizeof (char), auth->data_length, fp); 1020 else 1021 fprintfhex (fp, auth->data_length, auth->data); 1022 putc ('\n', fp); 1023 } 1024 return 0; 1025} 1026 1027static int 1028extract_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 1029{ 1030 struct _extract_data *ed = (struct _extract_data *) data; 1031 1032 if (!ed->fp) { 1033 ed->fp = open_file (&ed->filename, 1034 ed->numeric ? "w" : "wb", 1035 &ed->used_stdout, 1036 inputfilename, lineno, ed->cmd); 1037 if (!ed->fp) { 1038 prefix (inputfilename, lineno); 1039 fprintf (stderr, 1040 "unable to open extraction file \"%s\"\n", 1041 ed->filename); 1042 return -1; 1043 } 1044 } 1045 (*(ed->numeric ? dump_numeric : XauWriteAuth)) (ed->fp, auth); 1046 ed->nwritten++; 1047 1048 return 0; 1049} 1050 1051 1052static int 1053eq_auth(Xauth *a, Xauth *b) 1054{ 1055 return((a->family == b->family && 1056 a->address_length == b->address_length && 1057 a->number_length == b->number_length && 1058 a->name_length == b->name_length && 1059 a->data_length == b->data_length && 1060 memcmp(a->address, b->address, a->address_length) == 0 && 1061 memcmp(a->number, b->number, a->number_length) == 0 && 1062 memcmp(a->name, b->name, a->name_length) == 0 && 1063 memcmp(a->data, b->data, a->data_length) == 0) ? 1 : 0); 1064} 1065 1066static int 1067match_auth_dpy(register Xauth *a, register Xauth *b) 1068{ 1069 return ((a->family == b->family && 1070 a->address_length == b->address_length && 1071 a->number_length == b->number_length && 1072 memcmp(a->address, b->address, a->address_length) == 0 && 1073 memcmp(a->number, b->number, a->number_length) == 0) ? 1 : 0); 1074} 1075 1076/* return non-zero iff display and authorization type are the same */ 1077 1078static int 1079match_auth(register Xauth *a, register Xauth *b) 1080{ 1081 return ((match_auth_dpy(a, b) 1082 && a->name_length == b->name_length 1083 && memcmp(a->name, b->name, a->name_length) == 0) ? 1 : 0); 1084} 1085 1086 1087static int 1088merge_entries(AuthList **firstp, AuthList *second, int *nnewp, int *nreplp) 1089{ 1090 AuthList *a, *b, *first, *tail; 1091 int n = 0, nnew = 0, nrepl = 0; 1092 1093 if (!second) return 0; 1094 1095 if (!*firstp) { /* if nothing to merge into */ 1096 *firstp = second; 1097 for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ; 1098 *nnewp = n; 1099 *nreplp = 0; 1100 return n; 1101 } 1102 1103 first = *firstp; 1104 /* 1105 * find end of first list and stick second list on it 1106 */ 1107 for (tail = first; tail->next; tail = tail->next) ; 1108 tail->next = second; 1109 1110 /* 1111 * run down list freeing duplicate entries; if an entry is okay, then 1112 * bump the tail up to include it, otherwise, cut the entry out of 1113 * the chain. 1114 */ 1115 for (b = second; b; ) { 1116 AuthList *next = b->next; /* in case we free it */ 1117 1118 a = first; 1119 for (;;) { 1120 if (match_auth (a->auth, b->auth)) { /* found a duplicate */ 1121 AuthList tmp; /* swap it in for old one */ 1122 tmp = *a; 1123 *a = *b; 1124 *b = tmp; 1125 a->next = b->next; 1126 XauDisposeAuth (b->auth); 1127 free ((char *) b); 1128 b = NULL; 1129 tail->next = next; 1130 nrepl++; 1131 nnew--; 1132 break; 1133 } 1134 if (a == tail) break; /* if have looked at left side */ 1135 a = a->next; 1136 } 1137 if (b) { /* if we didn't remove it */ 1138 tail = b; /* bump end of first list */ 1139 } 1140 b = next; 1141 n++; 1142 nnew++; 1143 } 1144 1145 *nnewp = nnew; 1146 *nreplp = nrepl; 1147 return n; 1148 1149} 1150 1151static Xauth * 1152copyAuth(Xauth *auth) 1153{ 1154 Xauth *a; 1155 1156 a = (Xauth *)malloc(sizeof(Xauth)); 1157 if (a == NULL) { 1158 return NULL; 1159 } 1160 memset(a, 0, sizeof(Xauth)); 1161 a->family = auth->family; 1162 if (auth->address_length != 0) { 1163 a->address = malloc(auth->address_length); 1164 if (a->address == NULL) { 1165 free(a); 1166 return NULL; 1167 } 1168 memcpy(a->address, auth->address, auth->address_length); 1169 a->address_length = auth->address_length; 1170 } 1171 if (auth->number_length != 0) { 1172 a->number = malloc(auth->number_length); 1173 if (a->number == NULL) { 1174 free(a->address); 1175 free(a); 1176 return NULL; 1177 } 1178 memcpy(a->number, auth->number, auth->number_length); 1179 a->number_length = auth->number_length; 1180 } 1181 if (auth->name_length != 0) { 1182 a->name = malloc(auth->name_length); 1183 if (a->name == NULL) { 1184 free(a->address); 1185 free(a->number); 1186 free(a); 1187 return NULL; 1188 } 1189 memcpy(a->name, auth->name, auth->name_length); 1190 a->name_length = auth->name_length; 1191 } 1192 if (auth->data_length != 0) { 1193 a->data = malloc(auth->data_length); 1194 if (a->data == NULL) { 1195 free(a->address); 1196 free(a->number); 1197 free(a->name); 1198 free(a); 1199 return NULL; 1200 } 1201 memcpy(a->data, auth->data, auth->data_length); 1202 a->data_length = auth->data_length; 1203 } 1204 return a; 1205} 1206 1207typedef int (*YesNoFunc)(const char *, int, Xauth *, char *); 1208 1209static int 1210iterdpy (const char *inputfilename, int lineno, int start, 1211 int argc, const char *argv[], 1212 YesNoFunc yfunc, YesNoFunc nfunc, char *data) 1213{ 1214 int i; 1215 int status; 1216 int errors = 0; 1217 Xauth *tmp_auth; 1218 AuthList *proto_head, *proto; 1219 AuthList *l, *next; 1220 1221 /* 1222 * iterate 1223 */ 1224 for (i = start; i < argc; i++) { 1225 const char *displayname = argv[i]; 1226 if (!get_displayname_auth (displayname, &proto_head)) { 1227 prefix (inputfilename, lineno); 1228 baddisplayname (displayname, argv[0]); 1229 errors++; 1230 continue; 1231 } 1232 status = 0; 1233 for (l = xauth_head; l; l = next) { 1234 Bool matched = False; 1235 1236 /* l may be freed by remove_entry below. so save its contents */ 1237 next = l->next; 1238 tmp_auth = copyAuth(l->auth); 1239 for (proto = proto_head; proto; proto = proto->next) { 1240 if (match_auth_dpy (proto->auth, tmp_auth)) { 1241 matched = True; 1242 if (yfunc) { 1243 status = (*yfunc) (inputfilename, lineno, 1244 tmp_auth, data); 1245 if (status < 0) break; 1246 } 1247 } 1248 } 1249 XauDisposeAuth(tmp_auth); 1250 if (matched == False) { 1251 if (nfunc) { 1252 status = (*nfunc) (inputfilename, lineno, 1253 l->auth, data); 1254 } 1255 } 1256 if (status < 0) break; 1257 } 1258 for (proto = proto_head; proto ; proto = next) { 1259 next = proto->next; 1260 if (proto->auth->address) free (proto->auth->address); 1261 if (proto->auth->number) free (proto->auth->number); 1262 free (proto->auth); 1263 free (proto); 1264 } 1265 if (status < 0) { 1266 errors -= status; /* since status is negative */ 1267 break; 1268 } 1269 } 1270 1271 return errors; 1272} 1273 1274/* ARGSUSED */ 1275static int 1276remove_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 1277{ 1278 int *nremovedp = (int *) data; 1279 AuthList **listp = &xauth_head; 1280 AuthList *list; 1281 1282 /* 1283 * unlink the auth we were asked to 1284 */ 1285 while (!eq_auth((list = *listp)->auth, auth)) 1286 listp = &list->next; 1287 *listp = list->next; 1288 XauDisposeAuth (list->auth); /* free the auth */ 1289 free (list); /* free the link */ 1290 xauth_modified = True; 1291 (*nremovedp)++; 1292 return 1; 1293} 1294 1295/* 1296 * action routines 1297 */ 1298 1299/* 1300 * help 1301 */ 1302int 1303print_help(FILE *fp, const char *cmd, const char *prefix) 1304{ 1305 CommandTable *ct; 1306 int n = 0; 1307 1308 if (!prefix) prefix = ""; 1309 1310 if (!cmd) { /* if no cmd, print all help */ 1311 for (ct = command_table; ct->name; ct++) { 1312 fprintf (fp, "%s%s\n", prefix, ct->helptext); 1313 n++; 1314 } 1315 } else { 1316 int len = strlen (cmd); 1317 for (ct = command_table; ct->name; ct++) { 1318 if (strncmp (cmd, ct->name, len) == 0) { 1319 fprintf (fp, "%s%s\n", prefix, ct->helptext); 1320 n++; 1321 } 1322 } 1323 } 1324 1325 return n; 1326} 1327 1328static int 1329do_help(const char *inputfilename, int lineno, int argc, const char **argv) 1330{ 1331 const char *cmd = (argc > 1 ? argv[1] : NULL); 1332 int n; 1333 1334 n = print_help (stdout, cmd, " "); /* a nice amount */ 1335 1336 if (n < 0 || (n == 0 && !cmd)) { 1337 prefix (inputfilename, lineno); 1338 fprintf (stderr, "internal error with help"); 1339 if (cmd) { 1340 fprintf (stderr, " on command \"%s\"", cmd); 1341 } 1342 fprintf (stderr, "\n"); 1343 return 1; 1344 } 1345 1346 if (n == 0) { 1347 prefix (inputfilename, lineno); 1348 /* already know that cmd is set in this case */ 1349 fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd); 1350 } 1351 1352 return 0; 1353} 1354 1355/* 1356 * questionmark 1357 */ 1358/* ARGSUSED */ 1359static int 1360do_questionmark(const char *inputfilename, int lineno, int argc, const char **argv) 1361{ 1362 CommandTable *ct; 1363 int i; 1364#define WIDEST_COLUMN 72 1365 int col = WIDEST_COLUMN; 1366 1367 printf ("Commands:\n"); 1368 for (ct = command_table; ct->name; ct++) { 1369 if ((col + ct->maxlen) > WIDEST_COLUMN) { 1370 if (ct != command_table) { 1371 putc ('\n', stdout); 1372 } 1373 fputs (" ", stdout); 1374 col = 8; /* length of string above */ 1375 } 1376 fputs (ct->name, stdout); 1377 col += ct->maxlen; 1378 for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) { 1379 putc (' ', stdout); 1380 col++; 1381 } 1382 } 1383 if (col != 0) { 1384 putc ('\n', stdout); 1385 } 1386 1387 /* allow bad lines since this is help */ 1388 return 0; 1389} 1390 1391/* 1392 * list [displayname ...] 1393 */ 1394static int 1395do_list (const char *inputfilename, int lineno, int argc, const char **argv) 1396{ 1397 struct _list_data ld; 1398 1399 ld.fp = stdout; 1400 ld.numeric = (argv[0][0] == 'n'); 1401 1402 if (argc == 1) { 1403 register AuthList *l; 1404 1405 if (xauth_head) { 1406 for (l = xauth_head; l; l = l->next) { 1407 dump_entry (inputfilename, lineno, l->auth, (char *) &ld); 1408 } 1409 } 1410 return 0; 1411 } 1412 1413 return iterdpy (inputfilename, lineno, 1, argc, argv, 1414 dump_entry, NULL, (char *) &ld); 1415} 1416 1417/* 1418 * merge filename [filename ...] 1419 */ 1420static int 1421do_merge(const char *inputfilename, int lineno, int argc, const char **argv) 1422{ 1423 int i; 1424 int errors = 0; 1425 AuthList *head, *tail, *listhead, *listtail; 1426 int nentries, nnew, nrepl; 1427 Bool numeric = False; 1428 1429 if (argc < 2) { 1430 prefix (inputfilename, lineno); 1431 badcommandline (argv[0]); 1432 return 1; 1433 } 1434 1435 if (argv[0][0] == 'n') numeric = True; 1436 listhead = listtail = NULL; 1437 1438 for (i = 1; i < argc; i++) { 1439 const char *filename = argv[i]; 1440 FILE *fp; 1441 Bool used_stdin = False; 1442 1443 fp = open_file (&filename, 1444 numeric ? "r" : "rb", 1445 &used_stdin, inputfilename, lineno, 1446 argv[0]); 1447 if (!fp) { 1448 errors++; 1449 continue; 1450 } 1451 1452 head = tail = NULL; 1453 nentries = read_auth_entries (fp, numeric, &head, &tail); 1454 if (nentries == 0) { 1455 prefix (inputfilename, lineno); 1456 fprintf (stderr, "unable to read any entries from file \"%s\"\n", 1457 filename); 1458 errors++; 1459 } else { /* link it in */ 1460 add_to_list (listhead, listtail, head); 1461 } 1462 1463 if (!used_stdin) (void) fclose (fp); 1464 } 1465 1466 /* 1467 * if we have new entries, merge them in (freeing any duplicates) 1468 */ 1469 if (listhead) { 1470 nentries = merge_entries (&xauth_head, listhead, &nnew, &nrepl); 1471 if (verbose) 1472 printf ("%d entries read in: %d new, %d replacement%s\n", 1473 nentries, nnew, nrepl, nrepl != 1 ? "s" : ""); 1474 if (nentries > 0) xauth_modified = True; 1475 } 1476 1477 return 0; 1478} 1479 1480/* 1481 * extract filename displayname [displayname ...] 1482 */ 1483static int 1484do_extract(const char *inputfilename, int lineno, int argc, const char **argv) 1485{ 1486 int errors; 1487 struct _extract_data ed; 1488 1489 if (argc < 3) { 1490 prefix (inputfilename, lineno); 1491 badcommandline (argv[0]); 1492 return 1; 1493 } 1494 1495 ed.fp = NULL; 1496 ed.filename = argv[1]; 1497 ed.used_stdout = False; 1498 ed.numeric = (argv[0][0] == 'n'); 1499 ed.nwritten = 0; 1500 ed.cmd = argv[0]; 1501 1502 errors = iterdpy (inputfilename, lineno, 2, argc, argv, 1503 extract_entry, NULL, (char *) &ed); 1504 1505 if (!ed.fp) { 1506 fprintf (stderr, 1507 "No matches found, authority file \"%s\" not written\n", 1508 ed.filename); 1509 } else { 1510 if (verbose) { 1511 printf ("%d entries written to \"%s\"\n", 1512 ed.nwritten, ed.filename); 1513 } 1514 if (!ed.used_stdout) { 1515 (void) fclose (ed.fp); 1516 } 1517 } 1518 1519 return errors; 1520} 1521 1522 1523/* 1524 * add displayname protocolname hexkey 1525 */ 1526 1527static int 1528do_add(const char *inputfilename, int lineno, int argc, const char **argv) 1529{ 1530 int n, nnew, nrepl; 1531 int len; 1532 const char *dpyname; 1533 const char *protoname; 1534 const char *hexkey; 1535 char *key; 1536 AuthList *list, *list_cur, *list_next; 1537 1538 if (argc != 4 || !argv[1] || !argv[2] || !argv[3]) { 1539 prefix (inputfilename, lineno); 1540 badcommandline (argv[0]); 1541 return 1; 1542 } 1543 1544 dpyname = argv[1]; 1545 protoname = argv[2]; 1546 hexkey = argv[3]; 1547 1548 len = strlen(hexkey); 1549 if (hexkey[0] == '"' && hexkey[len-1] == '"') { 1550 key = malloc(len-1); 1551 strncpy(key, hexkey+1, len-2); 1552 len -= 2; 1553 } else if (!strcmp(protoname, SECURERPC) || 1554 !strcmp(protoname, K5AUTH)) { 1555 key = malloc(len+1); 1556 strcpy(key, hexkey); 1557 } else { 1558 len = cvthexkey (hexkey, &key); 1559 if (len < 0) { 1560 prefix (inputfilename, lineno); 1561 fprintf (stderr, 1562 "key contains odd number of or non-hex characters\n"); 1563 return 1; 1564 } 1565 } 1566 1567 if (!get_displayname_auth (dpyname, &list)) { 1568 prefix (inputfilename, lineno); 1569 baddisplayname (dpyname, argv[0]); 1570 free (key); 1571 return 1; 1572 } 1573 1574 /* 1575 * allow an abbreviation for common protocol names 1576 */ 1577 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) { 1578 protoname = DEFAULT_PROTOCOL; 1579 } 1580 1581 for (list_cur = list; list_cur != NULL; list_cur = list_cur->next) { 1582 Xauth *auth = list_cur->auth; 1583 1584 auth->name_length = strlen (protoname); 1585 auth->name = copystring (protoname, auth->name_length); 1586 if (!auth->name) { 1587 prefix (inputfilename, lineno); 1588 fprintf (stderr, "unable to allocate %d character protocol name\n", 1589 auth->name_length); 1590 for (list_cur = list; list_cur != NULL; list_cur = list_next) { 1591 list_next = list_cur->next; 1592 XauDisposeAuth(list_cur->auth); 1593 free(list_cur); 1594 } 1595 free (key); 1596 return 1; 1597 } 1598 auth->data_length = len; 1599 auth->data = malloc(len); 1600 if (!auth->data) { 1601 prefix(inputfilename, lineno); 1602 fprintf(stderr, "unable to allocate %d bytes for key\n", len); 1603 for (list_cur = list; list_cur != NULL; list_cur = list_next) { 1604 list_next = list_cur->next; 1605 XauDisposeAuth(list_cur->auth); 1606 free(list_cur); 1607 } 1608 free(key); 1609 return 1; 1610 } 1611 memcpy(auth->data, key, len); 1612 } 1613 free(key); 1614 /* 1615 * merge it in; note that merge will deal with allocation 1616 */ 1617 n = merge_entries (&xauth_head, list, &nnew, &nrepl); 1618 if (n <= 0) { 1619 prefix (inputfilename, lineno); 1620 fprintf (stderr, "unable to merge in added record\n"); 1621 return 1; 1622 } 1623 1624 xauth_modified = True; 1625 return 0; 1626} 1627 1628/* 1629 * remove displayname 1630 */ 1631static int 1632do_remove(const char *inputfilename, int lineno, int argc, const char **argv) 1633{ 1634 int nremoved = 0; 1635 int errors; 1636 1637 if (argc < 2) { 1638 prefix (inputfilename, lineno); 1639 badcommandline (argv[0]); 1640 return 1; 1641 } 1642 1643 errors = iterdpy (inputfilename, lineno, 1, argc, argv, 1644 remove_entry, NULL, (char *) &nremoved); 1645 if (verbose) printf ("%d entries removed\n", nremoved); 1646 return errors; 1647} 1648 1649/* 1650 * info 1651 */ 1652static int 1653do_info(const char *inputfilename, int lineno, int argc, const char **argv) 1654{ 1655 int n; 1656 AuthList *l; 1657 1658 if (argc != 1) { 1659 prefix (inputfilename, lineno); 1660 badcommandline (argv[0]); 1661 return 1; 1662 } 1663 1664 for (l = xauth_head, n = 0; l; l = l->next, n++) ; 1665 1666 printf ("Authority file: %s\n", 1667 xauth_filename ? xauth_filename : "(none)"); 1668 printf ("File new: %s\n", xauth_existed ? No : Yes); 1669 printf ("File locked: %s\n", xauth_locked ? No : Yes); 1670 printf ("Number of entries: %d\n", n); 1671 printf ("Changes honored: %s\n", xauth_allowed ? Yes : No); 1672 printf ("Changes made: %s\n", xauth_modified ? Yes : No); 1673 printf ("Current input: %s:%d\n", inputfilename, lineno); 1674 return 0; 1675} 1676 1677 1678/* 1679 * exit 1680 */ 1681static Bool alldone = False; 1682 1683/* ARGSUSED */ 1684static int 1685do_exit(const char *inputfilename, int lineno, int argc, const char **argv) 1686{ 1687 /* allow bogus stuff */ 1688 alldone = True; 1689 return 0; 1690} 1691 1692/* 1693 * quit 1694 */ 1695/* ARGSUSED */ 1696static int 1697do_quit(const char *inputfilename, int lineno, int argc, const char **argv) 1698{ 1699 /* allow bogus stuff */ 1700 die (0); 1701 /* NOTREACHED */ 1702 return -1; /* for picky compilers */ 1703} 1704 1705 1706/* 1707 * source filename 1708 */ 1709static int 1710do_source(const char *inputfilename, int lineno, int argc, const char **argv) 1711{ 1712 const char *script; 1713 char buf[BUFSIZ]; 1714 FILE *fp; 1715 Bool used_stdin = False; 1716 int len; 1717 int errors = 0, status; 1718 int sublineno = 0; 1719 const char **subargv; 1720 int subargc; 1721 Bool prompt = False; /* only true if reading from tty */ 1722 1723 if (argc != 2 || !argv[1]) { 1724 prefix (inputfilename, lineno); 1725 badcommandline (argv[0]); 1726 return 1; 1727 } 1728 1729 script = argv[1]; 1730 1731 fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]); 1732 if (!fp) { 1733 return 1; 1734 } 1735 1736 if (verbose && used_stdin && isatty (fileno (fp))) prompt = True; 1737 1738 while (!alldone) { 1739 buf[0] = '\0'; 1740 if (prompt) { 1741 printf ("xauth> "); 1742 fflush (stdout); 1743 } 1744 if (fgets (buf, sizeof buf, fp) == NULL) break; 1745 sublineno++; 1746 len = strlen (buf); 1747 if (len == 0 || buf[0] == '#') continue; 1748 if (buf[len-1] != '\n') { 1749 prefix (script, sublineno); 1750 fprintf (stderr, "line too long\n"); 1751 errors++; 1752 break; 1753 } 1754 buf[--len] = '\0'; /* remove new line */ 1755 subargv = (const char **) split_into_words (buf, &subargc); 1756 if (subargv) { 1757 status = process_command (script, sublineno, subargc, subargv); 1758 free (subargv); 1759 errors += status; 1760 } else { 1761 prefix (script, sublineno); 1762 fprintf (stderr, "unable to break line into words\n"); 1763 errors++; 1764 } 1765 } 1766 1767 if (!used_stdin) { 1768 (void) fclose (fp); 1769 } 1770 return errors; 1771} 1772 1773static int x_protocol_error; 1774static int 1775catch_x_protocol_error(Display *dpy, XErrorEvent *errevent) 1776{ 1777 char buf[80]; 1778 XGetErrorText(dpy, errevent->error_code, buf, sizeof (buf)); 1779 fprintf(stderr, "%s\n", buf); 1780 x_protocol_error = errevent->error_code; 1781 return 1; 1782} 1783 1784/* 1785 * generate 1786 */ 1787static int 1788do_generate(const char *inputfilename, int lineno, int argc, const char **argv) 1789{ 1790 const char *displayname; 1791 int major_version, minor_version; 1792 XSecurityAuthorization id_return; 1793 Xauth *auth_in, *auth_return; 1794 XSecurityAuthorizationAttributes attributes; 1795 unsigned long attrmask = 0; 1796 Display *dpy; 1797 int status; 1798 const char *args[4]; 1799 const char *protoname = "."; 1800 int i; 1801 int authdatalen = 0; 1802 const char *hexdata; 1803 char *authdata = NULL; 1804 1805 if (argc < 2 || !argv[1]) { 1806 prefix (inputfilename, lineno); 1807 badcommandline (argv[0]); 1808 return 1; 1809 } 1810 1811 displayname = argv[1]; 1812 1813 if (argc > 2) { 1814 protoname = argv[2]; 1815 } 1816 1817 for (i = 3; i < argc; i++) { 1818 if (0 == strcmp(argv[i], "timeout")) { 1819 if (++i == argc) { 1820 prefix (inputfilename, lineno); 1821 badcommandline (argv[i-1]); 1822 return 1; 1823 } 1824 attributes.timeout = atoi(argv[i]); 1825 attrmask |= XSecurityTimeout; 1826 1827 } else if (0 == strcmp(argv[i], "trusted")) { 1828 attributes.trust_level = XSecurityClientTrusted; 1829 attrmask |= XSecurityTrustLevel; 1830 1831 } else if (0 == strcmp(argv[i], "untrusted")) { 1832 attributes.trust_level = XSecurityClientUntrusted; 1833 attrmask |= XSecurityTrustLevel; 1834 1835 } else if (0 == strcmp(argv[i], "group")) { 1836 if (++i == argc) { 1837 prefix (inputfilename, lineno); 1838 badcommandline (argv[i-1]); 1839 return 1; 1840 } 1841 attributes.group = atoi(argv[i]); 1842 attrmask |= XSecurityGroup; 1843 1844 } else if (0 == strcmp(argv[i], "data")) { 1845 if (++i == argc) { 1846 prefix (inputfilename, lineno); 1847 badcommandline (argv[i-1]); 1848 return 1; 1849 } 1850 hexdata = argv[i]; 1851 authdatalen = strlen(hexdata); 1852 if (hexdata[0] == '"' && hexdata[authdatalen-1] == '"') { 1853 authdata = malloc(authdatalen-1); 1854 strncpy(authdata, hexdata+1, authdatalen-2); 1855 authdatalen -= 2; 1856 } else { 1857 authdatalen = cvthexkey (hexdata, &authdata); 1858 if (authdatalen < 0) { 1859 prefix (inputfilename, lineno); 1860 fprintf (stderr, 1861 "data contains odd number of or non-hex characters\n"); 1862 return 1; 1863 } 1864 } 1865 } else { 1866 prefix (inputfilename, lineno); 1867 badcommandline (argv[i]); 1868 return 1; 1869 } 1870 } 1871 1872 /* generate authorization using the Security extension */ 1873 1874 dpy = XOpenDisplay (displayname); 1875 if (!dpy) { 1876 prefix (inputfilename, lineno); 1877 fprintf (stderr, "unable to open display \"%s\".\n", displayname); 1878 return 1; 1879 } 1880 1881 status = XSecurityQueryExtension(dpy, &major_version, &minor_version); 1882 if (!status) 1883 { 1884 prefix (inputfilename, lineno); 1885 fprintf (stderr, "couldn't query Security extension on display \"%s\"\n", 1886 displayname); 1887 return 1; 1888 } 1889 1890 /* fill in input Xauth struct */ 1891 1892 auth_in = XSecurityAllocXauth(); 1893 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) { 1894 auth_in->name = DEFAULT_PROTOCOL; 1895 } 1896 else 1897 auth_in->name = protoname; 1898 auth_in->name_length = strlen(auth_in->name); 1899 auth_in->data = authdata; 1900 auth_in->data_length = authdatalen; 1901 1902 x_protocol_error = 0; 1903 XSetErrorHandler(catch_x_protocol_error); 1904 auth_return = XSecurityGenerateAuthorization(dpy, auth_in, attrmask, 1905 &attributes, &id_return); 1906 XSync(dpy, False); 1907 1908 if (!auth_return || x_protocol_error) 1909 { 1910 prefix (inputfilename, lineno); 1911 fprintf (stderr, "couldn't generate authorization\n"); 1912 return 1; 1913 } 1914 1915 if (verbose) 1916 printf("authorization id is %ld\n", id_return); 1917 1918 /* create a fake input line to give to do_add */ 1919 1920 args[0] = "add"; 1921 args[1] = displayname; 1922 args[2] = auth_in->name; 1923 args[3] = bintohex(auth_return->data_length, auth_return->data); 1924 1925 status = do_add(inputfilename, lineno, 4, args); 1926 1927 if (authdata) free(authdata); 1928 XSecurityFreeXauth(auth_in); 1929 XSecurityFreeXauth(auth_return); 1930 free((char *) args[3]); /* hex data */ 1931 XCloseDisplay(dpy); 1932 return status; 1933} 1934