open_sudoers(const char *file, bool doedit, bool *keepopen)
{
    struct stat sb;
    FILE *fp = NULL;
    bool perm_root = false;
    debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN);

    if (!set_perms(PERM_SUDOERS))
	debug_return_ptr(NULL);

again:
    switch (sudo_secure_file(file, sudoers_uid, sudoers_gid, &sb)) {
	case SUDO_PATH_SECURE:
	    /*
	     * If we are expecting sudoers to be group readable by
	     * SUDOERS_GID but it is not, we must open the file as root,
	     * not uid 1.
	     */
	    if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) {
		if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) {
		    if (!perm_root) {
			if (!restore_perms() || !set_perms(PERM_ROOT))
			    debug_return_ptr(NULL);
		    }
		}
	    }
	    /*
	     * Open file and make sure we can read it so we can present
	     * the user with a reasonable error message (unlike the lexer).
	     */
	    if ((fp = fopen(file, "r")) == NULL) {
		log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), file);
	    } else {
		if (sb.st_size != 0 && fgetc(fp) == EOF) {
		    log_warning(SLOG_SEND_MAIL,
			N_("unable to read %s"), file);
		    fclose(fp);
		    fp = NULL;
		} else {
		    /* Rewind fp and set close on exec flag. */
		    rewind(fp);
		    (void) fcntl(fileno(fp), F_SETFD, 1);
		}
	    }
	    break;
	case SUDO_PATH_MISSING:
	    /*
	     * If we tried to stat() sudoers as non-root but got EACCES,
	     * try again as root.
	     */
	    if (errno == EACCES && geteuid() != ROOT_UID) {
		int serrno = errno;
		if (restore_perms()) {
		    if (!set_perms(PERM_ROOT))
			debug_return_ptr(NULL);
		    perm_root = true;
		    goto again;
		}
		errno = serrno;
	    }
	    log_warning(SLOG_SEND_MAIL, N_("unable to stat %s"), file);
	    break;
	case SUDO_PATH_BAD_TYPE:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is not a regular file"), file);
	    break;
	case SUDO_PATH_WRONG_OWNER:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is owned by uid %u, should be %u"), file,
		(unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
	    break;
	case SUDO_PATH_WORLD_WRITABLE:
	    log_warningx(SLOG_SEND_MAIL, N_("%s is world writable"), file);
	    break;
	case SUDO_PATH_GROUP_WRITABLE:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is owned by gid %u, should be %u"), file,
		(unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
	    break;
	default:
	    /* NOTREACHED */
	    break;
    }

    if (!restore_perms()) {
	/* unable to change back to root */
	if (fp != NULL) {
	    fclose(fp);
	    fp = NULL;
	}
    }

    debug_return_ptr(fp);
}
open_sudoers(const char *file, bool doedit, bool *keepopen)
{
    struct stat sb;
    FILE *fp = NULL;
    bool perm_root = false;
    debug_decl(open_sudoers, SUDOERS_DEBUG_PLUGIN);

    if (!set_perms(PERM_SUDOERS))
	debug_return_ptr(NULL);

again:
    switch (sudo_secure_file(file, sudoers_uid, sudoers_gid, &sb)) {
	case SUDO_PATH_SECURE:
	     
	    if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) {
		if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) {
		    if (!perm_root) {
			if (!restore_perms() || !set_perms(PERM_ROOT))
			    debug_return_ptr(NULL);
		    }
		}
	    }
	     
	    if ((fp = fopen(file, "r")) == NULL) {
		log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), file);
	    } else {
		if (sb.st_size != 0 && fgetc(fp) == EOF) {
		    log_warning(SLOG_SEND_MAIL,
			N_("unable to read %s"), file);
		    fclose(fp);
		    fp = NULL;
		} else {
		     
		    rewind(fp);
		    (void) fcntl(fileno(fp), F_SETFD, 1);
		}
	    }
	    break;
	case SUDO_PATH_MISSING:
	     
	    if (errno == EACCES && geteuid() != ROOT_UID) {
		int serrno = errno;
		if (restore_perms()) {
		    if (!set_perms(PERM_ROOT))
			debug_return_ptr(NULL);
		    perm_root = true;
		    goto again;
		}
		errno = serrno;
	    }
	    log_warning(SLOG_SEND_MAIL, N_("unable to stat %s"), file);
	    break;
	case SUDO_PATH_BAD_TYPE:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is not a regular file"), file);
	    break;
	case SUDO_PATH_WRONG_OWNER:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is owned by uid %u, should be %u"), file,
		(unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
	    break;
	case SUDO_PATH_WORLD_WRITABLE:
	    log_warningx(SLOG_SEND_MAIL, N_("%s is world writable"), file);
	    break;
	case SUDO_PATH_GROUP_WRITABLE:
	    log_warningx(SLOG_SEND_MAIL,
		N_("%s is owned by gid %u, should be %u"), file,
		(unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
	    break;
	default:
	     
	    break;
    }

    if (!restore_perms()) {
	 
	if (fp != NULL) {
	    fclose(fp);
	    fp = NULL;
	}
    }

    debug_return_ptr(fp);
}