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