File: | process.c |
Location: | line 434, column 12 |
Description: | Potential leak of memory pointed to by 'auth' |
1 | /* | |||||
2 | ||||||
3 | Copyright 1989, 1998 The Open Group | |||||
4 | ||||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
6 | documentation for any purpose is hereby granted without fee, provided that | |||||
7 | the above copyright notice appear in all copies and that both that | |||||
8 | copyright notice and this permission notice appear in supporting | |||||
9 | documentation. | |||||
10 | ||||||
11 | The above copyright notice and this permission notice shall be included | |||||
12 | in all copies or substantial portions of the Software. | |||||
13 | ||||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||||
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||||
17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||||
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||||
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||||
20 | OTHER DEALINGS IN THE SOFTWARE. | |||||
21 | ||||||
22 | Except as contained in this notice, the name of The Open Group shall | |||||
23 | not be used in advertising or otherwise to promote the sale, use or | |||||
24 | other dealings in this Software without prior written authorization | |||||
25 | from 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 | ||||||
67 | typedef struct _AuthList { /* linked list of entries */ | |||||
68 | struct _AuthList *next; | |||||
69 | Xauth *auth; | |||||
70 | } AuthList; | |||||
71 | ||||||
72 | typedef 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 | ||||||
76 | typedef 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 | ||||||
84 | struct _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 | ||||||
93 | struct _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 | */ | |||||
102 | static const char *stdin_filename = "(stdin)"; /* for messages */ | |||||
103 | static const char *stdout_filename = "(stdout)"; /* for messages */ | |||||
104 | static const char *Yes = "yes"; /* for messages */ | |||||
105 | static const char *No = "no"; /* for messages */ | |||||
106 | ||||||
107 | static int do_help ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
108 | static int do_questionmark ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
109 | static int do_list ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
110 | static int do_merge ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
111 | static int do_extract ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
112 | static int do_add ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
113 | static int do_remove ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
114 | static int do_info ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
115 | static int do_exit ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
116 | static int do_quit ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
117 | static int do_source ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
118 | static int do_generate ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
119 | static int do_version ( const char *inputfilename, int lineno, int argc, const char **argv ); | |||||
120 | ||||||
121 | static 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 | ||||||
167 | static Boolint okay_to_use_stdin = True1; /* set to false after using */ | |||||
168 | ||||||
169 | static 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 | ||||||
204 | static unsigned int hexvalues[256]; /* for parsing hex input */ | |||||
205 | ||||||
206 | static int original_umask = 0; /* for restoring */ | |||||
207 | ||||||
208 | ||||||
209 | /* | |||||
210 | * private utility procedures | |||||
211 | */ | |||||
212 | ||||||
213 | static void | |||||
214 | prefix(const char *fn, int n) | |||||
215 | { | |||||
216 | fprintf (stderr__stderrp, "%s: %s:%d: ", ProgramName, fn, n); | |||||
217 | } | |||||
218 | ||||||
219 | static void | |||||
220 | baddisplayname(const char *dpy, const char *cmd) | |||||
221 | { | |||||
222 | fprintf (stderr__stderrp, "bad display name \"%s\" in \"%s\" command\n", | |||||
223 | dpy, cmd); | |||||
224 | } | |||||
225 | ||||||
226 | static void | |||||
227 | badcommandline(const char *cmd) | |||||
228 | { | |||||
229 | fprintf (stderr__stderrp, "bad \"%s\" command line\n", cmd); | |||||
230 | } | |||||
231 | ||||||
232 | static char * | |||||
233 | skip_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 | ||||||
243 | static char * | |||||
244 | skip_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 | ||||||
254 | static const char ** | |||||
255 | split_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 | ||||||
295 | static FILE * | |||||
296 | open_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 | ||||||
332 | static int | |||||
333 | getinput(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 | ||||||
341 | static int | |||||
342 | get_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 | ||||||
364 | static int | |||||
365 | get_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 | ||||||
390 | static Xauth * | |||||
391 | read_numeric(FILE *fp) | |||||
392 | { | |||||
393 | Xauth *auth; | |||||
394 | ||||||
395 | auth = (Xauth *) malloc (sizeof (Xauth)); | |||||
| ||||||
396 | if (!auth) goto bad; | |||||
397 | auth->family = 0; | |||||
398 | auth->address = NULL((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)) | |||||
408 | goto bad; | |||||
409 | if (!get_short (fp, (unsigned short *) &auth->address_length)) | |||||
410 | goto bad; | |||||
411 | if (!get_bytes (fp, (unsigned int) auth->address_length, &auth->address)) | |||||
412 | goto bad; | |||||
413 | if (!get_short (fp, (unsigned short *) &auth->number_length)) | |||||
414 | goto bad; | |||||
415 | if (!get_bytes (fp, (unsigned int) auth->number_length, &auth->number)) | |||||
416 | goto bad; | |||||
417 | if (!get_short (fp, (unsigned short *) &auth->name_length)) | |||||
418 | goto bad; | |||||
419 | if (!get_bytes (fp, (unsigned int) auth->name_length, &auth->name)) | |||||
420 | goto bad; | |||||
421 | if (!get_short (fp, (unsigned short *) &auth->data_length)) | |||||
422 | goto bad; | |||||
423 | if (!get_bytes (fp, (unsigned int) auth->data_length, &auth->data)) | |||||
424 | goto bad; | |||||
425 | ||||||
426 | switch (getinput (fp)) { /* get end of line */ | |||||
427 | case EOF(-1): | |||||
428 | case '\n': | |||||
429 | return auth; | |||||
430 | } | |||||
431 | ||||||
432 | bad: | |||||
433 | if (auth) XauDisposeAuth (auth); /* won't free null pointers */ | |||||
434 | return NULL((void*)0); | |||||
| ||||||
435 | } | |||||
436 | ||||||
437 | typedef Xauth *(*ReadFunc)(FILE *); | |||||
438 | ||||||
439 | static int | |||||
440 | read_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 | ||||||
472 | static Boolint | |||||
473 | get_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 | ||||||
550 | static int | |||||
551 | cvthexkey(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 | ||||||
602 | static int | |||||
603 | dispatch_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 | ||||||
630 | static AuthList *xauth_head = NULL((void*)0); /* list of auth entries */ | |||||
631 | static Boolint xauth_existed = False0; /* if was present at initialize */ | |||||
632 | static Boolint xauth_modified = False0; /* if added, removed, or merged */ | |||||
633 | static Boolint xauth_allowed = True1; /* if allowed to write auth file */ | |||||
634 | static Boolint xauth_locked = False0; /* if has been locked */ | |||||
635 | static const char *xauth_filename = NULL((void*)0); | |||||
636 | static 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)) | |||||
645 | static void | |||||
646 | die(int sig) | |||||
647 | { | |||||
648 | dieing = True1; | |||||
649 | _exit (auth_finalize ()); | |||||
650 | /* NOTREACHED */ | |||||
651 | } | |||||
652 | ||||||
653 | _X_NORETURN__attribute((noreturn)) | |||||
654 | static void | |||||
655 | catchsig(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 | ||||||
673 | static void | |||||
674 | register_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 | ||||||
692 | int | |||||
693 | auth_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 | ||||||
801 | static int | |||||
802 | write_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 | ||||||
854 | int | |||||
855 | auth_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 | ||||||
918 | int | |||||
919 | process_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 | ||||||
939 | static char * | |||||
940 | bintohex(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 | ||||||
958 | static void | |||||
959 | fprintfhex(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 | ||||||
968 | static int | |||||
969 | dump_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 */ | |||||
985 | static int | |||||
986 | dump_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 | ||||||
1034 | static int | |||||
1035 | extract_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 | ||||||
1059 | static int | |||||
1060 | eq_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 | ||||||
1073 | static int | |||||
1074 | match_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 | ||||||
1105 | static int | |||||
1106 | match_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 | ||||||
1114 | static int | |||||
1115 | merge_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 | ||||||
1178 | static Xauth * | |||||
1179 | copyAuth(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 | ||||||
1234 | typedef int (*YesNoFunc)(const char *, int, Xauth *, char *); | |||||
1235 | ||||||
1236 | static int | |||||
1237 | iterdpy (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 */ | |||||
1302 | static int | |||||
1303 | remove_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 | */ | |||||
1332 | int | |||||
1333 | print_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 | ||||||
1358 | static int | |||||
1359 | do_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 */ | |||||
1389 | static int | |||||
1390 | do_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 */ | |||||
1425 | static int | |||||
1426 | do_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 | */ | |||||
1435 | static int | |||||
1436 | do_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 | */ | |||||
1461 | static int | |||||
1462 | do_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 | */ | |||||
1524 | static int | |||||
1525 | do_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 | ||||||
1568 | static int | |||||
1569 | do_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 | */ | |||||
1672 | static int | |||||
1673 | do_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 | */ | |||||
1693 | static int | |||||
1694 | do_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 | */ | |||||
1722 | static Boolint alldone = False0; | |||||
1723 | ||||||
1724 | /* ARGSUSED */ | |||||
1725 | static int | |||||
1726 | do_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 */ | |||||
1737 | static int | |||||
1738 | do_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 | */ | |||||
1750 | static int | |||||
1751 | do_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 | ||||||
1814 | static int x_protocol_error; | |||||
1815 | static int | |||||
1816 | catch_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 | */ | |||||
1828 | static int | |||||
1829 | do_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 | } |