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