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