process.c revision 2852888e
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)(char *, int, int, 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 char *name; /* full name */ 74 int minlen; /* unique prefix */ 75 int maxlen; /* strlen(name) */ 76 ProcessFunc processfunc; /* handler */ 77 char *helptext; /* what to print for help */ 78} CommandTable; 79 80struct _extract_data { /* for iterating */ 81 FILE *fp; /* input source */ 82 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 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 char *stdin_filename = "(stdin)"; /* for messages */ 99static char *stdout_filename = "(stdout)"; /* for messages */ 100static char *Yes = "yes"; /* for messages */ 101static char *No = "no"; /* for messages */ 102 103static int do_help ( char *inputfilename, int lineno, int argc, char **argv ); 104static int do_questionmark ( char *inputfilename, int lineno, int argc, char **argv ); 105static int do_list ( char *inputfilename, int lineno, int argc, char **argv ); 106static int do_merge ( char *inputfilename, int lineno, int argc, char **argv ); 107static int do_extract ( char *inputfilename, int lineno, int argc, char **argv ); 108static int do_add ( char *inputfilename, int lineno, int argc, char **argv ); 109static int do_remove ( char *inputfilename, int lineno, int argc, char **argv ); 110static int do_info ( char *inputfilename, int lineno, int argc, char **argv ); 111static int do_exit ( char *inputfilename, int lineno, int argc, char **argv ); 112static int do_quit ( char *inputfilename, int lineno, int argc, char **argv ); 113static int do_source ( char *inputfilename, int lineno, int argc, char **argv ); 114static int do_generate ( char *inputfilename, int lineno, int argc, 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 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(char *fn, int n) 208{ 209 fprintf (stderr, "%s: %s:%d: ", ProgramName, fn, n); 210} 211 212static void 213baddisplayname(char *dpy, char *cmd) 214{ 215 fprintf (stderr, "bad display name \"%s\" in \"%s\" command\n", 216 dpy, cmd); 217} 218 219static void 220badcommandline(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(char **filenamep, 290 char *mode, 291 Bool *usedstdp, 292 char *srcfn, 293 int srcln, 294 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(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(char *hexstr, char **ptrp) /* turn hex key string into octets */ 545{ 546 int i; 547 int len = 0; 548 char *retval, *s; 549 unsigned char *us; 550 char c; 551 char savec = '\0'; 552 553 /* count */ 554 for (s = hexstr; *s; s++) { 555 if (!isascii(*s)) return -1; 556 if (isspace(*s)) continue; 557 if (!isxdigit(*s)) return -1; 558 len++; 559 } 560 561 /* if 0 or odd, then there was an error */ 562 if (len == 0 || (len & 1) == 1) return -1; 563 564 565 /* now we know that the input is good */ 566 len >>= 1; 567 retval = malloc (len); 568 if (!retval) { 569 fprintf (stderr, "%s: unable to allocate %d bytes for hexkey\n", 570 ProgramName, len); 571 return -1; 572 } 573 574 for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) { 575 c = *hexstr; 576 if (isspace(c)) continue; /* already know it is ascii */ 577 if (isupper(c)) 578 c = tolower(c); 579 if (savec) { 580#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10))) 581 *us = (unsigned char)((atoh(savec) << 4) + atoh(c)); 582#undef atoh 583 savec = 0; /* ready for next character */ 584 us++; 585 i--; 586 } else { 587 savec = c; 588 } 589 } 590 *ptrp = retval; 591 return len; 592} 593 594static int 595dispatch_command(char *inputfilename, 596 int lineno, 597 int argc, 598 char **argv, 599 CommandTable *tab, 600 int *statusp) 601{ 602 CommandTable *ct; 603 char *cmd; 604 int n; 605 /* scan table for command */ 606 cmd = argv[0]; 607 n = strlen (cmd); 608 for (ct = tab; ct->name; ct++) { 609 /* look for unique prefix */ 610 if (n >= ct->minlen && n <= ct->maxlen && 611 strncmp (cmd, ct->name, n) == 0) { 612 *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv); 613 return 1; 614 } 615 } 616 617 *statusp = 1; 618 return 0; 619} 620 621 622static AuthList *xauth_head = NULL; /* list of auth entries */ 623static Bool xauth_existed = False; /* if was present at initialize */ 624static Bool xauth_modified = False; /* if added, removed, or merged */ 625static Bool xauth_allowed = True; /* if allowed to write auth file */ 626static Bool xauth_locked = False; /* if has been locked */ 627static char *xauth_filename = NULL; 628static volatile Bool dieing = False; 629 630 631/* poor man's puts(), for under signal handlers */ 632#define WRITES(fd, S) (void)write((fd), (S), strlen((S))) 633 634/* ARGSUSED */ 635static RETSIGTYPE 636die(int sig) 637{ 638 dieing = True; 639 _exit (auth_finalize ()); 640 /* NOTREACHED */ 641#ifdef SIGNALRETURNSINT 642 return -1; /* for picky compilers */ 643#endif 644} 645 646static RETSIGTYPE 647catchsig(int sig) 648{ 649#ifdef SYSV 650 if (sig > 0) signal (sig, die); /* re-establish signal handler */ 651#endif 652 /* 653 * fileno() might not be reentrant, avoid it if possible, and use 654 * stderr instead of stdout 655 */ 656#ifdef STDERR_FILENO 657 if (verbose && xauth_modified) WRITES(STDERR_FILENO, "\r\n"); 658#else 659 if (verbose && xauth_modified) WRITES(fileno(stderr), "\r\n"); 660#endif 661 die (sig); 662 /* NOTREACHED */ 663#ifdef SIGNALRETURNSINT 664 return -1; /* for picky compilers */ 665#endif 666} 667 668static void 669register_signals(void) 670{ 671 signal (SIGINT, catchsig); 672 signal (SIGTERM, catchsig); 673#ifdef SIGHUP 674 signal (SIGHUP, catchsig); 675#endif 676#ifdef SIGPIPE 677 signal (SIGPIPE, catchsig); 678#endif 679 return; 680} 681 682 683/* 684 * public procedures for parsing lines of input 685 */ 686 687int 688auth_initialize(char *authfilename) 689{ 690 int n; 691 AuthList *head, *tail; 692 FILE *authfp; 693 Bool exists; 694 695 xauth_filename = authfilename; /* used in cleanup, prevent race with 696 signals */ 697 register_signals (); 698 699 bzero ((char *) hexvalues, sizeof hexvalues); 700 hexvalues['0'] = 0; 701 hexvalues['1'] = 1; 702 hexvalues['2'] = 2; 703 hexvalues['3'] = 3; 704 hexvalues['4'] = 4; 705 hexvalues['5'] = 5; 706 hexvalues['6'] = 6; 707 hexvalues['7'] = 7; 708 hexvalues['8'] = 8; 709 hexvalues['9'] = 9; 710 hexvalues['a'] = hexvalues['A'] = 0xa; 711 hexvalues['b'] = hexvalues['B'] = 0xb; 712 hexvalues['c'] = hexvalues['C'] = 0xc; 713 hexvalues['d'] = hexvalues['D'] = 0xd; 714 hexvalues['e'] = hexvalues['E'] = 0xe; 715 hexvalues['f'] = hexvalues['F'] = 0xf; 716 717 if (break_locks && verbose) { 718 printf ("Attempting to break locks on authority file %s\n", 719 authfilename); 720 } 721 722 if (ignore_locks) { 723 if (break_locks) XauUnlockAuth (authfilename); 724 } else { 725 n = XauLockAuth (authfilename, XAUTH_DEFAULT_RETRIES, 726 XAUTH_DEFAULT_TIMEOUT, 727 (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME)); 728 if (n != LOCK_SUCCESS) { 729 char *reason = "unknown error"; 730 switch (n) { 731 case LOCK_ERROR: 732 reason = "error"; 733 break; 734 case LOCK_TIMEOUT: 735 reason = "timeout"; 736 break; 737 } 738 fprintf (stderr, "%s: %s in locking authority file %s\n", 739 ProgramName, reason, authfilename); 740 return -1; 741 } else 742 xauth_locked = True; 743 } 744 745 /* these checks can only be done reliably after the file is locked */ 746 exists = (access (authfilename, F_OK) == 0); 747 if (exists && access (authfilename, W_OK) != 0) { 748 fprintf (stderr, 749 "%s: %s not writable, changes will be ignored\n", 750 ProgramName, authfilename); 751 xauth_allowed = False; 752 } 753 754 original_umask = umask (0077); /* disallow non-owner access */ 755 756 authfp = fopen (authfilename, "rb"); 757 if (!authfp) { 758 int olderrno = errno; 759 760 /* if file there then error */ 761 if (access (authfilename, F_OK) == 0) { /* then file does exist! */ 762 errno = olderrno; 763 return -1; 764 } /* else ignore it */ 765 fprintf (stderr, 766 "%s: file %s does not exist\n", 767 ProgramName, authfilename); 768 } else { 769 xauth_existed = True; 770 n = read_auth_entries (authfp, False, &head, &tail); 771 (void) fclose (authfp); 772 if (n < 0) { 773 fprintf (stderr, 774 "%s: unable to read auth entries from file \"%s\"\n", 775 ProgramName, authfilename); 776 return -1; 777 } 778 xauth_head = head; 779 } 780 781 n = strlen (authfilename); 782 xauth_filename = malloc (n + 1); 783 if (xauth_filename) strcpy (xauth_filename, authfilename); 784 else { 785 fprintf(stderr,"cannot allocate memory\n"); 786 return -1; 787 } 788 789 xauth_modified = False; 790 791 if (verbose) { 792 printf ("%s authority file %s\n", 793 ignore_locks ? "Ignoring locks on" : "Using", authfilename); 794 } 795 return 0; 796} 797 798static int 799write_auth_file(char *tmp_nam) 800{ 801 FILE *fp = NULL; 802 int fd; 803 AuthList *list; 804 805 /* 806 * xdm and auth spec assumes auth file is 12 or fewer characters 807 */ 808 strcpy (tmp_nam, xauth_filename); 809 strcat (tmp_nam, "-n"); /* for new */ 810 (void) unlink (tmp_nam); 811 /* CPhipps 2000/02/12 - fix file unlink/fopen race */ 812 fd = open(tmp_nam, O_WRONLY | O_CREAT | O_EXCL, 0600); 813 if (fd != -1) fp = fdopen (fd, "wb"); 814 if (!fp) { 815 if (fd != -1) close(fd); 816 fprintf (stderr, "%s: unable to open tmp file \"%s\"\n", 817 ProgramName, tmp_nam); 818 return -1; 819 } 820 821 /* 822 * Write MIT-MAGIC-COOKIE-1 first, because R4 Xlib knows 823 * only that and uses the first authorization it finds. 824 */ 825 for (list = xauth_head; list; list = list->next) { 826 if (list->auth->name_length == 18 827 && strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) == 0) { 828 if (!XauWriteAuth(fp, list->auth)) { 829 (void) fclose(fp); 830 return -1; 831 } 832 } 833 } 834 for (list = xauth_head; list; list = list->next) { 835 if (list->auth->name_length != 18 836 || strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) != 0) { 837 if (!XauWriteAuth(fp, list->auth)) { 838 (void) fclose(fp); 839 return -1; 840 } 841 } 842 } 843 844 (void) fclose (fp); 845 return 0; 846} 847 848int 849auth_finalize(void) 850{ 851 char temp_name[1024]; /* large filename size */ 852 853 if (xauth_modified) { 854 if (dieing) { 855 if (verbose) { 856 /* 857 * called from a signal handler -- printf is *not* reentrant; also 858 * fileno() might not be reentrant, avoid it if possible, and use 859 * stderr instead of stdout 860 */ 861#ifdef STDERR_FILENO 862 WRITES(STDERR_FILENO, "\nAborting changes to authority file "); 863 WRITES(STDERR_FILENO, xauth_filename); 864 WRITES(STDERR_FILENO, "\n"); 865#else 866 WRITES(fileno(stderr), "\nAborting changes to authority file "); 867 WRITES(fileno(stderr), xauth_filename); 868 WRITES(fileno(stderr), "\n"); 869#endif 870 } 871 } else if (!xauth_allowed) { 872 fprintf (stderr, 873 "%s: %s not writable, changes ignored\n", 874 ProgramName, xauth_filename); 875 } else { 876 if (verbose) { 877 printf ("%s authority file %s\n", 878 ignore_locks ? "Ignoring locks and writing" : 879 "Writing", xauth_filename); 880 } 881 temp_name[0] = '\0'; 882 if (write_auth_file (temp_name) == -1) { 883 fprintf (stderr, 884 "%s: unable to write authority file %s\n", 885 ProgramName, temp_name); 886 } else { 887 (void) unlink (xauth_filename); 888#if defined(WIN32) || defined(__UNIXOS2__) 889 if (rename(temp_name, xauth_filename) == -1) 890#else 891 /* Attempt to rename() if link() fails, since this may be on a FS that does not support hard links */ 892 if (link (temp_name, xauth_filename) == -1 && rename(temp_name, xauth_filename) == -1) 893#endif 894 { 895 fprintf (stderr, 896 "%s: unable to link authority file %s, use %s\n", 897 ProgramName, xauth_filename, temp_name); 898 } else { 899 (void) unlink (temp_name); 900 } 901 } 902 } 903 } 904 905 if (xauth_locked) { 906 XauUnlockAuth (xauth_filename); 907 } 908 (void) umask (original_umask); 909 return 0; 910} 911 912int 913process_command(char *inputfilename, int lineno, int argc, char **argv) 914{ 915 int status; 916 917 if (argc < 1 || !argv || !argv[0]) return 1; 918 919 if (dispatch_command (inputfilename, lineno, argc, argv, 920 command_table, &status)) 921 return status; 922 923 prefix (inputfilename, lineno); 924 fprintf (stderr, "unknown command \"%s\"\n", argv[0]); 925 return 1; 926} 927 928 929/* 930 * utility routines 931 */ 932 933static char * 934bintohex(unsigned int len, char *bindata) 935{ 936 char *hexdata, *starthex; 937 938 /* two chars per byte, plus null termination */ 939 starthex = hexdata = (char *)malloc(2*len + 1); 940 if (!hexdata) 941 return NULL; 942 943 for (; len > 0; len--, bindata++) { 944 register char *s = hex_table[(unsigned char)*bindata]; 945 *hexdata++ = s[0]; 946 *hexdata++ = s[1]; 947 } 948 *hexdata = '\0'; 949 return starthex; 950} 951 952static void 953fprintfhex(register FILE *fp, int len, char *cp) 954{ 955 char *hex; 956 957 hex = bintohex(len, cp); 958 fprintf(fp, "%s", hex); 959 free(hex); 960} 961 962static int 963dump_numeric(register FILE *fp, register Xauth *auth) 964{ 965 fprintf (fp, "%04x", auth->family); /* unsigned short */ 966 fprintf (fp, " %04x ", auth->address_length); /* short */ 967 fprintfhex (fp, auth->address_length, auth->address); 968 fprintf (fp, " %04x ", auth->number_length); /* short */ 969 fprintfhex (fp, auth->number_length, auth->number); 970 fprintf (fp, " %04x ", auth->name_length); /* short */ 971 fprintfhex (fp, auth->name_length, auth->name); 972 fprintf (fp, " %04x ", auth->data_length); /* short */ 973 fprintfhex (fp, auth->data_length, auth->data); 974 putc ('\n', fp); 975 return 1; 976} 977 978/* ARGSUSED */ 979static int 980dump_entry(char *inputfilename, int lineno, Xauth *auth, char *data) 981{ 982 struct _list_data *ld = (struct _list_data *) data; 983 FILE *fp = ld->fp; 984 985 if (ld->numeric) { 986 dump_numeric (fp, auth); 987 } else { 988 char *dpyname = NULL; 989 990 switch (auth->family) { 991 case FamilyLocal: 992 fwrite (auth->address, sizeof (char), auth->address_length, fp); 993 fprintf (fp, "/unix"); 994 break; 995 case FamilyInternet: 996#if defined(IPv6) && defined(AF_INET6) 997 case FamilyInternet6: 998#endif 999 case FamilyDECnet: 1000 dpyname = get_hostname (auth); 1001 if (dpyname) { 1002 fprintf (fp, "%s", dpyname); 1003 break; 1004 } 1005 /* else fall through to default */ 1006 default: 1007 fprintf (fp, "#%04x#", auth->family); 1008 fprintfhex (fp, auth->address_length, auth->address); 1009 putc ('#', fp); 1010 } 1011 putc (':', fp); 1012 fwrite (auth->number, sizeof (char), auth->number_length, fp); 1013 putc (' ', fp); 1014 putc (' ', fp); 1015 fwrite (auth->name, sizeof (char), auth->name_length, fp); 1016 putc (' ', fp); 1017 putc (' ', fp); 1018 if (!strncmp(auth->name, SECURERPC, auth->name_length) || 1019 !strncmp(auth->name, K5AUTH, auth->name_length)) 1020 fwrite (auth->data, sizeof (char), auth->data_length, fp); 1021 else 1022 fprintfhex (fp, auth->data_length, auth->data); 1023 putc ('\n', fp); 1024 } 1025 return 0; 1026} 1027 1028static int 1029extract_entry(char *inputfilename, int lineno, Xauth *auth, char *data) 1030{ 1031 struct _extract_data *ed = (struct _extract_data *) data; 1032 1033 if (!ed->fp) { 1034 ed->fp = open_file (&ed->filename, 1035 ed->numeric ? "w" : "wb", 1036 &ed->used_stdout, 1037 inputfilename, lineno, ed->cmd); 1038 if (!ed->fp) { 1039 prefix (inputfilename, lineno); 1040 fprintf (stderr, 1041 "unable to open extraction file \"%s\"\n", 1042 ed->filename); 1043 return -1; 1044 } 1045 } 1046 (*(ed->numeric ? dump_numeric : XauWriteAuth)) (ed->fp, auth); 1047 ed->nwritten++; 1048 1049 return 0; 1050} 1051 1052 1053static int 1054eq_auth(Xauth *a, Xauth *b) 1055{ 1056 return((a->family == b->family && 1057 a->address_length == b->address_length && 1058 a->number_length == b->number_length && 1059 a->name_length == b->name_length && 1060 a->data_length == b->data_length && 1061 memcmp(a->address, b->address, a->address_length) == 0 && 1062 memcmp(a->number, b->number, a->number_length) == 0 && 1063 memcmp(a->name, b->name, a->name_length) == 0 && 1064 memcmp(a->data, b->data, a->data_length) == 0) ? 1 : 0); 1065} 1066 1067static int 1068match_auth_dpy(register Xauth *a, register Xauth *b) 1069{ 1070 return ((a->family == b->family && 1071 a->address_length == b->address_length && 1072 a->number_length == b->number_length && 1073 memcmp(a->address, b->address, a->address_length) == 0 && 1074 memcmp(a->number, b->number, a->number_length) == 0) ? 1 : 0); 1075} 1076 1077/* return non-zero iff display and authorization type are the same */ 1078 1079static int 1080match_auth(register Xauth *a, register Xauth *b) 1081{ 1082 return ((match_auth_dpy(a, b) 1083 && a->name_length == b->name_length 1084 && memcmp(a->name, b->name, a->name_length) == 0) ? 1 : 0); 1085} 1086 1087 1088static int 1089merge_entries(AuthList **firstp, AuthList *second, int *nnewp, int *nreplp) 1090{ 1091 AuthList *a, *b, *first, *tail; 1092 int n = 0, nnew = 0, nrepl = 0; 1093 1094 if (!second) return 0; 1095 1096 if (!*firstp) { /* if nothing to merge into */ 1097 *firstp = second; 1098 for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ; 1099 *nnewp = n; 1100 *nreplp = 0; 1101 return n; 1102 } 1103 1104 first = *firstp; 1105 /* 1106 * find end of first list and stick second list on it 1107 */ 1108 for (tail = first; tail->next; tail = tail->next) ; 1109 tail->next = second; 1110 1111 /* 1112 * run down list freeing duplicate entries; if an entry is okay, then 1113 * bump the tail up to include it, otherwise, cut the entry out of 1114 * the chain. 1115 */ 1116 for (b = second; b; ) { 1117 AuthList *next = b->next; /* in case we free it */ 1118 1119 a = first; 1120 for (;;) { 1121 if (match_auth (a->auth, b->auth)) { /* found a duplicate */ 1122 AuthList tmp; /* swap it in for old one */ 1123 tmp = *a; 1124 *a = *b; 1125 *b = tmp; 1126 a->next = b->next; 1127 XauDisposeAuth (b->auth); 1128 free ((char *) b); 1129 b = NULL; 1130 tail->next = next; 1131 nrepl++; 1132 nnew--; 1133 break; 1134 } 1135 if (a == tail) break; /* if have looked at left side */ 1136 a = a->next; 1137 } 1138 if (b) { /* if we didn't remove it */ 1139 tail = b; /* bump end of first list */ 1140 } 1141 b = next; 1142 n++; 1143 nnew++; 1144 } 1145 1146 *nnewp = nnew; 1147 *nreplp = nrepl; 1148 return n; 1149 1150} 1151 1152static Xauth * 1153copyAuth(Xauth *auth) 1154{ 1155 Xauth *a; 1156 1157 a = (Xauth *)malloc(sizeof(Xauth)); 1158 if (a == NULL) { 1159 return NULL; 1160 } 1161 memset(a, 0, sizeof(Xauth)); 1162 a->family = auth->family; 1163 if (auth->address_length != 0) { 1164 a->address = malloc(auth->address_length); 1165 if (a->address == NULL) { 1166 free(a); 1167 return NULL; 1168 } 1169 memcpy(a->address, auth->address, auth->address_length); 1170 a->address_length = auth->address_length; 1171 } 1172 if (auth->number_length != 0) { 1173 a->number = malloc(auth->number_length); 1174 if (a->number == NULL) { 1175 free(a->address); 1176 free(a); 1177 return NULL; 1178 } 1179 memcpy(a->number, auth->number, auth->number_length); 1180 a->number_length = auth->number_length; 1181 } 1182 if (auth->name_length != 0) { 1183 a->name = malloc(auth->name_length); 1184 if (a->name == NULL) { 1185 free(a->address); 1186 free(a->number); 1187 free(a); 1188 return NULL; 1189 } 1190 memcpy(a->name, auth->name, auth->name_length); 1191 a->name_length = auth->name_length; 1192 } 1193 if (auth->data_length != 0) { 1194 a->data = malloc(auth->data_length); 1195 if (a->data == NULL) { 1196 free(a->address); 1197 free(a->number); 1198 free(a->name); 1199 free(a); 1200 return NULL; 1201 } 1202 memcpy(a->data, auth->data, auth->data_length); 1203 a->data_length = auth->data_length; 1204 } 1205 return a; 1206} 1207 1208typedef int (*YesNoFunc)(char *, int, Xauth *, char *); 1209 1210static int 1211iterdpy (char *inputfilename, int lineno, int start, 1212 int argc, char *argv[], 1213 YesNoFunc yfunc, YesNoFunc nfunc, char *data) 1214{ 1215 int i; 1216 int status; 1217 int errors = 0; 1218 Xauth *tmp_auth; 1219 AuthList *proto_head, *proto; 1220 AuthList *l, *next; 1221 1222 /* 1223 * iterate 1224 */ 1225 for (i = start; i < argc; i++) { 1226 char *displayname = argv[i]; 1227 if (!get_displayname_auth (displayname, &proto_head)) { 1228 prefix (inputfilename, lineno); 1229 baddisplayname (displayname, argv[0]); 1230 errors++; 1231 continue; 1232 } 1233 status = 0; 1234 for (l = xauth_head; l; l = next) { 1235 Bool matched = False; 1236 1237 /* l may be freed by remove_entry below. so save its contents */ 1238 next = l->next; 1239 tmp_auth = copyAuth(l->auth); 1240 for (proto = proto_head; proto; proto = proto->next) { 1241 if (match_auth_dpy (proto->auth, tmp_auth)) { 1242 matched = True; 1243 if (yfunc) { 1244 status = (*yfunc) (inputfilename, lineno, 1245 tmp_auth, data); 1246 if (status < 0) break; 1247 } 1248 } 1249 } 1250 XauDisposeAuth(tmp_auth); 1251 if (matched == False) { 1252 if (nfunc) { 1253 status = (*nfunc) (inputfilename, lineno, 1254 l->auth, data); 1255 } 1256 } 1257 if (status < 0) break; 1258 } 1259 for (proto = proto_head; proto ; proto = next) { 1260 next = proto->next; 1261 if (proto->auth->address) free (proto->auth->address); 1262 if (proto->auth->number) free (proto->auth->number); 1263 free (proto->auth); 1264 free (proto); 1265 } 1266 if (status < 0) { 1267 errors -= status; /* since status is negative */ 1268 break; 1269 } 1270 } 1271 1272 return errors; 1273} 1274 1275/* ARGSUSED */ 1276static int 1277remove_entry(char *inputfilename, int lineno, Xauth *auth, char *data) 1278{ 1279 int *nremovedp = (int *) data; 1280 AuthList **listp = &xauth_head; 1281 AuthList *list; 1282 1283 /* 1284 * unlink the auth we were asked to 1285 */ 1286 while (!eq_auth((list = *listp)->auth, auth)) 1287 listp = &list->next; 1288 *listp = list->next; 1289 XauDisposeAuth (list->auth); /* free the auth */ 1290 free (list); /* free the link */ 1291 xauth_modified = True; 1292 (*nremovedp)++; 1293 return 1; 1294} 1295 1296/* 1297 * action routines 1298 */ 1299 1300/* 1301 * help 1302 */ 1303int 1304print_help(FILE *fp, char *cmd, char *prefix) 1305{ 1306 CommandTable *ct; 1307 int n = 0; 1308 1309 if (!prefix) prefix = ""; 1310 1311 if (!cmd) { /* if no cmd, print all help */ 1312 for (ct = command_table; ct->name; ct++) { 1313 fprintf (fp, "%s%s\n", prefix, ct->helptext); 1314 n++; 1315 } 1316 } else { 1317 int len = strlen (cmd); 1318 for (ct = command_table; ct->name; ct++) { 1319 if (strncmp (cmd, ct->name, len) == 0) { 1320 fprintf (fp, "%s%s\n", prefix, ct->helptext); 1321 n++; 1322 } 1323 } 1324 } 1325 1326 return n; 1327} 1328 1329static int 1330do_help(char *inputfilename, int lineno, int argc, char **argv) 1331{ 1332 char *cmd = (argc > 1 ? argv[1] : NULL); 1333 int n; 1334 1335 n = print_help (stdout, cmd, " "); /* a nice amount */ 1336 1337 if (n < 0 || (n == 0 && !cmd)) { 1338 prefix (inputfilename, lineno); 1339 fprintf (stderr, "internal error with help"); 1340 if (cmd) { 1341 fprintf (stderr, " on command \"%s\"", cmd); 1342 } 1343 fprintf (stderr, "\n"); 1344 return 1; 1345 } 1346 1347 if (n == 0) { 1348 prefix (inputfilename, lineno); 1349 /* already know that cmd is set in this case */ 1350 fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd); 1351 } 1352 1353 return 0; 1354} 1355 1356/* 1357 * questionmark 1358 */ 1359/* ARGSUSED */ 1360static int 1361do_questionmark(char *inputfilename, int lineno, int argc, char **argv) 1362{ 1363 CommandTable *ct; 1364 int i; 1365#define WIDEST_COLUMN 72 1366 int col = WIDEST_COLUMN; 1367 1368 printf ("Commands:\n"); 1369 for (ct = command_table; ct->name; ct++) { 1370 if ((col + ct->maxlen) > WIDEST_COLUMN) { 1371 if (ct != command_table) { 1372 putc ('\n', stdout); 1373 } 1374 fputs (" ", stdout); 1375 col = 8; /* length of string above */ 1376 } 1377 fputs (ct->name, stdout); 1378 col += ct->maxlen; 1379 for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) { 1380 putc (' ', stdout); 1381 col++; 1382 } 1383 } 1384 if (col != 0) { 1385 putc ('\n', stdout); 1386 } 1387 1388 /* allow bad lines since this is help */ 1389 return 0; 1390} 1391 1392/* 1393 * list [displayname ...] 1394 */ 1395static int 1396do_list (char *inputfilename, int lineno, int argc, char **argv) 1397{ 1398 struct _list_data ld; 1399 1400 ld.fp = stdout; 1401 ld.numeric = (argv[0][0] == 'n'); 1402 1403 if (argc == 1) { 1404 register AuthList *l; 1405 1406 if (xauth_head) { 1407 for (l = xauth_head; l; l = l->next) { 1408 dump_entry (inputfilename, lineno, l->auth, (char *) &ld); 1409 } 1410 } 1411 return 0; 1412 } 1413 1414 return iterdpy (inputfilename, lineno, 1, argc, argv, 1415 dump_entry, NULL, (char *) &ld); 1416} 1417 1418/* 1419 * merge filename [filename ...] 1420 */ 1421static int 1422do_merge(char *inputfilename, int lineno, int argc, char **argv) 1423{ 1424 int i; 1425 int errors = 0; 1426 AuthList *head, *tail, *listhead, *listtail; 1427 int nentries, nnew, nrepl; 1428 Bool numeric = False; 1429 1430 if (argc < 2) { 1431 prefix (inputfilename, lineno); 1432 badcommandline (argv[0]); 1433 return 1; 1434 } 1435 1436 if (argv[0][0] == 'n') numeric = True; 1437 listhead = listtail = NULL; 1438 1439 for (i = 1; i < argc; i++) { 1440 char *filename = argv[i]; 1441 FILE *fp; 1442 Bool used_stdin = False; 1443 1444 fp = open_file (&filename, 1445 numeric ? "r" : "rb", 1446 &used_stdin, inputfilename, lineno, 1447 argv[0]); 1448 if (!fp) { 1449 errors++; 1450 continue; 1451 } 1452 1453 head = tail = NULL; 1454 nentries = read_auth_entries (fp, numeric, &head, &tail); 1455 if (nentries == 0) { 1456 prefix (inputfilename, lineno); 1457 fprintf (stderr, "unable to read any entries from file \"%s\"\n", 1458 filename); 1459 errors++; 1460 } else { /* link it in */ 1461 add_to_list (listhead, listtail, head); 1462 } 1463 1464 if (!used_stdin) (void) fclose (fp); 1465 } 1466 1467 /* 1468 * if we have new entries, merge them in (freeing any duplicates) 1469 */ 1470 if (listhead) { 1471 nentries = merge_entries (&xauth_head, listhead, &nnew, &nrepl); 1472 if (verbose) 1473 printf ("%d entries read in: %d new, %d replacement%s\n", 1474 nentries, nnew, nrepl, nrepl != 1 ? "s" : ""); 1475 if (nentries > 0) xauth_modified = True; 1476 } 1477 1478 return 0; 1479} 1480 1481/* 1482 * extract filename displayname [displayname ...] 1483 */ 1484static int 1485do_extract(char *inputfilename, int lineno, int argc, char **argv) 1486{ 1487 int errors; 1488 struct _extract_data ed; 1489 1490 if (argc < 3) { 1491 prefix (inputfilename, lineno); 1492 badcommandline (argv[0]); 1493 return 1; 1494 } 1495 1496 ed.fp = NULL; 1497 ed.filename = argv[1]; 1498 ed.used_stdout = False; 1499 ed.numeric = (argv[0][0] == 'n'); 1500 ed.nwritten = 0; 1501 ed.cmd = argv[0]; 1502 1503 errors = iterdpy (inputfilename, lineno, 2, argc, argv, 1504 extract_entry, NULL, (char *) &ed); 1505 1506 if (!ed.fp) { 1507 fprintf (stderr, 1508 "No matches found, authority file \"%s\" not written\n", 1509 ed.filename); 1510 } else { 1511 if (verbose) { 1512 printf ("%d entries written to \"%s\"\n", 1513 ed.nwritten, ed.filename); 1514 } 1515 if (!ed.used_stdout) { 1516 (void) fclose (ed.fp); 1517 } 1518 } 1519 1520 return errors; 1521} 1522 1523 1524/* 1525 * add displayname protocolname hexkey 1526 */ 1527static int 1528do_add(char *inputfilename, int lineno, int argc, char **argv) 1529{ 1530 int n, nnew, nrepl; 1531 int len; 1532 char *dpyname; 1533 char *protoname; 1534 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(char *inputfilename, int lineno, int argc, 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(char *inputfilename, int lineno, int argc, 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(char *inputfilename, int lineno, int argc, 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(char *inputfilename, int lineno, int argc, 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(char *inputfilename, int lineno, int argc, char **argv) 1711{ 1712 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 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 = split_into_words (buf, &subargc); 1756 if (subargv) { 1757 status = process_command (script, sublineno, subargc, subargv); 1758 free ((char *) 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(char *inputfilename, int lineno, int argc, char **argv) 1789{ 1790 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 char *args[4]; 1799 char *protoname = "."; 1800 int i; 1801 int authdatalen = 0; 1802 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(args[3]); /* hex data */ 1931 XCloseDisplay(dpy); 1932 return status; 1933} 1934