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