Annotation of src/usr.bin/sudo/visudo.c, Revision 1.9.2.1
1.1 millert 1: /*
1.9.2.1 ! millert 2: * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: *
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: *
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * 4. Products derived from this software may not be called "Sudo" nor
20: * may "Sudo" appear in their names without specific prior written
21: * permission from the author.
22: *
23: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: /*
36: * Lock the sudoers file for safe editing (ala vipw) and check for parse errors.
37: */
38:
39: #include "config.h"
40:
1.9.2.1 ! millert 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43: #include <sys/stat.h>
! 44: #include <sys/file.h>
! 45: #include <sys/wait.h>
1.1 millert 46: #include <stdio.h>
47: #ifdef STDC_HEADERS
1.9.2.1 ! millert 48: # include <stdlib.h>
! 49: # include <stddef.h>
! 50: #else
! 51: # ifdef HAVE_STDLIB_H
! 52: # include <stdlib.h>
! 53: # endif
1.1 millert 54: #endif /* STDC_HEADERS */
1.9.2.1 ! millert 55: #ifdef HAVE_STRING_H
! 56: # include <string.h>
! 57: #else
! 58: # ifdef HAVE_STRINGS_H
! 59: # include <strings.h>
! 60: # endif
! 61: #endif /* HAVE_STRING_H */
1.1 millert 62: #ifdef HAVE_UNISTD_H
63: #include <unistd.h>
64: #endif /* HAVE_UNISTD_H */
65: #include <ctype.h>
66: #include <pwd.h>
67: #include <time.h>
68: #include <signal.h>
69: #include <errno.h>
70: #include <fcntl.h>
71:
72: #include "sudo.h"
73: #include "version.h"
74:
75: #ifndef lint
1.9.2.1 ! millert 76: static const char rcsid[] = "$Sudo: visudo.c,v 1.146 2002/01/17 15:35:54 millert Exp $";
1.1 millert 77: #endif /* lint */
78:
79: /*
80: * Function prototypes
81: */
82: static void usage __P((void));
83: static char whatnow __P((void));
84: static RETSIGTYPE Exit __P((int));
85: static void setup_signals __P((void));
1.9.2.1 ! millert 86: static int run_command __P((char *, char **));
! 87: static int check_syntax __P((int));
1.1 millert 88: int command_matches __P((char *, char *, char *, char *));
89: int addr_matches __P((char *));
1.4 millert 90: int hostname_matches __P((char *, char *, char *));
1.3 millert 91: int netgr_matches __P((char *, char *, char *, char *));
1.1 millert 92: int usergr_matches __P((char *, char *));
93: void init_parser __P((void));
94: void yyrestart __P((FILE *));
95:
96: /*
97: * External globals exported by the parser
98: */
99: extern FILE *yyin, *yyout;
100: extern int errorlineno;
101: extern int pedantic;
1.9.2.1 ! millert 102: extern int quiet;
! 103:
! 104: /* For getopt(3) */
! 105: extern char *optarg;
! 106: extern int optind;
1.1 millert 107:
108: /*
109: * Globals
110: */
111: char **Argv;
112: char *sudoers = _PATH_SUDOERS;
113: char *stmp = _PATH_SUDOERS_TMP;
114: struct sudo_user sudo_user;
115: int parse_error = FALSE;
116:
117: int
118: main(argc, argv)
119: int argc;
120: char **argv;
121: {
122: char buf[MAXPATHLEN*2]; /* buffer used for copying files */
1.4 millert 123: char *Editor; /* editor to use */
1.9.2.1 ! millert 124: char *UserEditor; /* editor user wants to use */
! 125: char *EditorPath; /* colon-separated list of editors */
! 126: char *av[4]; /* argument vector for run_command */
! 127: int checkonly; /* only check existing file? */
1.1 millert 128: int sudoers_fd; /* sudoers file descriptor */
129: int stmp_fd; /* stmp file descriptor */
130: int n; /* length parameter */
1.9.2.1 ! millert 131: int ch; /* getopt char */
1.1 millert 132: time_t now; /* time now */
133: struct stat stmp_sb, sudoers_sb; /* to check for changes */
134:
135: /* Warn about aliases that are used before being defined. */
136: pedantic = 1;
137:
138: /*
139: * Parse command line options
140: */
141: Argv = argv;
142:
143: /*
144: * Arg handling.
145: */
1.9.2.1 ! millert 146: checkonly = 0;
! 147: while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) {
! 148: switch (ch) {
! 149: case 'V':
! 150: (void) printf("visudo version %s\n", version);
! 151: exit(0);
! 152: case 'c':
! 153: checkonly++; /* check mode */
! 154: break;
! 155: case 'f':
! 156: sudoers = optarg; /* sudoers file path */
! 157: easprintf(&stmp, "%s.tmp", optarg);
! 158: break;
! 159: case 's':
! 160: pedantic++; /* strict mode */
! 161: break;
! 162: case 'q':
! 163: quiet++; /* quiet mode */
! 164: break;
! 165: default:
! 166: usage();
1.1 millert 167: }
168: }
1.9.2.1 ! millert 169: argc -= optind;
! 170: argv += optind;
! 171: if (argc)
! 172: usage();
1.1 millert 173:
174: /* Mock up a fake sudo_user struct. */
175: user_host = user_shost = user_cmnd = "";
176: if ((sudo_user.pw = getpwuid(getuid())) == NULL) {
177: (void) fprintf(stderr, "%s: Can't find you in the passwd database.\n",
178: Argv[0]);
179: exit(1);
180: }
181:
1.4 millert 182: /* Setup defaults data structures. */
183: init_defaults();
1.1 millert 184:
1.9.2.1 ! millert 185: if (checkonly)
! 186: exit(check_syntax(quiet));
! 187:
1.1 millert 188: /*
1.3 millert 189: * Open sudoers, lock it and stat it.
190: * sudoers_fd must remain open throughout in order to hold the lock.
1.1 millert 191: */
1.6 millert 192: sudoers_fd = open(sudoers, O_RDWR | O_CREAT, SUDOERS_MODE);
1.3 millert 193: if (sudoers_fd == -1) {
194: (void) fprintf(stderr, "%s: %s: %s\n", Argv[0], sudoers,
195: strerror(errno));
1.9.2.1 ! millert 196: exit(1);
1.1 millert 197: }
1.3 millert 198: if (!lock_file(sudoers_fd, SUDO_TLOCK)) {
1.1 millert 199: (void) fprintf(stderr, "%s: sudoers file busy, try again later.\n",
200: Argv[0]);
201: exit(1);
202: }
1.3 millert 203: #ifdef HAVE_FSTAT
204: if (fstat(sudoers_fd, &sudoers_sb) == -1) {
1.1 millert 205: #else
1.3 millert 206: if (stat(sudoers, &sudoers_sb) == -1) {
1.1 millert 207: #endif
1.3 millert 208: (void) fprintf(stderr, "%s: can't stat %s: %s\n",
209: Argv[0], sudoers, strerror(errno));
1.9.2.1 ! millert 210: exit(1);
1.1 millert 211: }
212:
1.3 millert 213: /*
214: * Open sudoers temp file.
215: */
216: stmp_fd = open(stmp, O_WRONLY | O_CREAT | O_TRUNC, 0600);
217: if (stmp_fd < 0) {
218: (void) fprintf(stderr, "%s: %s: %s\n", Argv[0], stmp, strerror(errno));
219: exit(1);
220: }
221:
1.1 millert 222: /* Install signal handlers to clean up stmp if we are killed. */
223: setup_signals();
224:
225: /* Copy sudoers -> stmp and reset the mtime */
1.3 millert 226: if (sudoers_sb.st_size) {
1.1 millert 227: while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
228: if (write(stmp_fd, buf, n) != n) {
229: (void) fprintf(stderr, "%s: Write failed: %s\n", Argv[0],
230: strerror(errno));
231: Exit(-1);
232: }
233:
1.3 millert 234: (void) close(stmp_fd);
235: (void) touch(stmp, sudoers_sb.st_mtime);
1.4 millert 236:
237: /* Parse sudoers to pull in editor and env_editor conf values. */
238: if ((yyin = fopen(stmp, "r"))) {
239: yyout = stdout;
240: init_parser();
241: yyparse();
242: parse_error = FALSE;
243: yyrestart(yyin);
244: fclose(yyin);
245: }
1.3 millert 246: } else
247: (void) close(stmp_fd);
1.1 millert 248:
249: /*
1.9.2.1 ! millert 250: * Check EDITOR and VISUAL environment variables to see which editor
! 251: * the user wants to use (we may not end up using it though).
! 252: * If the path is not fully-qualified, make it so and check that
! 253: * the specified executable actually exists.
! 254: */
! 255: if ((UserEditor = getenv("EDITOR")) == NULL || *UserEditor == '\0')
! 256: UserEditor = getenv("VISUAL");
! 257: if (UserEditor && *UserEditor == '\0')
! 258: UserEditor = NULL;
! 259: else if (UserEditor) {
! 260: if (find_path(UserEditor, &Editor, getenv("PATH")) == FOUND) {
! 261: UserEditor = Editor;
! 262: } else {
! 263: if (def_flag(I_ENV_EDITOR)) {
! 264: /* If we are honoring $EDITOR this is a fatal error. */
! 265: (void) fprintf(stderr,
! 266: "%s: specified editor (%s) doesn't exist!\n",
! 267: Argv[0], UserEditor);
! 268: Exit(-1);
! 269: } else {
! 270: /* Otherwise, just ignore $EDITOR. */
! 271: UserEditor = NULL;
! 272: }
! 273: }
! 274: }
! 275:
! 276: /*
! 277: * See if we can use the user's choice of editors either because
! 278: * we allow any $EDITOR or because $EDITOR is in the allowable list.
1.4 millert 279: */
1.9.2.1 ! millert 280: Editor = EditorPath = NULL;
! 281: if (def_flag(I_ENV_EDITOR) && UserEditor)
! 282: Editor = UserEditor;
! 283: else if (UserEditor) {
! 284: struct stat editor_sb;
! 285: struct stat user_editor_sb;
! 286: char *base, *userbase;
! 287:
! 288: if (stat(UserEditor, &user_editor_sb) != 0) {
! 289: /* Should never happen since we already checked above. */
! 290: (void) fprintf(stderr, "%s: unable to stat editor (%s): %s\n",
! 291: Argv[0], UserEditor, strerror(errno));
! 292: Exit(-1);
! 293: }
! 294: EditorPath = estrdup(def_str(I_EDITOR));
! 295: Editor = strtok(EditorPath, ":");
! 296: do {
! 297: /*
! 298: * Both Editor and UserEditor should be fully qualified but
! 299: * check anyway...
! 300: */
! 301: if ((base = strrchr(Editor, '/')) == NULL)
! 302: continue;
! 303: if ((userbase = strrchr(UserEditor, '/')) == NULL) {
! 304: Editor = NULL;
! 305: break;
! 306: }
! 307: base++, userbase++;
! 308:
! 309: /*
! 310: * We compare the basenames first and then use stat to match
! 311: * for sure.
! 312: */
! 313: if (strcmp(base, userbase) == 0) {
! 314: if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode)
! 315: && (editor_sb.st_mode & 0000111) &&
! 316: editor_sb.st_dev == user_editor_sb.st_dev &&
! 317: editor_sb.st_ino == user_editor_sb.st_ino)
! 318: break;
! 319: }
! 320: } while ((Editor = strtok(NULL, ":")));
! 321: }
1.4 millert 322:
323: /*
1.9.2.1 ! millert 324: * Can't use $EDITOR, try each element of I_EDITOR until we
! 325: * find one that exists, is regular, and is executable.
1.1 millert 326: */
1.9.2.1 ! millert 327: if (Editor == NULL || *Editor == '\0') {
! 328: if (EditorPath != NULL)
! 329: free(EditorPath);
! 330: EditorPath = estrdup(def_str(I_EDITOR));
! 331: Editor = strtok(EditorPath, ":");
! 332: do {
! 333: if (sudo_goodpath(Editor))
! 334: break;
! 335: } while ((Editor = strtok(NULL, ":")));
! 336:
! 337: /* Bleah, none of the editors existed! */
! 338: if (Editor == NULL || *Editor == '\0') {
! 339: (void) fprintf(stderr, "%s: no editor found (editor path = %s)\n",
! 340: Argv[0], def_str(I_EDITOR));
1.1 millert 341: Exit(-1);
342: }
1.9.2.1 ! millert 343: }
! 344:
! 345: /*
! 346: * Edit the temp file and parse it (for sanity checking)
! 347: */
! 348: do {
! 349: char linestr[64];
! 350:
! 351: /* Build up argument vector for the command */
! 352: if ((av[0] = strrchr(Editor, '/')) != NULL)
! 353: av[0]++;
1.1 millert 354: else
1.9.2.1 ! millert 355: av[0] = Editor;
! 356: n = 1;
! 357: if (parse_error == TRUE) {
! 358: (void) snprintf(linestr, sizeof(linestr), "+%d", errorlineno);
! 359: av[n++] = linestr;
! 360: }
! 361: av[n++] = stmp;
! 362: av[n++] = NULL;
1.1 millert 363:
1.9.2.1 ! millert 364: /*
! 365: * Do the edit:
! 366: * We cannot check the editor's exit value against 0 since
! 367: * XPG4 specifies that vi's exit value is a function of the
! 368: * number of errors during editing (?!?!).
! 369: */
1.1 millert 370: now = time(NULL);
1.9.2.1 ! millert 371: if (run_command(Editor, av) != -1) {
1.1 millert 372: /*
373: * Sanity checks.
374: */
375: if (stat(stmp, &stmp_sb) < 0) {
376: (void) fprintf(stderr,
377: "%s: Can't stat temporary file (%s), %s unchanged.\n",
378: Argv[0], stmp, sudoers);
379: Exit(-1);
380: }
381: if (stmp_sb.st_size == 0) {
382: (void) fprintf(stderr,
383: "%s: Zero length temporary file (%s), %s unchanged.\n",
384: Argv[0], stmp, sudoers);
385: Exit(-1);
386: }
387:
388: /*
389: * Passed sanity checks so reopen stmp file and check
390: * for parse errors.
391: */
392: yyout = stdout;
393: if (parse_error)
394: yyin = freopen(stmp, "r", yyin);
395: else
396: yyin = fopen(stmp, "r");
397: if (yyin == NULL) {
398: (void) fprintf(stderr,
399: "%s: Can't re-open temporary file (%s), %s unchanged.\n",
400: Argv[0], stmp, sudoers);
401: Exit(-1);
402: }
403:
404: /* Clean slate for each parse */
1.5 millert 405: user_runas = NULL;
1.1 millert 406: init_defaults();
407: init_parser();
408:
409: /* Parse the sudoers file */
410: if (yyparse() && parse_error != TRUE) {
411: (void) fprintf(stderr,
412: "%s: Failed to parse temporary file (%s), unknown error.\n",
413: Argv[0], stmp);
414: parse_error = TRUE;
415: }
416: } else {
417: (void) fprintf(stderr,
1.9.2.1 ! millert 418: "%s: Editor (%s) failed, %s unchanged.\n", Argv[0],
! 419: Editor, sudoers);
1.1 millert 420: Exit(-1);
421: }
422:
423: /*
424: * Got an error, prompt the user for what to do now
425: */
426: if (parse_error == TRUE) {
427: switch (whatnow()) {
1.7 millert 428: case 'Q' : parse_error = FALSE; /* ignore parse error */
1.1 millert 429: break;
1.8 millert 430: case 'x' : if (sudoers_sb.st_size == 0)
431: unlink(sudoers);
432: Exit(0);
1.1 millert 433: break;
434: }
435: yyrestart(yyin); /* reset lexer */
436: }
437: } while (parse_error == TRUE);
438:
439: /*
440: * If the user didn't change the temp file, just unlink it.
441: */
442: if (sudoers_sb.st_mtime != now && sudoers_sb.st_mtime == stmp_sb.st_mtime &&
443: sudoers_sb.st_size == stmp_sb.st_size) {
444: (void) fprintf(stderr, "%s: sudoers file unchanged.\n", Argv[0]);
445: Exit(0);
446: }
447:
448: /*
449: * Change mode and ownership of temp file so when
450: * we move it to sudoers things are kosher.
451: */
452: if (chown(stmp, SUDOERS_UID, SUDOERS_GID)) {
453: (void) fprintf(stderr,
454: "%s: Unable to set (uid, gid) of %s to (%d, %d): %s\n",
455: Argv[0], stmp, SUDOERS_UID, SUDOERS_GID, strerror(errno));
456: Exit(-1);
457: }
458: if (chmod(stmp, SUDOERS_MODE)) {
459: (void) fprintf(stderr,
460: "%s: Unable to change mode of %s to %o: %s\n",
461: Argv[0], stmp, SUDOERS_MODE, strerror(errno));
462: Exit(-1);
463: }
464:
465: /*
466: * Now that we have a sane stmp file (parses ok) it needs to be
467: * rename(2)'d to sudoers. If the rename(2) fails we try using
468: * mv(1) in case stmp and sudoers are on different filesystems.
469: */
470: if (rename(stmp, sudoers)) {
471: if (errno == EXDEV) {
472: (void) fprintf(stderr,
473: "%s: %s and %s not on the same filesystem, using mv to rename.\n",
474: Argv[0], stmp, sudoers);
475:
1.9.2.1 ! millert 476: /* Build up argument vector for the command */
! 477: if ((av[0] = strrchr(_PATH_MV, '/')) != NULL)
! 478: av[0]++;
! 479: else
! 480: av[0] = _PATH_MV;
! 481: av[1] = stmp;
! 482: av[2] = sudoers;
! 483: av[3] = NULL;
1.1 millert 484:
1.9.2.1 ! millert 485: /* And run it... */
! 486: if (run_command(_PATH_MV, av)) {
1.1 millert 487: (void) fprintf(stderr,
1.9.2.1 ! millert 488: "%s: Command failed: '%s %s %s', %s unchanged.\n",
! 489: Argv[0], _PATH_MV, stmp, sudoers, sudoers);
1.1 millert 490: Exit(-1);
491: }
492: } else {
493: (void) fprintf(stderr, "%s: Error renaming %s, %s unchanged: %s\n",
494: Argv[0], stmp, sudoers, strerror(errno));
495: Exit(-1);
496: }
497: }
498:
1.3 millert 499: exit(0);
1.1 millert 500: }
501:
502: /*
503: * Dummy *_matches routines.
504: * These exist to allow us to use the same parser as sudo(8).
505: */
506: int
507: command_matches(cmnd, cmnd_args, path, sudoers_args)
508: char *cmnd;
509: char *cmnd_args;
510: char *path;
511: char *sudoers_args;
512: {
513: return(TRUE);
514: }
515:
516: int
517: addr_matches(n)
518: char *n;
1.4 millert 519: {
520: return(TRUE);
521: }
522:
523: int
524: hostname_matches(s, l, p)
525: char *s, *l, *p;
1.1 millert 526: {
527: return(TRUE);
528: }
529:
530: int
531: usergr_matches(g, u)
532: char *g, *u;
533: {
534: return(TRUE);
535: }
536:
537: int
1.3 millert 538: netgr_matches(n, h, sh, u)
539: char *n, *h, *sh, *u;
1.1 millert 540: {
541: return(TRUE);
1.2 millert 542: }
543:
544: void
545: set_fqdn()
546: {
547: return;
1.1 millert 548: }
549:
1.9.2.1 ! millert 550: int
! 551: user_is_exempt()
! 552: {
! 553: return(TRUE);
! 554: }
! 555:
! 556: void
! 557: init_envtables()
! 558: {
! 559: return;
! 560: }
! 561:
1.1 millert 562: /*
563: * Assuming a parse error occurred, prompt the user for what they want
564: * to do now. Returns the first letter of their choice.
565: */
566: static char
567: whatnow()
568: {
569: int choice, c;
570:
571: for (;;) {
572: (void) fputs("What now? ", stdout);
573: choice = getchar();
574: for (c = choice; c != '\n' && c != EOF;)
575: c = getchar();
576:
1.3 millert 577: switch (choice) {
578: case EOF:
579: choice = 'x';
580: /* FALLTHROUGH */
581: case 'e':
582: case 'x':
583: case 'Q':
584: return(choice);
585: default:
586: (void) puts("Options are:");
587: (void) puts(" (e)dit sudoers file again");
588: (void) puts(" e(x)it without saving changes to sudoers file");
589: (void) puts(" (Q)uit and save changes to sudoers file (DANGER!)\n");
1.1 millert 590: }
591: }
592: }
593:
594: /*
595: * Install signal handlers for visudo.
596: */
597: static void
598: setup_signals()
599: {
1.9.2.1 ! millert 600: sigaction_t sa;
1.1 millert 601:
602: /*
603: * Setup signal handlers to cleanup nicely.
604: */
1.9.2.1 ! millert 605: sigemptyset(&sa.sa_mask);
! 606: sa.sa_flags = SA_RESTART;
! 607: sa.sa_handler = Exit;
! 608: (void) sigaction(SIGTERM, &sa, NULL);
! 609: (void) sigaction(SIGHUP, &sa, NULL);
! 610: (void) sigaction(SIGINT, &sa, NULL);
! 611: (void) sigaction(SIGQUIT, &sa, NULL);
! 612: }
! 613:
! 614: static int
! 615: run_command(path, argv)
! 616: char *path;
! 617: char **argv;
! 618: {
! 619: int status;
! 620: pid_t pid;
! 621: sigset_t set, oset;
! 622:
! 623: (void) sigemptyset(&set);
! 624: (void) sigaddset(&set, SIGCHLD);
! 625: (void) sigprocmask(SIG_BLOCK, &set, &oset);
! 626:
! 627: switch (pid = fork()) {
! 628: case -1:
! 629: (void) fprintf(stderr,
! 630: "%s: unable to run %s: %s\n", Argv[0], path, strerror(errno));
! 631: Exit(-1);
! 632: break; /* NOTREACHED */
! 633: case 0:
! 634: (void) sigprocmask(SIG_SETMASK, &oset, NULL);
! 635: execv(path, argv);
! 636: (void) fprintf(stderr,
! 637: "%s: unable to run %s: %s\n", Argv[0], path, strerror(errno));
! 638: _exit(127);
! 639: break; /* NOTREACHED */
! 640: }
! 641:
! 642: #ifdef sudo_waitpid
! 643: pid = sudo_waitpid(pid, &status, 0);
1.1 millert 644: #else
1.9.2.1 ! millert 645: pid = wait(&status);
! 646: #endif
! 647:
! 648: (void) sigprocmask(SIG_SETMASK, &oset, NULL);
! 649:
! 650: /* XXX - should use WEXITSTATUS() */
! 651: return(pid == -1 ? -1 : (status >> 8));
! 652: }
! 653:
! 654: static int
! 655: check_syntax(quiet)
! 656: int quiet;
! 657: {
! 658:
! 659: if ((yyin = fopen(sudoers, "r")) == NULL) {
! 660: if (!quiet)
! 661: (void) fprintf(stderr, "%s: unable to open %s: %s\n", Argv[0],
! 662: sudoers, strerror(errno));
! 663: exit(1);
! 664: }
! 665: yyout = stdout;
! 666: init_parser();
! 667: if (yyparse() && parse_error != TRUE) {
! 668: if (!quiet)
! 669: (void) fprintf(stderr,
! 670: "%s: failed to parse %s file, unknown error.\n",
! 671: Argv[0], sudoers);
! 672: parse_error = TRUE;
! 673: }
! 674: if (!quiet){
! 675: if (parse_error)
! 676: (void) printf("parse error in %s near line %d\n", sudoers,
! 677: errorlineno);
! 678: else
! 679: (void) printf("%s file parsed OK\n", sudoers);
! 680: }
! 681:
! 682: return(parse_error == TRUE);
1.1 millert 683: }
684:
685: /*
686: * Unlink the sudoers temp file (if it exists) and exit.
687: * Used in place of a normal exit() and as a signal handler.
1.9.2.1 ! millert 688: * A positive parameter indicates we were called as a signal handler.
1.1 millert 689: */
690: static RETSIGTYPE
691: Exit(sig)
692: int sig;
693: {
1.9.2.1 ! millert 694: char *emsg = " exiting due to signal.\n";
1.1 millert 695:
1.9.2.1 ! millert 696: (void) unlink(stmp);
1.1 millert 697:
1.9.2.1 ! millert 698: if (sig > 0) {
! 699: write(STDERR_FILENO, Argv[0], strlen(Argv[0]));
! 700: write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
! 701: _exit(-sig);
! 702: }
! 703: exit(-sig);
1.1 millert 704: }
705:
706: static void
707: usage()
708: {
1.9.2.1 ! millert 709: (void) fprintf(stderr, "usage: %s [-c] [-f sudoers] [-q] [-s] [-V]\n",
! 710: Argv[0]);
1.1 millert 711: exit(1);
712: }