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