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