Bug Summary

File:process.c
Location:line 434, column 12
Description:Potential leak of memory pointed to by 'auth'

Annotated Source Code

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_H1
34#include "config.h"
35#endif
36
37#include "xauth.h"
38#include <ctype.h>
39#include <errno(*__error()).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"MIT-MAGIC-COOKIE-1" /* for protocol abbreviation */
57#define DEFAULT_PROTOCOL"MIT-MAGIC-COOKIE-1" "MIT-MAGIC-COOKIE-1"
58#endif
59
60#define SECURERPC"SUN-DES-1" "SUN-DES-1"
61#define K5AUTH"MIT-KERBEROS-5" "MIT-KERBEROS-5"
62
63#define XAUTH_DEFAULT_RETRIES10 10 /* number of competitors we expect */
64#define XAUTH_DEFAULT_TIMEOUT2 2 /* in seconds, be quick */
65#define XAUTH_DEFAULT_DEADTIME600L 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);} {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 Boolint used_stdout; /* whether or not need to close */
88 Boolint 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 Boolint 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((void*)0), 0, 0, NULL((void*)0), NULL((void*)0) },
162};
163
164#define COMMAND_NAMES_PADDED_WIDTH10 10 /* wider than anything above */
165
166
167static Boolint okay_to_use_stdin = True1; /* 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__stderrp, "%s: %s:%d: ", ProgramName, fn, n);
217}
218
219static void
220baddisplayname(const char *dpy, const char *cmd)
221{
222 fprintf (stderr__stderrp, "bad display name \"%s\" in \"%s\" command\n",
223 dpy, cmd);
224}
225
226static void
227badcommandline(const char *cmd)
228{
229 fprintf (stderr__stderrp, "bad \"%s\" command line\n", cmd);
230}
231
232static char *
233skip_space(register char *s)
234{
235 if (!s) return NULL((void*)0);
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((void*)0);
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 WORDSTOALLOC4 4 /* most lines are short */
264 argv = malloc (WORDSTOALLOC4 * sizeof (char *));
265 if (!argv) return NULL((void*)0);
266 cur = 0;
267 total = WORDSTOALLOC4;
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 += WORDSTOALLOC4;
282 argv = realloc (argv, total * sizeof (char *));
283 if (!argv) return NULL((void*)0);
284 }
285 argv[cur++] = jword;
286 if (savec) src++; /* if not last on line advance */
287 } while (jword != src);
288
289 argv[--cur] = NULL((void*)0); /* 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 Boolint *usedstdp,
299 const char *srcfn,
300 int srcln,
301 const char *cmd)
302{
303 FILE *fp;
304
305 if (strcmp (*filenamep, "-") == 0) {
306 *usedstdp = True1;
307 /* select std descriptor to use */
308 if (mode[0] == 'r') {
309 if (okay_to_use_stdin) {
310 okay_to_use_stdin = False0;
311 *filenamep = stdin_filename;
312 return stdin__stdinp;
313 } else {
314 prefix (srcfn, srcln);
315 fprintf (stderr__stderrp, "%s: stdin already in use\n", cmd);
316 return NULL((void*)0);
317 }
318 } else {
319 *filenamep = stdout_filename;
320 return stdout__stdoutp; /* always okay to use stdout */
321 }
322 }
323
324 fp = fopen (*filenamep, mode);
325 if (!fp) {
326 prefix (srcfn, srcln);
327 fprintf (stderr__stderrp, "%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(-1) && 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(-1):
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(-1) || c1 == '\n' ||
376 (c2 = getinput (fp)) == EOF(-1) || 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));
1
Memory is allocated
396 if (!auth) goto bad;
2
Assuming 'auth' is non-null
3
Taking false branch
397 auth->family = 0;
398 auth->address = NULL((void*)0);
399 auth->address_length = 0;
400 auth->number = NULL((void*)0);
401 auth->number_length = 0;
402 auth->name = NULL((void*)0);
403 auth->name_length = 0;
404 auth->data = NULL((void*)0);
405 auth->data_length = 0;
406
407 if (!get_short (fp, (unsigned short *) &auth->family))
4
Taking true branch
408 goto bad;
5
Control jumps to line 433
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(-1):
428 case '\n':
429 return auth;
430 }
431
432 bad:
433 if (auth) XauDisposeAuth (auth); /* won't free null pointers */
6
Taking true branch
434 return NULL((void*)0);
7
Within the expansion of the macro 'NULL':
a
Potential leak of memory pointed to by 'auth'
435}
436
437typedef Xauth *(*ReadFunc)(FILE *);
438
439static int
440read_auth_entries(FILE *fp, Boolint 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((void*)0);
448 n = 0;
449 /* put all records into linked list */
450 while ((auth = ((*readfunc) (fp))) != NULL((void*)0)) {
451 AuthList *l = (AuthList *) malloc (sizeof (AuthList));
452 if (!l) {
453 fprintf (stderr__stderrp,
454 "%s: unable to alloc entry reading auth file\n",
455 ProgramName);
456 exit (1);
457 }
458 l->next = NULL((void*)0);
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 Boolint
473get_displayname_auth(const char *displayname, AuthList **authl)
474{
475 int family;
476 char *host = NULL((void*)0), *rest = NULL((void*)0);
477 int dpynum, scrnum;
478 char *cp;
479 int prelen = 0;
480 struct addrlist *addrlist_head, *addrlist_cur;
481 AuthList *authl_cur = NULL((void*)0);
482
483 *authl = NULL((void*)0);
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 False0;
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)__builtin___sprintf_chk (buf, 0, __builtin_object_size (buf, 2
> 1 ? 1 : 0), "%d", dpynum)
;
504 dpylen = strlen (buf);
505 if (dpylen > 0) {
506 for (addrlist_cur = addrlist_head; addrlist_cur != NULL((void*)0);
507 addrlist_cur = addrlist_cur->next) {
508 AuthList *newal = malloc(sizeof(AuthList));
509 Xauth *auth = malloc(sizeof(Xauth));
510
511 if ((newal == NULL((void*)0)) || (auth == NULL((void*)0))) {
512 if (newal != NULL((void*)0)) free(newal);
513 if (auth != NULL((void*)0)) free(auth);
514 break;
515 }
516
517 if (authl_cur == NULL((void*)0)) {
518 *authl = authl_cur = newal;
519 } else {
520 authl_cur->next = newal;
521 authl_cur = newal;
522 }
523
524 newal->next = NULL((void*)0);
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((void*)0);
533 auth->name_length = 0;
534 auth->data = NULL((void*)0);
535 auth->data_length = 0;
536 }
537 }
538 }
539
540 if (host) free (host);
541 if (rest) free (rest);
542
543 if (*authl != NULL((void*)0)) {
544 return True1;
545 } else {
546 return False0;
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__stderrp, "%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((void*)0); /* list of auth entries */
631static Boolint xauth_existed = False0; /* if was present at initialize */
632static Boolint xauth_modified = False0; /* if added, removed, or merged */
633static Boolint xauth_allowed = True1; /* if allowed to write auth file */
634static Boolint xauth_locked = False0; /* if has been locked */
635static const char *xauth_filename = NULL((void*)0);
636static volatile Boolint dieing = False0;
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))));} {if(write((fd), (S), strlen((S))));}
642
643/* ARGSUSED */
644_X_NORETURN__attribute((noreturn))
645static void
646die(int sig)
647{
648 dieing = True1;
649 _exit (auth_finalize ());
650 /* NOTREACHED */
651}
652
653_X_NORETURN__attribute((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_FILENO2
665 if (verbose && xauth_modified) WRITES(STDERR_FILENO, "\r\n"){if(write((2), ("\r\n"), strlen(("\r\n"))));};
666#else
667 if (verbose && xauth_modified) WRITES(fileno(stderr), "\r\n"){if(write((fileno(__stderrp)), ("\r\n"), strlen(("\r\n"))));};
668#endif
669 die (sig);
670 /* NOTREACHED */
671}
672
673static void
674register_signals(void)
675{
676 signal (SIGINT2, catchsig);
677 signal (SIGTERM15, catchsig);
678#ifdef SIGHUP1
679 signal (SIGHUP1, catchsig);
680#endif
681#ifdef SIGPIPE13
682 signal (SIGPIPE13, 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 Boolint exists;
699
700 xauth_filename = authfilename; /* used in cleanup, prevent race with
701 signals */
702 register_signals ();
703
704 bzero ((char *) hexvalues, sizeof hexvalues)__builtin___memset_chk ((char *) hexvalues, 0, sizeof hexvalues
, __builtin_object_size ((char *) hexvalues, 0))
;
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_RETRIES10,
731 XAUTH_DEFAULT_TIMEOUT2,
732 (break_locks ? 0L : XAUTH_DEFAULT_DEADTIME600L));
733 if (n != LOCK_SUCCESS0) {
734 const char *reason = "unknown error";
735 switch (n) {
736 case LOCK_ERROR1:
737 reason = "error";
738 break;
739 case LOCK_TIMEOUT2:
740 reason = "timeout";
741 break;
742 }
743 fprintf (stderr__stderrp, "%s: %s in locking authority file %s\n",
744 ProgramName, reason, authfilename);
745 return -1;
746 } else
747 xauth_locked = True1;
748 }
749
750 /* these checks can only be done reliably after the file is locked */
751 exists = (access (authfilename, F_OK0) == 0);
752 if (exists && access (authfilename, W_OK(1<<1)) != 0) {
753 fprintf (stderr__stderrp,
754 "%s: %s not writable, changes will be ignored\n",
755 ProgramName, authfilename);
756 xauth_allowed = False0;
757 }
758
759 original_umask = umask (0077); /* disallow non-owner access */
760
761 authfp = fopen (authfilename, "rb");
762 if (!authfp) {
763 int olderrno = errno(*__error());
764
765 /* if file there then error */
766 if (access (authfilename, F_OK0) == 0) { /* then file does exist! */
767 errno(*__error()) = olderrno;
768 return -1;
769 } /* else ignore it */
770 fprintf (stderr__stderrp,
771 "%s: file %s does not exist\n",
772 ProgramName, authfilename);
773 } else {
774 xauth_existed = True1;
775 n = read_auth_entries (authfp, False0, &head, &tail);
776 (void) fclose (authfp);
777 if (n < 0) {
778 fprintf (stderr__stderrp,
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__stderrp,"cannot allocate memory\n");
789 return -1;
790 }
791
792 xauth_modified = False0;
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((void*)0);
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)__builtin___strcpy_chk (tmp_nam, xauth_filename, __builtin_object_size
(tmp_nam, 2 > 1 ? 1 : 0))
;
812 strcat (tmp_nam, "-n")__builtin___strcat_chk (tmp_nam, "-n", __builtin_object_size (
tmp_nam, 2 > 1 ? 1 : 0))
; /* for new */
813 (void) unlink (tmp_nam);
814 /* CPhipps 2000/02/12 - fix file unlink/fopen race */
815 fd = open(tmp_nam, O_WRONLY0x0001 | O_CREAT0x0200 | O_EXCL0x0800, 0600);
816 if (fd != -1) fp = fdopen (fd, "wb");
817 if (!fp) {
818 if (fd != -1) close(fd);
819 fprintf (stderr__stderrp, "%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_FILENO2
868 WRITES(STDERR_FILENO, "\nAborting changes to authority file "){if(write((2), ("\nAborting changes to authority file "), strlen
(("\nAborting changes to authority file "))));}
;
869 WRITES(STDERR_FILENO, xauth_filename){if(write((2), (xauth_filename), strlen((xauth_filename))));};
870 WRITES(STDERR_FILENO, "\n"){if(write((2), ("\n"), strlen(("\n"))));};
871#else
872 WRITES(fileno(stderr), "\nAborting changes to authority file "){if(write((fileno(__stderrp)), ("\nAborting changes to authority file "
), strlen(("\nAborting changes to authority file "))));}
;
873 WRITES(fileno(stderr), xauth_filename){if(write((fileno(__stderrp)), (xauth_filename), strlen((xauth_filename
))));}
;
874 WRITES(fileno(stderr), "\n"){if(write((fileno(__stderrp)), ("\n"), strlen(("\n"))));};
875#endif
876 }
877 } else if (!xauth_allowed) {
878 fprintf (stderr__stderrp,
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__stderrp,
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__stderrp,
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__stderrp, "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((void*)0);
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((void*)0);
995
996 switch (auth->family) {
997 case FamilyLocal(256):
998 fwrite (auth->address, sizeof (char), auth->address_length, fp);
999 fprintf (fp, "/unix");
1000 break;
1001 case FamilyInternet0:
1002#if defined(IPv61) && defined(AF_INET630)
1003 case FamilyInternet66:
1004#endif
1005 case FamilyDECnet1:
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"SUN-DES-1", auth->name_length) ||
1025 !strncmp(auth->name, K5AUTH"MIT-KERBEROS-5", 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__stderrp,
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(65535) && b->family != FamilyWild(65535)) {
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((void*)0);
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((void*)0)) {
1185 return NULL((void*)0);
1186 }
1187 memset(a, 0, sizeof(Xauth))__builtin___memset_chk (a, 0, sizeof(Xauth), __builtin_object_size
(a, 0))
;
1188 a->family = auth->family;
1189 if (auth->address_length != 0) {
1190 a->address = malloc(auth->address_length);
1191 if (a->address == NULL((void*)0)) {
1192 free(a);
1193 return NULL((void*)0);
1194 }
1195 memcpy(a->address, auth->address, auth->address_length)__builtin___memcpy_chk (a->address, auth->address, auth
->address_length, __builtin_object_size (a->address, 0)
)
;
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((void*)0)) {
1201 free(a->address);
1202 free(a);
1203 return NULL((void*)0);
1204 }
1205 memcpy(a->number, auth->number, auth->number_length)__builtin___memcpy_chk (a->number, auth->number, auth->
number_length, __builtin_object_size (a->number, 0))
;
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((void*)0)) {
1211 free(a->address);
1212 free(a->number);
1213 free(a);
1214 return NULL((void*)0);
1215 }
1216 memcpy(a->name, auth->name, auth->name_length)__builtin___memcpy_chk (a->name, auth->name, auth->name_length
, __builtin_object_size (a->name, 0))
;
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((void*)0)) {
1222 free(a->address);
1223 free(a->number);
1224 free(a->name);
1225 free(a);
1226 return NULL((void*)0);
1227 }
1228 memcpy(a->data, auth->data, auth->data_length)__builtin___memcpy_chk (a->data, auth->data, auth->data_length
, __builtin_object_size (a->data, 0))
;
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 Boolint matched = False0;
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 = True1;
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 == False0) {
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 = True1;
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((void*)0));
1362 int n;
1363
1364 n = print_help (stdout__stdoutp, cmd, " "); /* a nice amount */
1365
1366 if (n < 0 || (n == 0 && !cmd)) {
1367 prefix (inputfilename, lineno);
1368 fprintf (stderr__stderrp, "internal error with help");
1369 if (cmd) {
1370 fprintf (stderr__stderrp, " on command \"%s\"", cmd);
1371 }
1372 fprintf (stderr__stderrp, "\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__stderrp, "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_COLUMN72 72
1395 int col = WIDEST_COLUMN72;
1396
1397 printf ("Commands:\n");
1398 for (ct = command_table; ct->name; ct++) {
1399 if ((col + ct->maxlen) > WIDEST_COLUMN72) {
1400 if (ct != command_table) {
1401 putc ('\n', stdout__stdoutp);
1402 }
1403 fputs (" ", stdout__stdoutp);
1404 col = 8; /* length of string above */
1405 }
1406 fputs (ct->name, stdout__stdoutp);
1407 col += ct->maxlen;
1408 for (i = ct->maxlen; i < COMMAND_NAMES_PADDED_WIDTH10; i++) {
1409 putc (' ', stdout__stdoutp);
1410 col++;
1411 }
1412 }
1413 if (col != 0) {
1414 putc ('\n', stdout__stdoutp);
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"1.0.9");
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__stdoutp;
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((void*)0), (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 Boolint numeric = False0;
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 = True1;
1477 listhead = listtail = NULL((void*)0);
1478
1479 for (i = 1; i < argc; i++) {
1480 const char *filename = argv[i];
1481 FILE *fp;
1482 Boolint used_stdin = False0;
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((void*)0);
1494 nentries = read_auth_entries (fp, numeric, &head, &tail);
1495 if (nentries == 0) {
1496 prefix (inputfilename, lineno);
1497 fprintf (stderr__stderrp, "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){if (listtail) (listtail)->next = (head); else (listhead) =
(head); (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 = True1;
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((void*)0);
1537 ed.filename = argv[1];
1538 ed.used_stdout = False0;
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((void*)0), (char *) &ed);
1545
1546 if (!ed.fp) {
1547 fprintf (stderr__stderrp,
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)__builtin___strncpy_chk (key, hexkey+1, len-2, __builtin_object_size
(key, 2 > 1 ? 1 : 0))
;
1593 len -= 2;
1594 } else if (!strcmp(protoname, SECURERPC"SUN-DES-1") ||
1595 !strcmp(protoname, K5AUTH"MIT-KERBEROS-5")) {
1596 key = malloc(len+1);
1597 strcpy(key, hexkey)__builtin___strcpy_chk (key, hexkey, __builtin_object_size (key
, 2 > 1 ? 1 : 0))
;
1598 } else {
1599 len = cvthexkey (hexkey, &key);
1600 if (len < 0) {
1601 prefix (inputfilename, lineno);
1602 fprintf (stderr__stderrp,
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"MIT-MAGIC-COOKIE-1";
1620 }
1621
1622 for (list_cur = list; list_cur != NULL((void*)0); 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__stderrp, "unable to allocate %d character protocol name\n",
1630 auth->name_length);
1631 for (list_cur = list; list_cur != NULL((void*)0); 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__stderrp, "unable to allocate %d bytes for key\n", len);
1644 for (list_cur = list; list_cur != NULL((void*)0); 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)__builtin___memcpy_chk (auth->data, key, len, __builtin_object_size
(auth->data, 0))
;
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__stderrp, "unable to merge in added record\n");
1662 return 1;
1663 }
1664
1665 xauth_modified = True1;
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((void*)0), (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 Boolint alldone = False0;
1723
1724/* ARGSUSED */
1725static int
1726do_exit(const char *inputfilename, int lineno, int argc, const char **argv)
1727{
1728 /* allow bogus stuff */
1729 alldone = True1;
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[BUFSIZ1024];
1755 FILE *fp;
1756 Boolint used_stdin = False0;
1757 int len;
1758 int errors = 0, status;
1759 int sublineno = 0;
1760 const char **subargv;
1761 int subargc;
1762 Boolint prompt = False0; /* 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 = True1;
1778
1779 while (!alldone) {
1780 buf[0] = '\0';
1781 if (prompt) {
1782 printf ("xauth> ");
1783 fflush (stdout__stdoutp);
1784 }
1785 if (fgets (buf, sizeof buf, fp) == NULL((void*)0)) 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__stderrp, "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__stderrp, "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__stderrp, "%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((void*)0);
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(1<<0);
1868
1869 } else if (0 == strcmp(argv[i], "trusted")) {
1870 attributes.trust_level = XSecurityClientTrusted0;
1871 attrmask |= XSecurityTrustLevel(1<<1);
1872
1873 } else if (0 == strcmp(argv[i], "untrusted")) {
1874 attributes.trust_level = XSecurityClientUntrusted1;
1875 attrmask |= XSecurityTrustLevel(1<<1);
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(1<<2);
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)__builtin___strncpy_chk (authdata, hexdata+1, authdatalen-2, __builtin_object_size
(authdata, 2 > 1 ? 1 : 0))
;
1897 authdatalen -= 2;
1898 } else {
1899 authdatalen = cvthexkey (hexdata, &authdata);
1900 if (authdatalen < 0) {
1901 prefix (inputfilename, lineno);
1902 fprintf (stderr__stderrp,
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__stderrp, "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__stderrp, "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"MIT-MAGIC-COOKIE-1", strlen(DEFAULT_PROTOCOL"MIT-MAGIC-COOKIE-1"));
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, False0);
1949
1950 if (!auth_return || x_protocol_error)
1951 {
1952 prefix (inputfilename, lineno);
1953 fprintf (stderr__stderrp, "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}