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 $ */
5 Copyright 1989, 1998 The Open Group
7 Permission to use, copy, modify, distribute, and sell this software and its
8 documentation for any purpose is hereby granted without fee, provided that
9 the above copyright notice appear in all copies and that both that
10 copyright notice and this permission notice appear in supporting
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
24 Except as contained in this notice, the name of The Open Group shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
30 /* $XFree86: xc/programs/xauth/process.c,v 3.23 2003/11/25 03:15:04 dawes Exp $ */
33 * Author: Jim Fulton, MIT X Consortium
44 #include <sys/socket.h>
47 #include <X11/X.h> /* for Family constants */
50 #include <X11/extensions/security.h>
52 #ifndef DEFAULT_PROTOCOL_ABBREV /* to make add command easier */
53 #define DEFAULT_PROTOCOL_ABBREV "."
55 #ifndef DEFAULT_PROTOCOL /* for protocol abbreviation */
56 #define DEFAULT_PROTOCOL "MIT-MAGIC-COOKIE-1"
59 #define SECURERPC "SUN-DES-1"
60 #define K5AUTH "MIT-KERBEROS-5"
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 */
66 typedef struct _AuthList { /* linked list of entries */
67 struct _AuthList *next;
71 typedef int (*ProcessFunc)(char *, int, int, char**);
73 #define add_to_list(h,t,e) {if (t) (t)->next = (e); else (h) = (e); (t) = (e);}
75 typedef 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 */
83 struct _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 */
92 struct _list_data { /* for iterating */
93 FILE *fp; /* output file */
94 Bool numeric; /* format in which to write */
101 static char *stdin_filename = "(stdin)"; /* for messages */
102 static char *stdout_filename = "(stdout)"; /* for messages */
103 static char *Yes = "yes"; /* for messages */
104 static char *No = "no"; /* for messages */
106 static int do_help ( char *inputfilename, int lineno, int argc, char **argv );
107 static int do_questionmark ( char *inputfilename, int lineno, int argc, char **argv );
108 static int do_list ( char *inputfilename, int lineno, int argc, char **argv );
109 static int do_merge ( char *inputfilename, int lineno, int argc, char **argv );
110 static int do_extract ( char *inputfilename, int lineno, int argc, char **argv );
111 static int do_add ( char *inputfilename, int lineno, int argc, char **argv );
112 static int do_remove ( char *inputfilename, int lineno, int argc, char **argv );
113 static int do_info ( char *inputfilename, int lineno, int argc, char **argv );
114 static int do_exit ( char *inputfilename, int lineno, int argc, char **argv );
115 static int do_quit ( char *inputfilename, int lineno, int argc, char **argv );
116 static int do_source ( char *inputfilename, int lineno, int argc, char **argv );
117 static int do_generate ( char *inputfilename, int lineno, int argc, char **argv );
119 static 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"
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"
157 { NULL, 0, 0, NULL, NULL },
160 #define COMMAND_NAMES_PADDED_WIDTH 10 /* wider than anything above */
163 static Bool okay_to_use_stdin = True; /* set to false after using */
165 static 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",
200 static unsigned int hexvalues[256]; /* for parsing hex input */
202 static int original_umask = 0; /* for restoring */
206 * private utility procedures
210 prefix(char *fn, int n)
212 fprintf (stderr, "%s: %s:%d: ", ProgramName, fn, n);
216 baddisplayname(char *dpy, char *cmd)
218 fprintf (stderr, "bad display name \"%s\" in \"%s\" command\n",
223 badcommandline(char *cmd)
225 fprintf (stderr, "bad \"%s\" command line\n", cmd);
229 skip_space(register char *s)
233 for ( ; *s && isascii(*s) && isspace(*s); s++)
240 skip_nonspace(register char *s)
244 /* put quoting into loop if need be */
245 for ( ; *s && isascii(*s) && !isspace(*s); s++)
251 split_into_words(char *src, int *argcp) /* argvify string */
259 #define WORDSTOALLOC 4 /* most lines are short */
260 argv = (char **) malloc (WORDSTOALLOC * sizeof (char *));
261 if (!argv) return NULL;
263 total = WORDSTOALLOC;
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
272 jword = skip_space (src);
273 src = skip_nonspace (jword);
277 total += WORDSTOALLOC;
278 argv = (char **) realloc (argv, total * sizeof (char *));
279 if (!argv) return NULL;
282 if (savec) src++; /* if not last on line advance */
283 } while (jword != src);
285 argv[--cur] = NULL; /* smash empty token to end list */
292 open_file(char **filenamep,
301 if (strcmp (*filenamep, "-") == 0) {
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;
310 prefix (srcfn, srcln);
311 fprintf (stderr, "%s: stdin already in use\n", cmd);
315 *filenamep = stdout_filename;
316 return stdout; /* always okay to use stdout */
320 fp = fopen (*filenamep, mode);
322 prefix (srcfn, srcln);
323 fprintf (stderr, "%s: unable to open file %s\n", cmd, *filenamep);
333 while ((c = getc (fp)) != EOF && isascii(c) && c != '\n' && isspace(c)) ;
338 get_short(FILE *fp, unsigned short *sp) /* for reading numeric input */
342 unsigned short us = 0;
345 * read family: written with %04x
347 for (i = 0; i < 4; i++) {
348 switch (c = getinput (fp)) {
353 if (c < 0 || c > 255) return 0;
354 us = (us * 16) + hexvalues[c]; /* since msb */
361 get_bytes(FILE *fp, unsigned int n, char **ptr) /* for reading numeric input */
371 if ((c1 = getinput (fp)) == EOF || c1 == '\n' ||
372 (c2 = getinput (fp)) == EOF || c2 == '\n') {
376 *cp = (char) ((hexvalues[c1] * 16) + hexvalues[c2]);
387 read_numeric(FILE *fp)
391 auth = (Xauth *) malloc (sizeof (Xauth));
394 auth->address = NULL;
395 auth->address_length = 0;
397 auth->number_length = 0;
399 auth->name_length = 0;
401 auth->data_length = 0;
403 if (!get_short (fp, (unsigned short *) &auth->family))
405 if (!get_short (fp, (unsigned short *) &auth->address_length))
407 if (!get_bytes (fp, (unsigned int) auth->address_length, &auth->address))
409 if (!get_short (fp, (unsigned short *) &auth->number_length))
411 if (!get_bytes (fp, (unsigned int) auth->number_length, &auth->number))
413 if (!get_short (fp, (unsigned short *) &auth->name_length))
415 if (!get_bytes (fp, (unsigned int) auth->name_length, &auth->name))
417 if (!get_short (fp, (unsigned short *) &auth->data_length))
419 if (!get_bytes (fp, (unsigned int) auth->data_length, &auth->data))
422 switch (getinput (fp)) { /* get end of line */
429 if (auth) XauDisposeAuth (auth); /* won't free null pointers */
433 typedef Xauth *(*ReadFunc)(FILE *);
436 read_auth_entries(FILE *fp, Bool numeric, AuthList **headp, AuthList **tailp)
438 ReadFunc readfunc = (numeric ? read_numeric : XauReadAuth);
440 AuthList *head, *tail;
445 /* put all records into linked list */
446 while ((auth = ((*readfunc) (fp))) != NULL) {
447 AuthList *l = (AuthList *) malloc (sizeof (AuthList));
450 "%s: unable to alloc entry reading auth file\n",
456 if (tail) /* if not first time through append */
459 head = l; /* first time through, so assign */
469 get_displayname_auth(char *displayname, AuthList **authl)
472 char *host = NULL, *rest = NULL;
476 struct addrlist *addrlist_head, *addrlist_cur;
477 AuthList *authl_cur = NULL;
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
484 cp = strchr(displayname, '/');
485 if (cp && strncmp (cp, "/unix:", 6) == 0)
486 prelen = (cp - displayname);
488 if (!parse_displayname (displayname + ((prelen > 0) ? prelen + 1 : 0),
489 &family, &host, &dpynum, &scrnum, &rest)) {
493 addrlist_head = get_address_info(family, displayname, prelen, host);
495 char buf[40]; /* want to hold largest display num */
496 unsigned short dpylen;
499 sprintf (buf, "%d", dpynum);
500 dpylen = strlen (buf);
502 for (addrlist_cur = addrlist_head; addrlist_cur != NULL;
503 addrlist_cur = addrlist_cur->next) {
504 AuthList *newal = malloc(sizeof(AuthList));
505 Xauth *auth = malloc(sizeof(Xauth));
507 if ((newal == NULL) || (auth == NULL)) {
508 if (newal != NULL) free(newal);
509 if (auth != NULL) free(auth);
513 if (authl_cur == NULL) {
514 *authl = authl_cur = newal;
516 authl_cur->next = newal;
523 auth->family = addrlist_cur->family;
524 auth->address = addrlist_cur->address;
525 auth->address_length = addrlist_cur->len;
526 auth->number = copystring(buf, dpylen);
527 auth->number_length = dpylen;
529 auth->name_length = 0;
531 auth->data_length = 0;
536 if (host) free (host);
537 if (rest) free (rest);
539 if (*authl != NULL) {
547 cvthexkey(char *hexstr, char **ptrp) /* turn hex key string into octets */
557 for (s = hexstr; *s; s++) {
558 if (!isascii(*s)) return -1;
559 if (isspace(*s)) continue;
560 if (!isxdigit(*s)) return -1;
564 /* if odd then there was an error */
565 if ((len & 1) == 1) return -1;
568 /* now we know that the input is good */
570 retval = malloc (len);
572 fprintf (stderr, "%s: unable to allocate %d bytes for hexkey\n",
577 for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
579 if (isspace(c)) continue; /* already know it is ascii */
583 #define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
584 *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
586 savec = 0; /* ready for next character */
598 dispatch_command(char *inputfilename,
608 /* scan table for command */
611 for (ct = tab; ct->name; ct++) {
612 /* look for unique prefix */
613 if (n >= ct->minlen && n <= ct->maxlen &&
614 strncmp (cmd, ct->name, n) == 0) {
615 *statusp = (*(ct->processfunc))(inputfilename, lineno, argc, argv);
625 static AuthList *xauth_head = NULL; /* list of auth entries */
626 static Bool xauth_existed = False; /* if was present at initialize */
627 static Bool xauth_modified = False; /* if added, removed, or merged */
628 static Bool xauth_allowed = True; /* if allowed to write auth file */
629 static Bool xauth_locked = False; /* if has been locked */
630 static char *xauth_filename = NULL;
631 static volatile Bool dieing = False;
634 /* poor man's puts(), for under signal handlers */
635 #define WRITES(fd, S) (void)write((fd), (S), strlen((S)))
642 _exit (auth_finalize ());
644 #ifdef SIGNALRETURNSINT
645 return -1; /* for picky compilers */
653 if (sig > 0) signal (sig, die); /* re-establish signal handler */
656 * fileno() might not be reentrant, avoid it if possible, and use
657 * stderr instead of stdout
660 if (verbose && xauth_modified) WRITES(STDERR_FILENO, "\r\n");
662 if (verbose && xauth_modified) WRITES(fileno(stderr), "\r\n");
666 #ifdef SIGNALRETURNSINT
667 return -1; /* for picky compilers */
672 register_signals(void)
674 signal (SIGINT, catchsig);
675 signal (SIGTERM, catchsig);
677 signal (SIGHUP, catchsig);
680 signal (SIGPIPE, catchsig);
687 * public procedures for parsing lines of input
691 auth_initialize(char *authfilename)
694 AuthList *head, *tail;
698 xauth_filename = authfilename; /* used in cleanup, prevent race with
702 bzero ((char *) hexvalues, sizeof hexvalues);
713 hexvalues['a'] = hexvalues['A'] = 0xa;
714 hexvalues['b'] = hexvalues['B'] = 0xb;
715 hexvalues['c'] = hexvalues['C'] = 0xc;
716 hexvalues['d'] = hexvalues['D'] = 0xd;
717 hexvalues['e'] = hexvalues['E'] = 0xe;
718 hexvalues['f'] = hexvalues['F'] = 0xf;
720 if (break_locks && verbose) {
721 printf ("Attempting to break locks on authority file %s\n",
726 if (break_locks) XauUnlockAuth (authfilename);
728 n = XauLockAuth (authfilename, XAUTH_DEFAULT_RETRIES,
729 XAUTH_DEFAULT_TIMEOUT,
730 (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME));
731 if (n != LOCK_SUCCESS) {
732 char *reason = "unknown error";
741 fprintf (stderr, "%s: %s in locking authority file %s\n",
742 ProgramName, reason, authfilename);
748 /* these checks can only be done reliably after the file is locked */
749 exists = (access (authfilename, F_OK) == 0);
750 if (exists && access (authfilename, W_OK) != 0) {
752 "%s: %s not writable, changes will be ignored\n",
753 ProgramName, authfilename);
754 xauth_allowed = False;
757 original_umask = umask (0077); /* disallow non-owner access */
759 authfp = fopen (authfilename, "rb");
761 int olderrno = errno;
763 /* if file there then error */
764 if (access (authfilename, F_OK) == 0) { /* then file does exist! */
767 } /* else ignore it */
769 "%s: file %s does not exist\n",
770 ProgramName, authfilename);
772 xauth_existed = True;
773 n = read_auth_entries (authfp, False, &head, &tail);
774 (void) fclose (authfp);
777 "%s: unable to read auth entries from file \"%s\"\n",
778 ProgramName, authfilename);
784 n = strlen (authfilename);
785 xauth_filename = malloc (n + 1);
786 if (xauth_filename) strcpy (xauth_filename, authfilename);
788 fprintf(stderr,"cannot allocate memory\n");
792 xauth_modified = False;
795 printf ("%s authority file %s\n",
796 ignore_locks ? "Ignoring locks on" : "Using", authfilename);
802 write_auth_file(char *tmp_nam)
809 * xdm and auth spec assumes auth file is 12 or fewer characters
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");
818 if (fd != -1) close(fd);
819 fprintf (stderr, "%s: unable to open tmp file \"%s\"\n",
820 ProgramName, tmp_nam);
825 * Write MIT-MAGIC-COOKIE-1 first, because R4 Xlib knows
826 * only that and uses the first authorization it finds.
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)) {
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)) {
854 char temp_name[1024]; /* large filename size */
856 if (xauth_modified) {
860 * called from a signal handler -- printf is *not* reentrant; also
861 * fileno() might not be reentrant, avoid it if possible, and use
862 * stderr instead of stdout
865 WRITES(STDERR_FILENO, "\nAborting changes to authority file ");
866 WRITES(STDERR_FILENO, xauth_filename);
867 WRITES(STDERR_FILENO, "\n");
869 WRITES(fileno(stderr), "\nAborting changes to authority file ");
870 WRITES(fileno(stderr), xauth_filename);
871 WRITES(fileno(stderr), "\n");
874 } else if (!xauth_allowed) {
876 "%s: %s not writable, changes ignored\n",
877 ProgramName, xauth_filename);
880 printf ("%s authority file %s\n",
881 ignore_locks ? "Ignoring locks and writing" :
882 "Writing", xauth_filename);
885 if (write_auth_file (temp_name) == -1) {
887 "%s: unable to write authority file %s\n",
888 ProgramName, temp_name);
890 (void) unlink (xauth_filename);
891 #if defined(WIN32) || defined(__UNIXOS2__)
892 if (rename(temp_name, xauth_filename) == -1)
894 if (link (temp_name, xauth_filename) == -1)
898 "%s: unable to link authority file %s, use %s\n",
899 ProgramName, xauth_filename, temp_name);
901 (void) unlink (temp_name);
908 XauUnlockAuth (xauth_filename);
910 (void) umask (original_umask);
915 process_command(char *inputfilename, int lineno, int argc, char **argv)
919 if (argc < 1 || !argv || !argv[0]) return 1;
921 if (dispatch_command (inputfilename, lineno, argc, argv,
922 command_table, &status))
925 prefix (inputfilename, lineno);
926 fprintf (stderr, "unknown command \"%s\"\n", argv[0]);
936 bintohex(unsigned int len, char *bindata)
938 char *hexdata, *starthex;
940 /* two chars per byte, plus null termination */
941 starthex = hexdata = (char *)malloc(2*len + 1);
945 for (; len > 0; len--, bindata++) {
946 register char *s = hex_table[(unsigned char)*bindata];
955 fprintfhex(register FILE *fp, int len, char *cp)
959 hex = bintohex(len, cp);
960 fprintf(fp, "%s", hex);
965 dump_numeric(register FILE *fp, register Xauth *auth)
967 fprintf (fp, "%04x", auth->family); /* unsigned short */
968 fprintf (fp, " %04x ", auth->address_length); /* short */
969 fprintfhex (fp, auth->address_length, auth->address);
970 fprintf (fp, " %04x ", auth->number_length); /* short */
971 fprintfhex (fp, auth->number_length, auth->number);
972 fprintf (fp, " %04x ", auth->name_length); /* short */
973 fprintfhex (fp, auth->name_length, auth->name);
974 fprintf (fp, " %04x ", auth->data_length); /* short */
975 fprintfhex (fp, auth->data_length, auth->data);
982 dump_entry(char *inputfilename, int lineno, Xauth *auth, char *data)
984 struct _list_data *ld = (struct _list_data *) data;
988 dump_numeric (fp, auth);
990 char *dpyname = NULL;
992 switch (auth->family) {
994 fwrite (auth->address, sizeof (char), auth->address_length, fp);
995 fprintf (fp, "/unix");
998 #if defined(IPv6) && defined(AF_INET6)
999 case FamilyInternet6:
1002 dpyname = get_hostname (auth);
1004 fprintf (fp, "%s", dpyname);
1007 /* else fall through to default */
1009 fprintf (fp, "#%04x#", auth->family);
1010 fprintfhex (fp, auth->address_length, auth->address);
1014 fwrite (auth->number, sizeof (char), auth->number_length, fp);
1017 fwrite (auth->name, sizeof (char), auth->name_length, fp);
1020 if (!strncmp(auth->name, SECURERPC, auth->name_length) ||
1021 !strncmp(auth->name, K5AUTH, auth->name_length))
1022 fwrite (auth->data, sizeof (char), auth->data_length, fp);
1024 fprintfhex (fp, auth->data_length, auth->data);
1031 extract_entry(char *inputfilename, int lineno, Xauth *auth, char *data)
1033 struct _extract_data *ed = (struct _extract_data *) data;
1036 ed->fp = open_file (&ed->filename,
1037 ed->numeric ? "w" : "wb",
1039 inputfilename, lineno, ed->cmd);
1041 prefix (inputfilename, lineno);
1043 "unable to open extraction file \"%s\"\n",
1048 (*(ed->numeric ? dump_numeric : XauWriteAuth)) (ed->fp, auth);
1056 eq_auth(Xauth *a, Xauth *b)
1058 return((a->family == b->family &&
1059 a->address_length == b->address_length &&
1060 a->number_length == b->number_length &&
1061 a->name_length == b->name_length &&
1062 a->data_length == b->data_length &&
1063 memcmp(a->address, b->address, a->address_length) == 0 &&
1064 memcmp(a->number, b->number, a->number_length) == 0 &&
1065 memcmp(a->name, b->name, a->name_length) == 0 &&
1066 memcmp(a->data, b->data, a->data_length) == 0) ? 1 : 0);
1070 match_auth_dpy(register Xauth *a, register Xauth *b)
1072 return ((a->family == b->family &&
1073 a->address_length == b->address_length &&
1074 a->number_length == b->number_length &&
1075 memcmp(a->address, b->address, a->address_length) == 0 &&
1076 memcmp(a->number, b->number, a->number_length) == 0) ? 1 : 0);
1079 /* return non-zero iff display and authorization type are the same */
1082 match_auth(register Xauth *a, register Xauth *b)
1084 return ((match_auth_dpy(a, b)
1085 && a->name_length == b->name_length
1086 && memcmp(a->name, b->name, a->name_length) == 0) ? 1 : 0);
1091 merge_entries(AuthList **firstp, AuthList *second, int *nnewp, int *nreplp)
1093 AuthList *a, *b, *first, *tail;
1094 int n = 0, nnew = 0, nrepl = 0;
1096 if (!second) return 0;
1098 if (!*firstp) { /* if nothing to merge into */
1100 for (tail = *firstp, n = 1; tail->next; n++, tail = tail->next) ;
1108 * find end of first list and stick second list on it
1110 for (tail = first; tail->next; tail = tail->next) ;
1111 tail->next = second;
1114 * run down list freeing duplicate entries; if an entry is okay, then
1115 * bump the tail up to include it, otherwise, cut the entry out of
1118 for (b = second; b; ) {
1119 AuthList *next = b->next; /* in case we free it */
1123 if (match_auth (a->auth, b->auth)) { /* found a duplicate */
1124 AuthList tmp; /* swap it in for old one */
1129 XauDisposeAuth (b->auth);
1137 if (a == tail) break; /* if have looked at left side */
1140 if (b) { /* if we didn't remove it */
1141 tail = b; /* bump end of first list */
1155 copyAuth(Xauth *auth)
1159 a = (Xauth *)malloc(sizeof(Xauth));
1163 memset(a, 0, sizeof(Xauth));
1164 a->family = auth->family;
1165 if (auth->address_length != 0) {
1166 a->address = malloc(auth->address_length);
1167 if (a->address == NULL) {
1171 memcpy(a->address, auth->address, auth->address_length);
1172 a->address_length = auth->address_length;
1174 if (auth->number_length != 0) {
1175 a->number = malloc(auth->number_length);
1176 if (a->number == NULL) {
1181 memcpy(a->number, auth->number, auth->number_length);
1182 a->number_length = auth->number_length;
1184 if (auth->name_length != 0) {
1185 a->name = malloc(auth->name_length);
1186 if (a->name == NULL) {
1192 memcpy(a->name, auth->name, auth->name_length);
1193 a->name_length = auth->name_length;
1195 if (auth->data_length != 0) {
1196 a->data = malloc(auth->data_length);
1197 if (a->data == NULL) {
1204 memcpy(a->data, auth->data, auth->data_length);
1205 a->data_length = auth->data_length;
1210 typedef int (*YesNoFunc)(char *, int, Xauth *, char *);
1213 iterdpy (char *inputfilename, int lineno, int start,
1214 int argc, char *argv[],
1215 YesNoFunc yfunc, YesNoFunc nfunc, char *data)
1221 AuthList *proto_head, *proto;
1227 for (i = start; i < argc; i++) {
1228 char *displayname = argv[i];
1229 if (!get_displayname_auth (displayname, &proto_head)) {
1230 prefix (inputfilename, lineno);
1231 baddisplayname (displayname, argv[0]);
1236 for (l = xauth_head; l; l = next) {
1237 Bool matched = False;
1239 /* l may be freed by remove_entry below. so save its contents */
1241 tmp_auth = copyAuth(l->auth);
1242 for (proto = proto_head; proto; proto = proto->next) {
1243 if (match_auth_dpy (proto->auth, tmp_auth)) {
1246 status = (*yfunc) (inputfilename, lineno,
1248 if (status < 0) break;
1252 XauDisposeAuth(tmp_auth);
1253 if (matched == False) {
1255 status = (*nfunc) (inputfilename, lineno,
1259 if (status < 0) break;
1261 for (proto = proto_head; proto ; proto = next) {
1263 if (proto->auth->address) free (proto->auth->address);
1264 if (proto->auth->number) free (proto->auth->number);
1269 errors -= status; /* since status is negative */
1279 remove_entry(char *inputfilename, int lineno, Xauth *auth, char *data)
1281 int *nremovedp = (int *) data;
1282 AuthList **listp = &xauth_head;
1286 * unlink the auth we were asked to
1288 while (!eq_auth((list = *listp)->auth, auth))
1289 listp = &list->next;
1290 *listp = list->next;
1291 XauDisposeAuth (list->auth); /* free the auth */
1292 free (list); /* free the link */
1293 xauth_modified = True;
1306 print_help(FILE *fp, char *cmd, char *prefix)
1311 if (!prefix) prefix = "";
1313 if (!cmd) { /* if no cmd, print all help */
1314 for (ct = command_table; ct->name; ct++) {
1315 fprintf (fp, "%s%s\n", prefix, ct->helptext);
1319 int len = strlen (cmd);
1320 for (ct = command_table; ct->name; ct++) {
1321 if (strncmp (cmd, ct->name, len) == 0) {
1322 fprintf (fp, "%s%s\n", prefix, ct->helptext);
1332 do_help(char *inputfilename, int lineno, int argc, char **argv)
1334 char *cmd = (argc > 1 ? argv[1] : NULL);
1337 n = print_help (stdout, cmd, " "); /* a nice amount */
1339 if (n < 0 || (n == 0 && !cmd)) {
1340 prefix (inputfilename, lineno);
1341 fprintf (stderr, "internal error with help");
1343 fprintf (stderr, " on command \"%s\"", cmd);
1345 fprintf (stderr, "\n");
1350 prefix (inputfilename, lineno);
1351 /* already know that cmd is set in this case */
1352 fprintf (stderr, "no help for noexistent command \"%s\"\n", cmd);
1363 do_questionmark(char *inputfilename, int lineno, int argc, char **argv)
1367 #define WIDEST_COLUMN 72
1368 int col = WIDEST_COLUMN;
1370 printf ("Commands:\n");
1371 for (ct = command_table; ct->name; ct++) {
1372 if ((col + ct->maxlen) > WIDEST_COLUMN) {
1373 if (ct != command_table) {
1374 putc ('\n', stdout);
1376 fputs (" ", stdout);
1377 col = 8; /* length of string above */
1379 fputs (ct->name, stdout);
1381 for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH; i++) {
1387 putc ('\n', stdout);
1390 /* allow bad lines since this is help */
1395 * list [displayname ...]
1398 do_list (char *inputfilename, int lineno, int argc, char **argv)
1400 struct _list_data ld;
1403 ld.numeric = (argv[0][0] == 'n');
1406 register AuthList *l;
1409 for (l = xauth_head; l; l = l->next) {
1410 dump_entry (inputfilename, lineno, l->auth, (char *) &ld);
1416 return iterdpy (inputfilename, lineno, 1, argc, argv,
1417 dump_entry, NULL, (char *) &ld);
1421 * merge filename [filename ...]
1424 do_merge(char *inputfilename, int lineno, int argc, char **argv)
1428 AuthList *head, *tail, *listhead, *listtail;
1429 int nentries, nnew, nrepl;
1430 Bool numeric = False;
1433 prefix (inputfilename, lineno);
1434 badcommandline (argv[0]);
1438 if (argv[0][0] == 'n') numeric = True;
1439 listhead = listtail = NULL;
1441 for (i = 1; i < argc; i++) {
1442 char *filename = argv[i];
1444 Bool used_stdin = False;
1446 fp = open_file (&filename,
1447 numeric ? "r" : "rb",
1448 &used_stdin, inputfilename, lineno,
1456 nentries = read_auth_entries (fp, numeric, &head, &tail);
1457 if (nentries == 0) {
1458 prefix (inputfilename, lineno);
1459 fprintf (stderr, "unable to read any entries from file \"%s\"\n",
1462 } else { /* link it in */
1463 add_to_list (listhead, listtail, head);
1466 if (!used_stdin) (void) fclose (fp);
1470 * if we have new entries, merge them in (freeing any duplicates)
1473 nentries = merge_entries (&xauth_head, listhead, &nnew, &nrepl);
1475 printf ("%d entries read in: %d new, %d replacement%s\n",
1476 nentries, nnew, nrepl, nrepl != 1 ? "s" : "");
1477 if (nentries > 0) xauth_modified = True;
1484 * extract filename displayname [displayname ...]
1487 do_extract(char *inputfilename, int lineno, int argc, char **argv)
1490 struct _extract_data ed;
1493 prefix (inputfilename, lineno);
1494 badcommandline (argv[0]);
1499 ed.filename = argv[1];
1500 ed.used_stdout = False;
1501 ed.numeric = (argv[0][0] == 'n');
1505 errors = iterdpy (inputfilename, lineno, 2, argc, argv,
1506 extract_entry, NULL, (char *) &ed);
1510 "No matches found, authority file \"%s\" not written\n",
1514 printf ("%d entries written to \"%s\"\n",
1515 ed.nwritten, ed.filename);
1517 if (!ed.used_stdout) {
1518 (void) fclose (ed.fp);
1527 * add displayname protocolname hexkey
1530 do_add(char *inputfilename, int lineno, int argc, char **argv)
1538 AuthList *list, *list_cur, *list_next;
1540 if (argc != 4 || !argv[1] || !argv[2] || !argv[3]) {
1541 prefix (inputfilename, lineno);
1542 badcommandline (argv[0]);
1547 protoname = argv[2];
1550 len = strlen(hexkey);
1551 if (hexkey[0] == '"' && hexkey[len-1] == '"') {
1552 key = malloc(len-1);
1553 strncpy(key, hexkey+1, len-2);
1555 } else if (!strcmp(protoname, SECURERPC) ||
1556 !strcmp(protoname, K5AUTH)) {
1557 key = malloc(len+1);
1558 strcpy(key, hexkey);
1560 len = cvthexkey (hexkey, &key);
1562 prefix (inputfilename, lineno);
1564 "key contains odd number of or non-hex characters\n");
1569 if (!get_displayname_auth (dpyname, &list)) {
1570 prefix (inputfilename, lineno);
1571 baddisplayname (dpyname, argv[0]);
1577 * allow an abbreviation for common protocol names
1579 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) {
1580 protoname = DEFAULT_PROTOCOL;
1583 for (list_cur = list; list_cur != NULL; list_cur = list_cur->next) {
1584 Xauth *auth = list_cur->auth;
1586 auth->name_length = strlen (protoname);
1587 auth->name = copystring (protoname, auth->name_length);
1589 prefix (inputfilename, lineno);
1590 fprintf (stderr, "unable to allocate %d character protocol name\n",
1592 for (list_cur = list; list_cur != NULL; list_cur = list_next) {
1593 list_next = list_cur->next;
1594 XauDisposeAuth(list_cur->auth);
1600 auth->data_length = len;
1601 auth->data = malloc(len);
1603 prefix(inputfilename, lineno);
1604 fprintf(stderr, "unable to allocate %d bytes for key\n", len);
1605 for (list_cur = list; list_cur != NULL; list_cur = list_next) {
1606 list_next = list_cur->next;
1607 XauDisposeAuth(list_cur->auth);
1613 memcpy(auth->data, key, len);
1617 * merge it in; note that merge will deal with allocation
1619 n = merge_entries (&xauth_head, list, &nnew, &nrepl);
1621 prefix (inputfilename, lineno);
1622 fprintf (stderr, "unable to merge in added record\n");
1626 xauth_modified = True;
1631 * remove displayname
1634 do_remove(char *inputfilename, int lineno, int argc, char **argv)
1640 prefix (inputfilename, lineno);
1641 badcommandline (argv[0]);
1645 errors = iterdpy (inputfilename, lineno, 1, argc, argv,
1646 remove_entry, NULL, (char *) &nremoved);
1647 if (verbose) printf ("%d entries removed\n", nremoved);
1655 do_info(char *inputfilename, int lineno, int argc, char **argv)
1661 prefix (inputfilename, lineno);
1662 badcommandline (argv[0]);
1666 for (l = xauth_head, n = 0; l; l = l->next, n++) ;
1668 printf ("Authority file: %s\n",
1669 xauth_filename ? xauth_filename : "(none)");
1670 printf ("File new: %s\n", xauth_existed ? No : Yes);
1671 printf ("File locked: %s\n", xauth_locked ? No : Yes);
1672 printf ("Number of entries: %d\n", n);
1673 printf ("Changes honored: %s\n", xauth_allowed ? Yes : No);
1674 printf ("Changes made: %s\n", xauth_modified ? Yes : No);
1675 printf ("Current input: %s:%d\n", inputfilename, lineno);
1683 static Bool alldone = False;
1687 do_exit(char *inputfilename, int lineno, int argc, char **argv)
1689 /* allow bogus stuff */
1699 do_quit(char *inputfilename, int lineno, int argc, char **argv)
1701 /* allow bogus stuff */
1704 return -1; /* for picky compilers */
1712 do_source(char *inputfilename, int lineno, int argc, char **argv)
1717 Bool used_stdin = False;
1719 int errors = 0, status;
1723 Bool prompt = False; /* only true if reading from tty */
1725 if (argc != 2 || !argv[1]) {
1726 prefix (inputfilename, lineno);
1727 badcommandline (argv[0]);
1733 fp = open_file (&script, "r", &used_stdin, inputfilename, lineno, argv[0]);
1738 if (verbose && used_stdin && isatty (fileno (fp))) prompt = True;
1746 if (fgets (buf, sizeof buf, fp) == NULL) break;
1749 if (len == 0 || buf[0] == '#') continue;
1750 if (buf[len-1] != '\n') {
1751 prefix (script, sublineno);
1752 fprintf (stderr, "line too long\n");
1756 buf[--len] = '\0'; /* remove new line */
1757 subargv = split_into_words (buf, &subargc);
1759 status = process_command (script, sublineno, subargc, subargv);
1760 free ((char *) subargv);
1763 prefix (script, sublineno);
1764 fprintf (stderr, "unable to break line into words\n");
1775 static int x_protocol_error;
1777 catch_x_protocol_error(Display *dpy, XErrorEvent *errevent)
1780 XGetErrorText(dpy, errevent->error_code, buf, sizeof (buf));
1781 fprintf(stderr, "%s\n", buf);
1782 x_protocol_error = errevent->error_code;
1790 do_generate(char *inputfilename, int lineno, int argc, char **argv)
1793 int major_version, minor_version;
1794 XSecurityAuthorization id_return;
1795 Xauth *auth_in, *auth_return;
1796 XSecurityAuthorizationAttributes attributes;
1797 unsigned long attrmask = 0;
1801 char *protoname = ".";
1803 int authdatalen = 0;
1805 char *authdata = NULL;
1807 if (argc < 2 || !argv[1]) {
1808 prefix (inputfilename, lineno);
1809 badcommandline (argv[0]);
1813 displayname = argv[1];
1816 protoname = argv[2];
1819 for (i = 3; i < argc; i++) {
1820 if (0 == strcmp(argv[i], "timeout")) {
1822 prefix (inputfilename, lineno);
1823 badcommandline (argv[i-1]);
1826 attributes.timeout = atoi(argv[i]);
1827 attrmask |= XSecurityTimeout;
1829 } else if (0 == strcmp(argv[i], "trusted")) {
1830 attributes.trust_level = XSecurityClientTrusted;
1831 attrmask |= XSecurityTrustLevel;
1833 } else if (0 == strcmp(argv[i], "untrusted")) {
1834 attributes.trust_level = XSecurityClientUntrusted;
1835 attrmask |= XSecurityTrustLevel;
1837 } else if (0 == strcmp(argv[i], "group")) {
1839 prefix (inputfilename, lineno);
1840 badcommandline (argv[i-1]);
1843 attributes.group = atoi(argv[i]);
1844 attrmask |= XSecurityGroup;
1846 } else if (0 == strcmp(argv[i], "data")) {
1848 prefix (inputfilename, lineno);
1849 badcommandline (argv[i-1]);
1853 authdatalen = strlen(hexdata);
1854 if (hexdata[0] == '"' && hexdata[authdatalen-1] == '"') {
1855 authdata = malloc(authdatalen-1);
1856 strncpy(authdata, hexdata+1, authdatalen-2);
1859 authdatalen = cvthexkey (hexdata, &authdata);
1860 if (authdatalen < 0) {
1861 prefix (inputfilename, lineno);
1863 "data contains odd number of or non-hex characters\n");
1868 prefix (inputfilename, lineno);
1869 badcommandline (argv[i]);
1874 /* generate authorization using the Security extension */
1876 dpy = XOpenDisplay (displayname);
1878 prefix (inputfilename, lineno);
1879 fprintf (stderr, "unable to open display \"%s\".\n", displayname);
1883 status = XSecurityQueryExtension(dpy, &major_version, &minor_version);
1886 prefix (inputfilename, lineno);
1887 fprintf (stderr, "couldn't query Security extension on display \"%s\"\n",
1892 /* fill in input Xauth struct */
1894 auth_in = XSecurityAllocXauth();
1895 if (strcmp (protoname, DEFAULT_PROTOCOL_ABBREV) == 0) {
1896 auth_in->name = DEFAULT_PROTOCOL;
1899 auth_in->name = protoname;
1900 auth_in->name_length = strlen(auth_in->name);
1901 auth_in->data = authdata;
1902 auth_in->data_length = authdatalen;
1904 x_protocol_error = 0;
1905 XSetErrorHandler(catch_x_protocol_error);
1906 auth_return = XSecurityGenerateAuthorization(dpy, auth_in, attrmask,
1907 &attributes, &id_return);
1910 if (!auth_return || x_protocol_error)
1912 prefix (inputfilename, lineno);
1913 fprintf (stderr, "couldn't generate authorization\n");
1918 printf("authorization id is %ld\n", id_return);
1920 /* create a fake input line to give to do_add */
1923 args[1] = displayname;
1924 args[2] = auth_in->name;
1925 args[3] = bintohex(auth_return->data_length, auth_return->data);
1927 status = do_add(inputfilename, lineno, 4, args);
1929 if (authdata) free(authdata);
1930 XSecurityFreeXauth(auth_in);
1931 XSecurityFreeXauth(auth_return);
1932 free(args[3]); /* hex data */