process.c revision c06e8ac6
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 sprintf (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 if (strlen(authfilename) > 1022) { 718 fprintf (stderr, "%s: authority file name \"%s\" too long\n", 719 ProgramName, authfilename); 720 } 721 xauth_filename = authfilename; /* used in cleanup, prevent race with 722 signals */ 723 register_signals (); 724 725 bzero ((char *) hexvalues, sizeof hexvalues); 726 hexvalues['0'] = 0; 727 hexvalues['1'] = 1; 728 hexvalues['2'] = 2; 729 hexvalues['3'] = 3; 730 hexvalues['4'] = 4; 731 hexvalues['5'] = 5; 732 hexvalues['6'] = 6; 733 hexvalues['7'] = 7; 734 hexvalues['8'] = 8; 735 hexvalues['9'] = 9; 736 hexvalues['a'] = hexvalues['A'] = 0xa; 737 hexvalues['b'] = hexvalues['B'] = 0xb; 738 hexvalues['c'] = hexvalues['C'] = 0xc; 739 hexvalues['d'] = hexvalues['D'] = 0xd; 740 hexvalues['e'] = hexvalues['E'] = 0xe; 741 hexvalues['f'] = hexvalues['F'] = 0xf; 742 743 if (break_locks && verbose) { 744 printf ("Attempting to break locks on authority file %s\n", 745 authfilename); 746 } 747 748 if (ignore_locks) { 749 if (break_locks) XauUnlockAuth (authfilename); 750 } else { 751 n = XauLockAuth (authfilename, XAUTH_DEFAULT_RETRIES, 752 XAUTH_DEFAULT_TIMEOUT, 753 (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME)); 754 if (n != LOCK_SUCCESS) { 755 const char *reason = "unknown error"; 756 switch (n) { 757 case LOCK_ERROR: 758 reason = "error"; 759 break; 760 case LOCK_TIMEOUT: 761 reason = "timeout"; 762 break; 763 } 764 fprintf (stderr, "%s: %s in locking authority file %s\n", 765 ProgramName, reason, authfilename); 766 return -1; 767 } else 768 xauth_locked = True; 769 } 770 771 /* these checks can only be done reliably after the file is locked */ 772 exists = (access (authfilename, F_OK) == 0); 773 if (exists && access (authfilename, W_OK) != 0) { 774 fprintf (stderr, 775 "%s: %s not writable, changes will be ignored\n", 776 ProgramName, authfilename); 777 xauth_allowed = False; 778 } 779 780 original_umask = umask (0077); /* disallow non-owner access */ 781 782 authfp = fopen (authfilename, "rb"); 783 if (!authfp) { 784 int olderrno = errno; 785 786 /* if file there then error */ 787 if (access (authfilename, F_OK) == 0) { /* then file does exist! */ 788 errno = olderrno; 789 return -1; 790 } /* else ignore it */ 791 fprintf (stderr, 792 "%s: file %s does not exist\n", 793 ProgramName, authfilename); 794 } else { 795 AuthList *head, *tail; 796 797 xauth_existed = True; 798 n = read_auth_entries (authfp, False, &head, &tail); 799 (void) fclose (authfp); 800 if (n < 0) { 801 fprintf (stderr, 802 "%s: unable to read auth entries from file \"%s\"\n", 803 ProgramName, authfilename); 804 return -1; 805 } 806 xauth_head = head; 807 } 808 809 xauth_filename = strdup(authfilename); 810 if (!xauth_filename) { 811 fprintf(stderr,"cannot allocate memory\n"); 812 return -1; 813 } 814 815 xauth_modified = False; 816 817 if (verbose) { 818 printf ("%s authority file %s\n", 819 ignore_locks ? "Ignoring locks on" : "Using", authfilename); 820 } 821 return 0; 822} 823 824static int 825write_auth_file(char *tmp_nam) 826{ 827 FILE *fp = NULL; 828 int fd; 829 830 /* 831 * xdm and auth spec assumes auth file is 12 or fewer characters 832 */ 833 strcpy (tmp_nam, xauth_filename); 834 strcat (tmp_nam, "-n"); /* for new */ 835 (void) unlink (tmp_nam); 836 /* CPhipps 2000/02/12 - fix file unlink/fopen race */ 837 fd = open(tmp_nam, O_WRONLY | O_CREAT | O_EXCL, 0600); 838 if (fd != -1) fp = fdopen (fd, "wb"); 839 if (!fp) { 840 if (fd != -1) close(fd); 841 fprintf (stderr, "%s: unable to open tmp file \"%s\"\n", 842 ProgramName, tmp_nam); 843 return -1; 844 } 845 846 /* 847 * Write MIT-MAGIC-COOKIE-1 first, because R4 Xlib knows 848 * only that and uses the first authorization it finds. 849 */ 850 for (AuthList *list = xauth_head; list; list = list->next) { 851 if (list->auth->name_length == 18 852 && strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) == 0) { 853 if (!XauWriteAuth(fp, list->auth)) { 854 (void) fclose(fp); 855 return -1; 856 } 857 } 858 } 859 for (AuthList *list = xauth_head; list; list = list->next) { 860 if (list->auth->name_length != 18 861 || strncmp(list->auth->name, "MIT-MAGIC-COOKIE-1", 18) != 0) { 862 if (!XauWriteAuth(fp, list->auth)) { 863 (void) fclose(fp); 864 return -1; 865 } 866 } 867 } 868 869 if (fclose(fp)) { 870 return -1; 871 } 872 873 return 0; 874} 875 876int 877auth_finalize(void) 878{ 879 if (xauth_modified) { 880 if (dying) { 881 if (verbose) { 882 /* 883 * called from a signal handler -- printf is *not* reentrant; also 884 * fileno() might not be reentrant, avoid it if possible, and use 885 * stderr instead of stdout 886 */ 887#ifdef STDERR_FILENO 888 WRITES(STDERR_FILENO, "\nAborting changes to authority file "); 889 WRITES(STDERR_FILENO, xauth_filename); 890 WRITES(STDERR_FILENO, "\n"); 891#else 892 WRITES(fileno(stderr), "\nAborting changes to authority file "); 893 WRITES(fileno(stderr), xauth_filename); 894 WRITES(fileno(stderr), "\n"); 895#endif 896 } 897 } else if (!xauth_allowed) { 898 fprintf (stderr, 899 "%s: %s not writable, changes ignored\n", 900 ProgramName, xauth_filename); 901 } else { 902 char temp_name[1025]; /* large filename size */ 903 904 if (verbose) { 905 printf ("%s authority file %s\n", 906 ignore_locks ? "Ignoring locks and writing" : 907 "Writing", xauth_filename); 908 } 909 temp_name[0] = '\0'; 910 if (write_auth_file (temp_name) == -1) { 911 fprintf (stderr, 912 "%s: unable to write authority file %s\n", 913 ProgramName, temp_name); 914 } else { 915 if (rename(temp_name, xauth_filename) == -1) { 916 fprintf (stderr, 917 "%s: unable to rename authority file %s, use %s\n", 918 ProgramName, xauth_filename, temp_name); 919 unlink(temp_name); 920 } 921 } 922 } 923 } 924 925 if (xauth_locked) { 926 XauUnlockAuth (xauth_filename); 927 } 928 (void) umask (original_umask); 929 return 0; 930} 931 932int 933process_command(const char *inputfilename, int lineno, int argc, const char **argv) 934{ 935 int status; 936 937 if (argc < 1 || !argv || !argv[0]) return 1; 938 939 if (dispatch_command (inputfilename, lineno, argc, argv, 940 command_table, &status)) 941 return status; 942 943 prefix (inputfilename, lineno); 944 fprintf (stderr, "unknown command \"%s\"\n", argv[0]); 945 return 1; 946} 947 948 949/* 950 * utility routines 951 */ 952 953static char * 954bintohex(unsigned int len, const char *bindata) 955{ 956 char *hexdata, *starthex; 957 958 /* two chars per byte, plus null termination */ 959 starthex = hexdata = malloc((2 * len) + 1); 960 if (!hexdata) 961 return NULL; 962 963 for (; len > 0; len--, bindata++) { 964 register const char *s = hex_table[(unsigned char)*bindata]; 965 *hexdata++ = s[0]; 966 *hexdata++ = s[1]; 967 } 968 *hexdata = '\0'; 969 return starthex; 970} 971 972static void 973fprintfhex(register FILE *fp, int len, char *cp) 974{ 975 char *hex; 976 977 hex = bintohex(len, cp); 978 fprintf(fp, "%s", hex); 979 free(hex); 980} 981 982static int 983dump_numeric(register FILE *fp, register Xauth *auth) 984{ 985 fprintf (fp, "%04x", auth->family); /* unsigned short */ 986 fprintf (fp, " %04x ", auth->address_length); /* short */ 987 fprintfhex (fp, auth->address_length, auth->address); 988 fprintf (fp, " %04x ", auth->number_length); /* short */ 989 fprintfhex (fp, auth->number_length, auth->number); 990 fprintf (fp, " %04x ", auth->name_length); /* short */ 991 fprintfhex (fp, auth->name_length, auth->name); 992 fprintf (fp, " %04x ", auth->data_length); /* short */ 993 fprintfhex (fp, auth->data_length, auth->data); 994 putc ('\n', fp); 995 return 1; 996} 997 998/* ARGSUSED */ 999static int 1000dump_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 1001{ 1002 struct _list_data *ld = (struct _list_data *) data; 1003 FILE *fp = ld->fp; 1004 1005 if (ld->numeric) { 1006 dump_numeric (fp, auth); 1007 } else { 1008 const char *dpyname = NULL; 1009 1010 switch (auth->family) { 1011 case FamilyLocal: 1012 fwrite (auth->address, sizeof (char), auth->address_length, fp); 1013 fprintf (fp, "/unix"); 1014 break; 1015 case FamilyInternet: 1016#if defined(IPv6) && defined(AF_INET6) 1017 case FamilyInternet6: 1018#endif 1019 case FamilyDECnet: 1020 dpyname = get_hostname (auth); 1021 if (dpyname) { 1022 fprintf (fp, "%s", dpyname); 1023 break; 1024 } 1025 /* else fall through */ 1026 default: 1027 fprintf (fp, "#%04x#", auth->family); 1028 fprintfhex (fp, auth->address_length, auth->address); 1029 putc ('#', fp); 1030 } 1031 putc (':', fp); 1032 fwrite (auth->number, sizeof (char), auth->number_length, fp); 1033 putc (' ', fp); 1034 putc (' ', fp); 1035 fwrite (auth->name, sizeof (char), auth->name_length, fp); 1036 putc (' ', fp); 1037 putc (' ', fp); 1038 if (!strncmp(auth->name, SECURERPC, auth->name_length) || 1039 !strncmp(auth->name, K5AUTH, auth->name_length)) 1040 fwrite (auth->data, sizeof (char), auth->data_length, fp); 1041 else 1042 fprintfhex (fp, auth->data_length, auth->data); 1043 putc ('\n', fp); 1044 } 1045 return 0; 1046} 1047 1048static int 1049extract_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 1050{ 1051 struct _extract_data *ed = (struct _extract_data *) data; 1052 1053 if (!ed->fp) { 1054 ed->fp = open_file (&ed->filename, 1055 ed->numeric ? "w" : "wb", 1056 &ed->used_stdout, 1057 inputfilename, lineno, ed->cmd); 1058 if (!ed->fp) { 1059 prefix (inputfilename, lineno); 1060 fprintf (stderr, 1061 "unable to open extraction file \"%s\"\n", 1062 ed->filename); 1063 return -1; 1064 } 1065 } 1066 (*(ed->numeric ? dump_numeric : XauWriteAuth)) (ed->fp, auth); 1067 ed->nwritten++; 1068 1069 return 0; 1070} 1071 1072 1073static int 1074eq_auth_dpy_and_name(Xauth *a, Xauth *b) 1075{ 1076 return((a->family == b->family && 1077 a->address_length == b->address_length && 1078 a->number_length == b->number_length && 1079 a->name_length == b->name_length && 1080 memcmp(a->address, b->address, a->address_length) == 0 && 1081 memcmp(a->number, b->number, a->number_length) == 0 && 1082 memcmp(a->name, b->name, a->name_length) == 0) ? 1 : 0); 1083} 1084 1085static int 1086eq_auth(Xauth *a, Xauth *b) 1087{ 1088 return((eq_auth_dpy_and_name(a, b) && 1089 a->data_length == b->data_length && 1090 memcmp(a->data, b->data, a->data_length) == 0) ? 1 : 0); 1091} 1092 1093static int 1094match_auth_dpy(register Xauth *a, register Xauth *b) 1095{ 1096 if (a->family != FamilyWild && b->family != FamilyWild) { 1097 /* Both "a" and "b" are not FamilyWild, they are "normal" families. */ 1098 1099 /* Make sure, that both families match: */ 1100 if (a->family != b->family) 1101 return 0; 1102 1103 /* By looking at 'man Xsecurity' and the code in 1104 * GetAuthByAddr() and XauGetBestAuthByAddr() in libXau, we 1105 * decided, that the address is only relevant for "normal" 1106 * families and therefore should be ignored for 1107 * "FamilyWild". */ 1108 if (a->address_length != b->address_length || 1109 memcmp(a->address, b->address, a->address_length) != 0) 1110 return 0; 1111 } 1112 1113 if (a->number_length != 0 && b->number_length != 0) { 1114 /* Both "a" and "b" have a number, make sure they match: */ 1115 if (a->number_length != b->number_length || 1116 memcmp(a->number, b->number, a->number_length) != 0) 1117 return 0; 1118 } 1119 1120 return 1; 1121} 1122 1123static int 1124merge_entries(AuthList **firstp, AuthList *second, int *nnewp, int *nreplp) 1125{ 1126 AuthList *first, *tail; 1127 int n = 0, nnew = 0, nrepl = 0; 1128 1129 if (!second) return 0; 1130 1131 if (!*firstp) { /* if nothing to merge into */ 1132 *firstp = second; 1133 for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ; 1134 *nnewp = n; 1135 *nreplp = 0; 1136 return n; 1137 } 1138 1139 first = *firstp; 1140 /* 1141 * find end of first list and stick second list on it 1142 */ 1143 for (tail = first; tail->next; tail = tail->next) ; 1144 tail->next = second; 1145 1146 /* 1147 * run down list freeing duplicate entries; if an entry is okay, then 1148 * bump the tail up to include it, otherwise, cut the entry out of 1149 * the chain. 1150 */ 1151 for (AuthList *b = second; b; ) { 1152 AuthList *next = b->next; /* in case we free it */ 1153 AuthList *a = first; 1154 1155 for (;;) { 1156 if (eq_auth_dpy_and_name (a->auth, b->auth)) { /* found a duplicate */ 1157 AuthList tmp; /* swap it in for old one */ 1158 tmp = *a; 1159 *a = *b; 1160 *b = tmp; 1161 a->next = b->next; 1162 XauDisposeAuth (b->auth); 1163 free ((char *) b); 1164 b = NULL; 1165 tail->next = next; 1166 nrepl++; 1167 nnew--; 1168 break; 1169 } 1170 if (a == tail) break; /* if have looked at left side */ 1171 a = a->next; 1172 } 1173 if (b) { /* if we didn't remove it */ 1174 tail = b; /* bump end of first list */ 1175 } 1176 b = next; 1177 n++; 1178 nnew++; 1179 } 1180 1181 *nnewp = nnew; 1182 *nreplp = nrepl; 1183 return n; 1184 1185} 1186 1187static void 1188sort_entries(AuthList **firstp) 1189{ 1190 /* Insert sort, in each pass it removes auth records of certain */ 1191 /* cathegory from the given list and inserts them into the sorted list. */ 1192 1193 AuthList *sorted = NULL, *sorted_tail = NULL; 1194 1195 #define SORT_OUT(EXPRESSION) { \ 1196 AuthList *prev = NULL, *next; \ 1197 for (AuthList *iter = *firstp; iter; iter = next) { \ 1198 next = iter->next; \ 1199 if (EXPRESSION) { \ 1200 if (prev) \ 1201 prev->next = next; \ 1202 else \ 1203 *firstp = next; \ 1204 if (sorted_tail == NULL) { \ 1205 sorted = sorted_tail = iter; \ 1206 } else { \ 1207 sorted_tail->next = iter; \ 1208 sorted_tail = iter; \ 1209 } \ 1210 iter->next = NULL; \ 1211 } else { \ 1212 prev = iter; \ 1213 } \ 1214 } \ 1215 } 1216 1217 SORT_OUT(iter->auth->family != FamilyWild && iter->auth->number_length != 0); 1218 SORT_OUT(iter->auth->family != FamilyWild && iter->auth->number_length == 0); 1219 SORT_OUT(iter->auth->family == FamilyWild && iter->auth->number_length != 0); 1220 SORT_OUT(iter->auth->family == FamilyWild && iter->auth->number_length == 0); 1221 1222 *firstp = sorted; 1223} 1224 1225static Xauth * 1226copyAuth(Xauth *auth) 1227{ 1228 Xauth *a; 1229 1230 a = malloc(sizeof(Xauth)); 1231 if (a == NULL) { 1232 return NULL; 1233 } 1234 memset(a, 0, sizeof(Xauth)); 1235 a->family = auth->family; 1236 if (auth->address_length != 0) { 1237 a->address = malloc(auth->address_length); 1238 if (a->address == NULL) { 1239 free(a); 1240 return NULL; 1241 } 1242 memcpy(a->address, auth->address, auth->address_length); 1243 a->address_length = auth->address_length; 1244 } 1245 if (auth->number_length != 0) { 1246 a->number = malloc(auth->number_length); 1247 if (a->number == NULL) { 1248 free(a->address); 1249 free(a); 1250 return NULL; 1251 } 1252 memcpy(a->number, auth->number, auth->number_length); 1253 a->number_length = auth->number_length; 1254 } 1255 if (auth->name_length != 0) { 1256 a->name = malloc(auth->name_length); 1257 if (a->name == NULL) { 1258 free(a->address); 1259 free(a->number); 1260 free(a); 1261 return NULL; 1262 } 1263 memcpy(a->name, auth->name, auth->name_length); 1264 a->name_length = auth->name_length; 1265 } 1266 if (auth->data_length != 0) { 1267 a->data = malloc(auth->data_length); 1268 if (a->data == NULL) { 1269 free(a->address); 1270 free(a->number); 1271 free(a->name); 1272 free(a); 1273 return NULL; 1274 } 1275 memcpy(a->data, auth->data, auth->data_length); 1276 a->data_length = auth->data_length; 1277 } 1278 return a; 1279} 1280 1281typedef int (*YesNoFunc)(const char *, int, Xauth *, char *); 1282 1283static int 1284iterdpy (const char *inputfilename, int lineno, int start, 1285 int argc, const char *argv[], 1286 YesNoFunc yfunc, YesNoFunc nfunc, char *data) 1287{ 1288 int errors = 0; 1289 1290 /* 1291 * iterate 1292 */ 1293 for (int i = start; i < argc; i++) { 1294 const char *displayname = argv[i]; 1295 AuthList *proto_head; 1296 AuthList *next; 1297 int status; 1298 1299 if (!get_displayname_auth (displayname, &proto_head)) { 1300 prefix (inputfilename, lineno); 1301 baddisplayname (displayname, argv[0]); 1302 errors++; 1303 continue; 1304 } 1305 status = 0; 1306 for (AuthList *l = xauth_head; l; l = next) { 1307 Bool matched = False; 1308 Xauth *tmp_auth; 1309 1310 /* l may be freed by remove_entry below. so save its contents */ 1311 next = l->next; 1312 tmp_auth = copyAuth(l->auth); 1313 for (AuthList *proto = proto_head; proto; proto = proto->next) { 1314 if (match_auth_dpy (proto->auth, tmp_auth)) { 1315 matched = True; 1316 if (yfunc) { 1317 status = (*yfunc) (inputfilename, lineno, 1318 tmp_auth, data); 1319 if (status < 0) break; 1320 } 1321 } 1322 } 1323 XauDisposeAuth(tmp_auth); 1324 if (matched == False) { 1325 if (nfunc) { 1326 status = (*nfunc) (inputfilename, lineno, 1327 l->auth, data); 1328 } 1329 } 1330 if (status < 0) break; 1331 } 1332 for (AuthList *proto = proto_head; proto ; proto = next) { 1333 next = proto->next; 1334 if (proto->auth->address) free (proto->auth->address); 1335 if (proto->auth->number) free (proto->auth->number); 1336 free (proto->auth); 1337 free (proto); 1338 } 1339 if (status < 0) { 1340 errors -= status; /* since status is negative */ 1341 break; 1342 } 1343 } 1344 1345 return errors; 1346} 1347 1348/* ARGSUSED */ 1349static int 1350remove_entry(const char *inputfilename, int lineno, Xauth *auth, char *data) 1351{ 1352 int *nremovedp = (int *) data; 1353 AuthList **listp = &xauth_head; 1354 AuthList *list; 1355 1356 /* 1357 * unlink the auth we were asked to 1358 */ 1359 while (!eq_auth((list = *listp)->auth, auth)) { 1360 listp = &list->next; 1361 if (!*listp) 1362 return 0; 1363 } 1364 *listp = list->next; 1365 XauDisposeAuth (list->auth); /* free the auth */ 1366 free (list); /* free the link */ 1367 xauth_modified = True; 1368 (*nremovedp)++; 1369 return 1; 1370} 1371 1372/* 1373 * action routines 1374 */ 1375 1376/* 1377 * help 1378 */ 1379int 1380print_help(FILE *fp, const char *cmd, const char *line_prefix) 1381{ 1382 int n = 0; 1383 1384 if (!line_prefix) line_prefix = ""; 1385 1386 if (!cmd) { /* if no cmd, print all help */ 1387 for (CommandTable *ct = command_table; ct->name; ct++) { 1388 fprintf (fp, "%s%s\n", line_prefix, ct->helptext); 1389 n++; 1390 } 1391 } else { 1392 int len = strlen (cmd); 1393 for (CommandTable *ct = command_table; ct->name; ct++) { 1394 if (strncmp (cmd, ct->name, len) == 0) { 1395 fprintf (fp, "%s%s\n", line_prefix, ct->helptext); 1396 n++; 1397 } 1398 } 1399 } 1400 1401 return n; 1402} 1403 1404static int 1405do_help(const char *inputfilename, int lineno, int argc, const char **argv) 1406{ 1407 const char *cmd = (argc > 1 ? argv[1] : NULL); 1408 int n; 1409 1410 n = print_help (stdout, cmd, " "); /* a nice amount */ 1411 1412 if (n < 0 || (n == 0 && !cmd)) { 1413 prefix (inputfilename, lineno); 1414 fprintf (stderr, "internal error with help"); 1415 if (cmd) { 1416 fprintf (stderr, " on command \"%s\"", cmd); 1417 } 1418 fprintf (stderr, "\n"); 1419 return 1; 1420 } 1421 1422 if (n == 0) { 1423 prefix (inputfilename, lineno); 1424 /* already know that cmd is set in this case */ 1425 fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd); 1426 } 1427 1428 return 0; 1429} 1430 1431/* 1432 * questionmark 1433 */ 1434/* ARGSUSED */ 1435static int 1436do_questionmark(const char *inputfilename, int lineno, int argc, const char **argv) 1437{ 1438#define WIDEST_COLUMN 72 1439 int col = WIDEST_COLUMN; 1440 1441 printf ("Commands:\n"); 1442 for (CommandTable *ct = command_table; ct->name; ct++) { 1443 if ((col + ct->maxlen) > WIDEST_COLUMN) { 1444 if (ct != command_table) { 1445 putc ('\n', stdout); 1446 } 1447 fputs (" ", stdout); 1448 col = 8; /* length of string above */ 1449 } 1450 fputs (ct->name, stdout); 1451 col += ct->maxlen; 1452 for (int i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) { 1453 putc (' ', stdout); 1454 col++; 1455 } 1456 } 1457 if (col != 0) { 1458 putc ('\n', stdout); 1459 } 1460 1461 /* allow bad lines since this is help */ 1462 return 0; 1463} 1464 1465/* 1466 * version 1467 */ 1468/* ARGSUSED */ 1469static int 1470do_version(const char *inputfilename, int lineno, int argc, const char **argv) 1471{ 1472 puts (PACKAGE_VERSION); 1473 return 0; 1474} 1475 1476/* 1477 * list [displayname ...] 1478 */ 1479static int 1480do_list (const char *inputfilename, int lineno, int argc, const char **argv) 1481{ 1482 struct _list_data ld; 1483 1484 ld.fp = stdout; 1485 ld.numeric = (argv[0][0] == 'n'); 1486 1487 if (argc == 1) { 1488 if (xauth_head) { 1489 for (AuthList *l = xauth_head; l; l = l->next) { 1490 dump_entry (inputfilename, lineno, l->auth, (char *) &ld); 1491 } 1492 } 1493 return 0; 1494 } 1495 1496 return iterdpy (inputfilename, lineno, 1, argc, argv, 1497 dump_entry, NULL, (char *) &ld); 1498} 1499 1500/* 1501 * merge filename [filename ...] 1502 */ 1503static int 1504do_merge(const char *inputfilename, int lineno, int argc, const char **argv) 1505{ 1506 int errors = 0; 1507 AuthList *listhead, *listtail; 1508 Bool numeric = False; 1509 1510 if (argc < 2) { 1511 prefix (inputfilename, lineno); 1512 badcommandline (argv[0]); 1513 return 1; 1514 } 1515 1516 if (argv[0][0] == 'n') numeric = True; 1517 listhead = listtail = NULL; 1518 1519 for (int i = 1; i < argc; i++) { 1520 const char *filename = argv[i]; 1521 FILE *fp; 1522 Bool used_stdin = False; 1523 int nentries; 1524 AuthList *head, *tail; 1525 1526 fp = open_file (&filename, 1527 numeric ? "r" : "rb", 1528 &used_stdin, inputfilename, lineno, 1529 argv[0]); 1530 if (!fp) { 1531 errors++; 1532 continue; 1533 } 1534 1535 head = tail = NULL; 1536 nentries = read_auth_entries (fp, numeric, &head, &tail); 1537 if (nentries == 0) { 1538 prefix (inputfilename, lineno); 1539 fprintf (stderr, "unable to read any entries from file \"%s\"\n", 1540 filename); 1541 errors++; 1542 } else { /* link it in */ 1543 add_to_list (listhead, listtail, head); 1544 } 1545 1546 if (!used_stdin) (void) fclose (fp); 1547 } 1548 1549 /* 1550 * if we have new entries, merge them in (freeing any duplicates) 1551 */ 1552 if (listhead) { 1553 int nentries, nnew, nrepl; 1554 1555 nentries = merge_entries (&xauth_head, listhead, &nnew, &nrepl); 1556 if (verbose) 1557 printf ("%d entries read in: %d new, %d replacement%s\n", 1558 nentries, nnew, nrepl, nrepl != 1 ? "s" : ""); 1559 if (nentries > 0) xauth_modified = True; 1560 sort_entries(&xauth_head); 1561 } 1562 1563 return 0; 1564} 1565 1566/* 1567 * extract filename displayname [displayname ...] 1568 */ 1569static int 1570do_extract(const char *inputfilename, int lineno, int argc, const char **argv) 1571{ 1572 int errors; 1573 struct _extract_data ed; 1574 1575 if (argc < 3) { 1576 prefix (inputfilename, lineno); 1577 badcommandline (argv[0]); 1578 return 1; 1579 } 1580 1581 ed.fp = NULL; 1582 ed.filename = argv[1]; 1583 ed.used_stdout = False; 1584 ed.numeric = (argv[0][0] == 'n'); 1585 ed.nwritten = 0; 1586 ed.cmd = argv[0]; 1587 1588 errors = iterdpy (inputfilename, lineno, 2, argc, argv, 1589 extract_entry, NULL, (char *) &ed); 1590 1591 if (!ed.fp) { 1592 fprintf (stderr, 1593 "No matches found, authority file \"%s\" not written\n", 1594 ed.filename); 1595 } else { 1596 if (verbose) { 1597 printf ("%d entries written to \"%s\"\n", 1598 ed.nwritten, ed.filename); 1599 } 1600 if (!ed.used_stdout) { 1601 (void) fclose (ed.fp); 1602 } 1603 } 1604 1605 return errors; 1606} 1607 1608 1609/* 1610 * add displayname protocolname hexkey 1611 */ 1612 1613static int 1614do_add(const char *inputfilename, int lineno, int argc, const char **argv) 1615{ 1616 int n, nnew, nrepl; 1617 int len; 1618 const char *dpyname; 1619 const char *protoname; 1620 const char *hexkey; 1621 char *key; 1622 AuthList *list, *list_cur, *list_next; 1623 1624 if (argc != 4 || !argv[1] || !argv[2] || !argv[3]) { 1625 prefix (inputfilename, lineno); 1626 badcommandline (argv[0]); 1627 return 1; 1628 } 1629 1630 dpyname = argv[1]; 1631 protoname = argv[2]; 1632 hexkey = argv[3]; 1633 1634 len = strlen(hexkey); 1635 if (len > 1 && hexkey[0] == '"' && hexkey[len-1] == '"') { 1636 key = malloc(len-1); 1637 if (!key) { 1638 fprintf(stderr, "unable to allocate memory\n"); 1639 return 1; 1640 } 1641 strncpy(key, hexkey+1, len-2); 1642 key[len-2] = '\0'; 1643 len -= 2; 1644 } else if (!strcmp(protoname, SECURERPC) || 1645 !strcmp(protoname, K5AUTH)) { 1646 key = malloc(len+1); 1647 if (!key) { 1648 fprintf(stderr, "unable to allocate memory\n"); 1649 return 1; 1650 } 1651 strcpy(key, hexkey); 1652 } else { 1653 len = cvthexkey (hexkey, &key); 1654 if (len < 0) { 1655 prefix (inputfilename, lineno); 1656 fprintf (stderr, 1657 "key contains odd number of or non-hex characters\n"); 1658 return 1; 1659 } 1660 } 1661 1662 if (!get_displayname_auth (dpyname, &list)) { 1663 prefix (inputfilename, lineno); 1664 baddisplayname (dpyname, argv[0]); 1665 free (key); 1666 return 1; 1667 } 1668 1669 /* 1670 * allow an abbreviation for common protocol names 1671 */ 1672 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) { 1673 protoname = DEFAULT_PROTOCOL; 1674 } 1675 1676 for (list_cur = list; list_cur != NULL; list_cur = list_cur->next) { 1677 Xauth *auth = list_cur->auth; 1678 1679 auth->name_length = strlen (protoname); 1680 auth->name = copystring (protoname, auth->name_length); 1681 if (!auth->name) { 1682 prefix (inputfilename, lineno); 1683 fprintf (stderr, "unable to allocate %d character protocol name\n", 1684 auth->name_length); 1685 for (list_cur = list; list_cur != NULL; list_cur = list_next) { 1686 list_next = list_cur->next; 1687 XauDisposeAuth(list_cur->auth); 1688 free(list_cur); 1689 } 1690 free (key); 1691 return 1; 1692 } 1693 auth->data_length = len; 1694 auth->data = malloc(len); 1695 if (!auth->data) { 1696 prefix(inputfilename, lineno); 1697 fprintf(stderr, "unable to allocate %d bytes for key\n", len); 1698 for (list_cur = list; list_cur != NULL; list_cur = list_next) { 1699 list_next = list_cur->next; 1700 XauDisposeAuth(list_cur->auth); 1701 free(list_cur); 1702 } 1703 free(key); 1704 return 1; 1705 } 1706 memcpy(auth->data, key, len); 1707 } 1708 free(key); 1709 /* 1710 * merge it in; note that merge will deal with allocation 1711 */ 1712 n = merge_entries (&xauth_head, list, &nnew, &nrepl); 1713 if (n <= 0) { 1714 prefix (inputfilename, lineno); 1715 fprintf (stderr, "unable to merge in added record\n"); 1716 return 1; 1717 } 1718 sort_entries(&xauth_head); 1719 1720 xauth_modified = True; 1721 return 0; 1722} 1723 1724/* 1725 * remove displayname 1726 */ 1727static int 1728do_remove(const char *inputfilename, int lineno, int argc, const char **argv) 1729{ 1730 int nremoved = 0; 1731 int errors; 1732 1733 if (argc < 2) { 1734 prefix (inputfilename, lineno); 1735 badcommandline (argv[0]); 1736 return 1; 1737 } 1738 1739 errors = iterdpy (inputfilename, lineno, 1, argc, argv, 1740 remove_entry, NULL, (char *) &nremoved); 1741 if (verbose) printf ("%d entries removed\n", nremoved); 1742 return errors; 1743} 1744 1745/* 1746 * info 1747 */ 1748static int 1749do_info(const char *inputfilename, int lineno, int argc, const char **argv) 1750{ 1751 int n; 1752 AuthList *l; 1753 1754 if (argc != 1) { 1755 prefix (inputfilename, lineno); 1756 badcommandline (argv[0]); 1757 return 1; 1758 } 1759 1760 for (l = xauth_head, n = 0; l; l = l->next, n++) ; 1761 1762 printf ("Authority file: %s\n", 1763 xauth_filename ? xauth_filename : "(none)"); 1764 printf ("File new: %s\n", xauth_existed ? No : Yes); 1765 printf ("File locked: %s\n", xauth_locked ? No : Yes); 1766 printf ("Number of entries: %d\n", n); 1767 printf ("Changes honored: %s\n", xauth_allowed ? Yes : No); 1768 printf ("Changes made: %s\n", xauth_modified ? Yes : No); 1769 printf ("Current input: %s:%d\n", inputfilename, lineno); 1770 return 0; 1771} 1772 1773 1774/* 1775 * exit 1776 */ 1777static Bool alldone = False; 1778 1779/* ARGSUSED */ 1780static int 1781do_exit(const char *inputfilename, int lineno, int argc, const char **argv) 1782{ 1783 /* allow bogus stuff */ 1784 alldone = True; 1785 return 0; 1786} 1787 1788/* 1789 * quit 1790 */ 1791/* ARGSUSED */ 1792static int 1793do_quit(const char *inputfilename, int lineno, int argc, const char **argv) 1794{ 1795 /* allow bogus stuff */ 1796 die (0); 1797 /* NOTREACHED */ 1798 return -1; /* for picky compilers */ 1799} 1800 1801 1802/* 1803 * source filename 1804 */ 1805static int 1806do_source(const char *inputfilename, int lineno, int argc, const char **argv) 1807{ 1808 const char *script; 1809 FILE *fp; 1810 Bool used_stdin = False; 1811 int errors = 0; 1812 int sublineno = 0; 1813 Bool prompt = False; /* only true if reading from tty */ 1814 1815 if (argc != 2 || !argv[1]) { 1816 prefix (inputfilename, lineno); 1817 badcommandline (argv[0]); 1818 return 1; 1819 } 1820 1821 script = argv[1]; 1822 1823 fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]); 1824 if (!fp) { 1825 return 1; 1826 } 1827 1828 if (verbose && used_stdin && isatty (fileno (fp))) prompt = True; 1829 1830 while (!alldone) { 1831 char buf[BUFSIZ]; 1832 int len; 1833 const char **subargv; 1834 int subargc; 1835 1836 buf[0] = '\0'; 1837 if (prompt) { 1838 printf ("xauth> "); 1839 fflush (stdout); 1840 } 1841 if (fgets (buf, sizeof buf, fp) == NULL) break; 1842 sublineno++; 1843 len = strlen (buf); 1844 if (len == 0 || buf[0] == '#') continue; 1845 if (buf[len-1] != '\n') { 1846 prefix (script, sublineno); 1847 fprintf (stderr, "line too long\n"); 1848 errors++; 1849 break; 1850 } 1851 buf[--len] = '\0'; /* remove new line */ 1852 subargv = (const char **) split_into_words (buf, &subargc); 1853 if (subargv) { 1854 int status = process_command (script, sublineno, subargc, subargv); 1855 errors += status; 1856 free (subargv); 1857 } else { 1858 prefix (script, sublineno); 1859 fprintf (stderr, "unable to break line into words\n"); 1860 errors++; 1861 } 1862 } 1863 1864 if (!used_stdin) { 1865 (void) fclose (fp); 1866 } 1867 return errors; 1868} 1869 1870static int x_protocol_error; 1871static int 1872catch_x_protocol_error(Display *dpy, XErrorEvent *errevent) 1873{ 1874 char buf[80]; 1875 XGetErrorText(dpy, errevent->error_code, buf, sizeof (buf)); 1876 fprintf(stderr, "%s\n", buf); 1877 x_protocol_error = errevent->error_code; 1878 return 1; 1879} 1880 1881/* 1882 * generate 1883 */ 1884static int 1885do_generate(const char *inputfilename, int lineno, int argc, const char **argv) 1886{ 1887 const char *displayname; 1888 int major_version, minor_version; 1889 XSecurityAuthorization id_return; 1890 Xauth *auth_in = NULL, *auth_return = NULL; 1891 XSecurityAuthorizationAttributes attributes; 1892 unsigned long attrmask = 0; 1893 Display *dpy = NULL; 1894 int status; 1895 const char *args[4]; 1896 const char *protoname = "."; 1897 int authdatalen = 0; 1898 const char *hexdata; 1899 char *authdata = NULL; 1900 char *hex = NULL; 1901 1902 if (argc < 2 || !argv[1]) { 1903 prefix (inputfilename, lineno); 1904 badcommandline (argv[0]); 1905 return 1; 1906 } 1907 1908 displayname = argv[1]; 1909 1910 if (argc > 2) { 1911 protoname = argv[2]; 1912 } 1913 1914 for (int i = 3; i < argc; i++) { 1915 if (0 == strcmp(argv[i], "timeout")) { 1916 if (++i == argc) { 1917 prefix (inputfilename, lineno); 1918 badcommandline (argv[i-1]); 1919 status = 1; 1920 goto exit_generate; 1921 } 1922 attributes.timeout = atoi(argv[i]); 1923 attrmask |= XSecurityTimeout; 1924 1925 } else if (0 == strcmp(argv[i], "trusted")) { 1926 attributes.trust_level = XSecurityClientTrusted; 1927 attrmask |= XSecurityTrustLevel; 1928 1929 } else if (0 == strcmp(argv[i], "untrusted")) { 1930 attributes.trust_level = XSecurityClientUntrusted; 1931 attrmask |= XSecurityTrustLevel; 1932 1933 } else if (0 == strcmp(argv[i], "group")) { 1934 if (++i == argc) { 1935 prefix (inputfilename, lineno); 1936 badcommandline (argv[i-1]); 1937 status = 1; 1938 goto exit_generate; 1939 } 1940 attributes.group = atoi(argv[i]); 1941 attrmask |= XSecurityGroup; 1942 1943 } else if (0 == strcmp(argv[i], "data")) { 1944 if (++i == argc) { 1945 prefix (inputfilename, lineno); 1946 badcommandline (argv[i-1]); 1947 status = 1; 1948 goto exit_generate; 1949 } 1950 hexdata = argv[i]; 1951 authdatalen = strlen(hexdata); 1952 if (hexdata[0] == '"' && hexdata[authdatalen-1] == '"') { 1953 authdata = malloc(authdatalen-1); 1954 if (!authdata) { 1955 fprintf(stderr, "unable to allocate memory\n"); 1956 status = 1; 1957 goto exit_generate; 1958 } 1959 strncpy(authdata, hexdata+1, authdatalen-2); 1960 authdata[authdatalen-2] = '\0'; 1961 authdatalen -= 2; 1962 } else { 1963 authdatalen = cvthexkey (hexdata, &authdata); 1964 if (authdatalen < 0) { 1965 prefix (inputfilename, lineno); 1966 fprintf (stderr, 1967 "data contains odd number of or non-hex characters\n"); 1968 status = 1; 1969 goto exit_generate; 1970 } 1971 } 1972 } else { 1973 prefix (inputfilename, lineno); 1974 badcommandline (argv[i]); 1975 status = 1; 1976 goto exit_generate; 1977 } 1978 } 1979 1980 /* generate authorization using the Security extension */ 1981 1982 dpy = XOpenDisplay (displayname); 1983 if (!dpy) { 1984 prefix (inputfilename, lineno); 1985 fprintf (stderr, "unable to open display \"%s\".\n", displayname); 1986 status = 1; 1987 goto exit_generate; 1988 } 1989 1990 status = XSecurityQueryExtension(dpy, &major_version, &minor_version); 1991 if (!status) 1992 { 1993 prefix (inputfilename, lineno); 1994 fprintf (stderr, "couldn't query Security extension on display \"%s\"\n", 1995 displayname); 1996 status = 1; 1997 goto exit_generate; 1998 } 1999 2000 /* fill in input Xauth struct */ 2001 2002 auth_in = XSecurityAllocXauth(); 2003 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) { 2004 auth_in->name = copystring(DEFAULT_PROTOCOL, strlen(DEFAULT_PROTOCOL)); 2005 } 2006 else 2007 auth_in->name = copystring (protoname, strlen(protoname)); 2008 auth_in->name_length = strlen(auth_in->name); 2009 auth_in->data = authdata; 2010 auth_in->data_length = authdatalen; 2011 2012 x_protocol_error = 0; 2013 XSetErrorHandler(catch_x_protocol_error); 2014 auth_return = XSecurityGenerateAuthorization(dpy, auth_in, attrmask, 2015 &attributes, &id_return); 2016 XSync(dpy, False); 2017 2018 if (!auth_return || x_protocol_error) 2019 { 2020 prefix (inputfilename, lineno); 2021 fprintf (stderr, "couldn't generate authorization\n"); 2022 status = 1; 2023 goto exit_generate; 2024 } 2025 2026 if (verbose) 2027 printf("authorization id is %ld\n", id_return); 2028 2029 /* create a fake input line to give to do_add */ 2030 hex = bintohex(auth_return->data_length, auth_return->data); 2031 args[0] = "add"; 2032 args[1] = displayname; 2033 args[2] = auth_in->name; 2034 args[3] = hex; 2035 2036 status = do_add(inputfilename, lineno, 4, args); 2037 2038 exit_generate: 2039 free(authdata); 2040 XSecurityFreeXauth(auth_in); 2041 XSecurityFreeXauth(auth_return); 2042 free(hex); 2043 if (dpy != NULL) 2044 XCloseDisplay(dpy); 2045 return status; 2046} 2047