Пример #1
0
static int
do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
{
    char *path, *slash;
    char dir_out[4096], file_out[4096];
    struct tm *timeptr;
    time_t now;
    int error = 0;

    /*
     * Expand any strftime(3) escapes
     * XXX - want to pass timeptr to expand_iolog_path
     */
    time(&now);
    timeptr = localtime(&now);
    strftime(dir_out, sizeof(dir_out), tdir_out, timeptr);
    strftime(file_out, sizeof(file_out), tfile_out, timeptr);

    path = expand_iolog_path(NULL, dir_in, file_in, &slash);
    *slash = '\0';
    if (strcmp(path, dir_out) != 0) {
	warningx("%s: expected %s, got %s", dir_in, dir_out, path);
	error = 1;
    }
    if (strcmp(slash + 1, file_out) != 0) {
	warningx("%s: expected %s, got %s", file_in, file_out, slash + 1);
	error = 1;
    }

    return error;
}
Пример #2
0
int
fwtk_init(struct passwd *pw, sudo_auth *auth)
{
    static Cfg *confp;			/* Configuration entry struct */
    char resp[128];			/* Response from the server */

    if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
	warningx(_("unable to read fwtk config"));
	return AUTH_FATAL;
    }

    if (auth_open(confp)) {
	warningx(_("unable to connect to authentication server"));
	return AUTH_FATAL;
    }

    /* Get welcome message from auth server */
    if (auth_recv(resp, sizeof(resp))) {
	warningx(_("lost connection to authentication server"));
	return AUTH_FATAL;
    }
    if (strncmp(resp, "Authsrv ready", 13) != 0) {
	warningx(_("authentication server error:\n%s"), resp);
	return AUTH_FATAL;
    }

    return AUTH_SUCCESS;
}
Пример #3
0
/*
 * This function attempts to revert the relabeling done to the tty.
 * fd		   - referencing the opened ttyn
 * ttyn		   - name of tty to restore
 *
 * Returns zero on success, non-zero otherwise
 */
int
selinux_restore_tty(void)
{
    int retval = 0;
    security_context_t chk_tty_context = NULL;

    if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL)
	goto skip_relabel;

    /* Verify that the tty still has the context set by sudo. */
    if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) {
	warning("unable to fgetfilecon %s", se_state.ttyn);
	goto skip_relabel;
    }

    if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) {
	warningx("%s changed labels.", se_state.ttyn);
	goto skip_relabel;
    }

    if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0)
	warning("unable to restore context for %s", se_state.ttyn);

skip_relabel:
    if (se_state.ttyfd != -1) {
	close(se_state.ttyfd);
	se_state.ttyfd = -1;
    }
    if (chk_tty_context != NULL) {
	freecon(chk_tty_context);
	chk_tty_context = NULL;
    }
    return retval;
}
Пример #4
0
/* 
 * Set the exec and tty contexts in preparation for fork/exec.
 * Must run as root, before the uid change.
 * If ptyfd is not -1, it indicates we are running
 * in a pty and do not need to reset std{in,out,err}.
 * Returns 0 on success and -1 on failure.
 */
int
selinux_setup(const char *role, const char *type, const char *ttyn,
    int ptyfd)
{
    int rval = -1;

    /* Store the caller's SID in old_context. */
    if (getprevcon(&se_state.old_context)) {
	warning("failed to get old_context");
	goto done;
    }

    se_state.enforcing = security_getenforce();
    if (se_state.enforcing < 0) {
	warning("unable to determine enforcing mode.");
	goto done;
    }

#ifdef DEBUG
    warningx("your old context was %s", se_state.old_context);
#endif
    se_state.new_context = get_exec_context(se_state.old_context, role, type);
    if (!se_state.new_context)
	goto done;
    
    if (relabel_tty(ttyn, ptyfd) < 0) {
	warning("unable to setup tty context for %s", se_state.new_context);
	goto done;
    }

#ifdef DEBUG
    if (se_state.ttyfd != -1) {
	warningx("your old tty context is %s", se_state.tty_context);
	warningx("your new tty context is %s", se_state.new_tty_context);
    }
#endif

#ifdef HAVE_LINUX_AUDIT
    linux_audit_role_change(se_state.old_context, se_state.new_context,
	se_state.ttyn);
#endif

    rval = 0;

done:
    return rval;
}
Пример #5
0
Файл: logging.c Проект: CVi/sudo
void
log_error(int flags, const char *fmt, ...)
{
    int serrno = errno;
    char *message;
    char *logline;
    va_list ap;

    /* Expand printf-style format + args. */
    va_start(ap, fmt);
    evasprintf(&message, fmt, ap);
    va_end(ap);

    /* Become root if we are not already to avoid user interference */
    set_perms(PERM_ROOT|PERM_NOEXIT);

    if (ISSET(flags, MSG_ONLY))
	logline = message;
    else
	logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0);

    /*
     * Tell the user.
     */
    if (!ISSET(flags, NO_STDERR)) {
	if (ISSET(flags, USE_ERRNO))
	    warning("%s", message);
	else
	    warningx("%s", message);
    }
    if (logline != message)
        efree(message);

    /*
     * Send a copy of the error via mail.
     */
    if (!ISSET(flags, NO_MAIL))
	send_mail("%s", logline);

    /*
     * Log to syslog and/or a file.
     */
    if (def_syslog)
	do_syslog(def_syslog_badpri, logline);
    if (def_logfile)
	do_logfile(logline);

    efree(logline);

    restore_perms();

    if (!ISSET(flags, NO_EXIT)) {
	plugin_cleanup(0);
	siglongjmp(error_jmp, 1);
    }
}
Пример #6
0
int
securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
{
    struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;

    /* Re-initialize SecurID every time. */
    if (sd_init(sd) == 0) {
	/* The programmer's guide says username is 32 bytes */
	strlcpy(sd->username, pw->pw_name, 32);
	return AUTH_SUCCESS;
    } else {
	warningx(_("unable to contact the SecurID server"));
	return AUTH_FATAL;
    }
}
Пример #7
0
static void
sudoers_policy_close(int exit_status, int error_code)
{
    if (sigsetjmp(error_jmp, 1)) {
	/* called via error(), errorx() or log_error() */
	return;
    }

    /* We do not currently log the exit status. */
    if (error_code)
	warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code));

    /* Close the session we opened in sudoers_policy_init_session(). */
    if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
	(void)sudo_auth_end_session(runas_pw);

    /* Free remaining references to password and group entries. */
    pw_delref(sudo_user.pw);
    pw_delref(runas_pw);
    if (runas_gr != NULL)
	gr_delref(runas_gr);
    if (user_group_list != NULL)
	grlist_delref(user_group_list);
}
Пример #8
0
/*
 * Extract a regular file.
 */
static void
extract_file(struct archive *a, struct archive_entry *e, char **path)
{
	int mode;
	time_t mtime;
	struct stat sb;
	struct timeval tv[2];
	int cr, fd, text, warn, check;
	ssize_t len;
	unsigned char *p, *q, *end;

	mode = archive_entry_mode(e) & 0777;
	if (mode == 0)
		mode = 0644;
	mtime = archive_entry_mtime(e);

	/* look for existing file of same name */
recheck:
	if (lstat(*path, &sb) == 0) {
		if (u_opt || f_opt) {
			/* check if up-to-date */
			if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
				return;
			(void)unlink(*path);
		} else if (o_opt) {
			/* overwrite */
			(void)unlink(*path);
		} else if (n_opt) {
			/* do not overwrite */
			return;
		} else {
			check = handle_existing_file(path);
			if (check == 0)
				goto recheck;
			if (check == -1)
				return; /* do not overwrite */
		}
	} else {
		if (f_opt)
			return;
	}

	if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
		error("open('%s')", *path);

	/* loop over file contents and write to disk */
	info(" extracting: %s", *path);
	text = a_opt;
	warn = 0;
	cr = 0;
	for (int n = 0; ; n++) {
		if (tty && (n % 4) == 0)
			info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);

		len = archive_read_data(a, buffer, sizeof buffer);

		if (len < 0)
			ac(len);

		/* left over CR from previous buffer */
		if (a_opt && cr) {
			if (len == 0 || buffer[0] != '\n')
				if (write(fd, "\r", 1) != 1)
					error("write('%s')", *path);
			cr = 0;
		}

		/* EOF */
		if (len == 0)
			break;
		end = buffer + len;

		/*
		 * Detect whether this is a text file.  The correct way to
		 * do this is to check the least significant bit of the
		 * "internal file attributes" field of the corresponding
		 * file header in the central directory, but libarchive
		 * does not read the central directory, so we have to
		 * guess by looking for non-ASCII characters in the
		 * buffer.  Hopefully we won't guess wrong.  If we do
		 * guess wrong, we print a warning message later.
		 */
		if (a_opt && n == 0) {
			for (p = buffer; p < end; ++p) {
				if (!isascii((unsigned char)*p)) {
					text = 0;
					break;
				}
			}
		}

		/* simple case */
		if (!a_opt || !text) {
			if (write(fd, buffer, len) != len)
				error("write('%s')", *path);
			continue;
		}

		/* hard case: convert \r\n to \n (sigh...) */
		for (p = buffer; p < end; p = q + 1) {
			for (q = p; q < end; q++) {
				if (!warn && !isascii(*q)) {
					warningx("%s may be corrupted due"
					    " to weak text file detection"
					    " heuristic", *path);
					warn = 1;
				}
				if (q[0] != '\r')
					continue;
				if (&q[1] == end) {
					cr = 1;
					break;
				}
				if (q[1] == '\n')
					break;
			}
			if (write(fd, p, q - p) != q - p)
				error("write('%s')", *path);
		}
	}
	if (tty)
		info("  \b\b");
	if (text)
		info(" (text)");
	info("\n");

	/* set access and modification time */
	tv[0].tv_sec = now;
	tv[0].tv_usec = 0;
	tv[1].tv_sec = mtime;
	tv[1].tv_usec = 0;
	if (futimes(fd, tv) != 0)
		error("utimes('%s')", *path);
	if (close(fd) != 0)
		error("close('%s')", *path);
}
Пример #9
0
int
fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{
    char *pass;				/* Password from the user */
    char buf[SUDO_PASS_MAX + 12];	/* General prupose buffer */
    char resp[128];			/* Response from the server */
    int error;

    /* Send username to authentication server. */
    (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name);
restart:
    if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
	warningx(_("lost connection to authentication server"));
	return AUTH_FATAL;
    }

    /* Get the password/response from the user. */
    if (strncmp(resp, "challenge ", 10) == 0) {
	(void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]);
	pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
	if (pass && *pass == '\0') {
	    pass = auth_getpass("Response [echo on]: ",
		def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON);
	}
    } else if (strncmp(resp, "chalnecho ", 10) == 0) {
	pass = auth_getpass(&resp[10], def_passwd_timeout * 60,
	    SUDO_CONV_PROMPT_ECHO_OFF);
    } else if (strncmp(resp, "password", 8) == 0) {
	pass = auth_getpass(prompt, def_passwd_timeout * 60,
	    SUDO_CONV_PROMPT_ECHO_OFF);
    } else if (strncmp(resp, "display ", 8) == 0) {
	fprintf(stderr, "%s\n", &resp[8]);
	strlcpy(buf, "response dummy", sizeof(buf));
	goto restart;
    } else {
	warningx("%s", resp);
	return AUTH_FATAL;
    }
    if (!pass) {			/* ^C or error */
	return AUTH_INTR;
    }

    /* Send the user's response to the server */
    (void) snprintf(buf, sizeof(buf), "response '%s'", pass);
    if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
	warningx(_("lost connection to authentication server"));
	error = AUTH_FATAL;
	goto done;
    }

    if (strncmp(resp, "ok", 2) == 0) {
	error = AUTH_SUCCESS;
	goto done;
    }

    /* Main loop prints "Permission Denied" or insult. */
    if (strcmp(resp, "Permission Denied.") != 0)
	warningx("%s", resp);
    error = AUTH_FAILURE;
done:
    zero_bytes(pass, strlen(pass));
    zero_bytes(buf, strlen(buf));
    return error;
}
Пример #10
0
/*
 * Allocate and fill in the interfaces global variable with the
 * machine's ip addresses and netmasks.
 */
int
get_net_ifs(char **addrinfo)
{
    struct ifconf *ifconf;
    struct ifreq *ifr, ifr_tmp;
    struct sockaddr_in *sin;
    int ailen, i, len, n, sock, num_interfaces = 0;
    size_t buflen = sizeof(struct ifconf) + BUFSIZ;
    char *cp, *previfname = "", *ifconf_buf = NULL;
#ifdef _ISC
    struct strioctl strioctl;
#endif /* _ISC */
    debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
	error(1, _("unable to open socket"));

    /*
     * Get interface configuration or return.
     */
    for (;;) {
	ifconf_buf = emalloc(buflen);
	ifconf = (struct ifconf *) ifconf_buf;
	ifconf->ifc_len = buflen - sizeof(struct ifconf);
	ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));

#ifdef _ISC
	STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
#else
	/* Note that some kernels return EINVAL if the buffer is too small */
	if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
#endif /* _ISC */
	    goto done;

	/* Break out of loop if we have a big enough buffer. */
	if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
	    break;
	buflen += BUFSIZ;
	efree(ifconf_buf);
    }

    /* Allocate space for the maximum number of interfaces that could exist. */
    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
	debug_return_int(0);
    ailen = n * 2 * INET6_ADDRSTRLEN;
    *addrinfo = cp = emalloc(ailen);

    /* For each interface, store the ip address and netmask. */
    for (i = 0; i < ifconf->ifc_len; ) {
	/* Get a pointer to the current interface. */
	ifr = (struct ifreq *) &ifconf->ifc_buf[i];

	/* Set i to the subscript of the next interface. */
	i += sizeof(struct ifreq);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */

	/* Skip duplicates and interfaces with NULL addresses. */
	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	if (sin->sin_addr.s_addr == 0 ||
	    strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
	    continue;

	if (ifr->ifr_addr.sa_family != AF_INET)
		continue;

#ifdef SIOCGIFFLAGS
	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
#endif
	    ifr_tmp = *ifr;
	
	/* Skip interfaces marked "down" and "loopback". */
	if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
	    ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
		continue;

	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	len = snprintf(cp, ailen - (*addrinfo - cp),
	    "%s%s/", cp == *addrinfo ? "" : " ",
	    inet_ntoa(sin->sin_addr));
	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
	    warningx(_("load_interfaces: overflow detected"));
	    goto done;
	}
	cp += len;

	/* Stash the name of the interface we saved. */
	previfname = ifr->ifr_name;

	/* Get the netmask. */
	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
#ifdef _ISC
	STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
#else
	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
#endif /* _ISC */
	    sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
	    sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
	}
	sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
	len = snprintf(cp, ailen - (*addrinfo - cp),
	    "%s", inet_ntoa(sin->sin_addr));
	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
	    warningx(_("load_interfaces: overflow detected"));
	    goto done;
	}
	cp += len;
	num_interfaces++;
    }

done:
    efree(ifconf_buf);
    (void) close(sock);

    debug_return_int(num_interfaces);
}

#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */

/*
 * Stub function for those without SIOCGIFCONF or getifaddrs()
 */
int
get_net_ifs(char **addrinfo)
{
    debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
    debug_return_int(0);
}
Пример #11
0
/*
 * Command line argument parsing.
 * Sets nargc and nargv which corresponds to the argc/argv we'll use
 * for the command to be run (if we are running one).
 */
int
parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
    char ***env_addp)
{
    int mode = 0;		/* what mode is sudo to be run in? */
    int flags = 0;		/* mode flags */
    int valid_flags, ch;
    int i, j;
    char *cp, **env_add, **settings;
    int nenv = 0;
    int env_size = 32;

    env_add = emalloc2(env_size, sizeof(char *));

    /* Pass progname to plugin so it can call setprogname() */
    sudo_settings[ARG_PROGNAME].value = getprogname();

    /* First, check to see if we were invoked as "sudoedit". */
    if (strcmp(getprogname(), "sudoedit") == 0) {
	mode = MODE_EDIT;
	sudo_settings[ARG_SUDOEDIT].value = "true";
    }

    /* Load local IP addresses and masks. */
    if (get_net_ifs(&cp) > 0)
	sudo_settings[ARG_NET_ADDRS].value = cp;

    /* Returns true if the last option string was "--" */
#define got_end_of_args	(optind > 1 && argv[optind - 1][0] == '-' && \
	    argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')

    /* Returns true if next option is an environment variable */
#define is_envar (optind < argc && argv[optind][0] != '/' && \
	    strchr(argv[optind], '=') != NULL)

    /* Flags allowed when running a command */
    valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
		  MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL;
    /* XXX - should fill in settings at the end to avoid dupes */
    for (;;) {
	/*
	 * We disable arg permutation for GNU getopt().
	 * Some trickiness is required to allow environment variables
	 * to be interspersed with command line options.
	 */
	if ((ch = getopt(argc, argv, "+Aa:bC:c:D:Eeg:HhiKklnPp:r:Sst:U:u:Vv")) != -1) {
	    switch (ch) {
		case 'A':
		    SET(tgetpass_flags, TGP_ASKPASS);
		    break;
#ifdef HAVE_BSD_AUTH_H
		case 'a':
		    sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
		    break;
#endif
		case 'b':
		    SET(flags, MODE_BACKGROUND);
		    break;
		case 'C':
		    if (atoi(optarg) < 3) {
			warningx(_("the argument to -C must be a number greater than or equal to 3"));
			usage(1);
		    }
		    sudo_settings[ARG_CLOSEFROM].value = optarg;
		    break;
#ifdef HAVE_LOGIN_CAP_H
		case 'c':
		    sudo_settings[ARG_LOGIN_CLASS].value = optarg;
		    break;
#endif
		case 'D':
		    if ((debug_level = atoi(optarg)) < 1 || debug_level > 9) {
			warningx(_("the argument to -D must be between 1 and 9 inclusive"));
			usage(1);
		    }
		    sudo_settings[ARG_DEBUG_LEVEL].value = optarg;
		    break;
		case 'E':
		    sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
		    break;
		case 'e':
		    if (mode && mode != MODE_EDIT)
			usage_excl(1);
		    mode = MODE_EDIT;
		    sudo_settings[ARG_SUDOEDIT].value = "true";
		    valid_flags = MODE_NONINTERACTIVE;
		    break;
		case 'g':
		    runas_group = optarg;
		    sudo_settings[ARG_RUNAS_GROUP].value = optarg;
		    break;
		case 'H':
		    sudo_settings[ARG_SET_HOME].value = "true";
		    break;
		case 'h':
		    if (mode && mode != MODE_HELP) {
			if (strcmp(getprogname(), "sudoedit") != 0)
			    usage_excl(1);
		    }
		    mode = MODE_HELP;
		    valid_flags = 0;
		    break;
		case 'i':
		    sudo_settings[ARG_LOGIN_SHELL].value = "true";
		    SET(flags, MODE_LOGIN_SHELL);
		    break;
		case 'k':
		    sudo_settings[ARG_IGNORE_TICKET].value = "true";
		    break;
		case 'K':
		    sudo_settings[ARG_IGNORE_TICKET].value = "true";
		    if (mode && mode != MODE_KILL)
			usage_excl(1);
		    mode = MODE_KILL;
		    valid_flags = 0;
		    break;
		case 'l':
		    if (mode) {
			if (mode == MODE_LIST)
			    SET(flags, MODE_LONG_LIST);
			else
			    usage_excl(1);
		    }
		    mode = MODE_LIST;
		    valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
		    break;
		case 'n':
		    SET(flags, MODE_NONINTERACTIVE);
		    sudo_settings[ARG_NONINTERACTIVE].value = "true";
		    break;
		case 'P':
		    sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
		    break;
		case 'p':
		    sudo_settings[ARG_PROMPT].value = optarg;
		    break;
#ifdef HAVE_SELINUX
		case 'r':
		    sudo_settings[ARG_SELINUX_ROLE].value = optarg;
		    break;
		case 't':
		    sudo_settings[ARG_SELINUX_TYPE].value = optarg;
		    break;
#endif
		case 'S':
		    SET(tgetpass_flags, TGP_STDIN);
		    break;
		case 's':
		    sudo_settings[ARG_USER_SHELL].value = "true";
		    SET(flags, MODE_SHELL);
		    break;
		case 'U':
		    if ((getpwnam(optarg)) == NULL)
			errorx(1, _("unknown user: %s"), optarg);
		    list_user = optarg;
		    break;
		case 'u':
		    runas_user = optarg;
		    sudo_settings[ARG_RUNAS_USER].value = optarg;
		    break;
		case 'v':
		    if (mode && mode != MODE_VALIDATE)
			usage_excl(1);
		    mode = MODE_VALIDATE;
		    valid_flags = MODE_NONINTERACTIVE;
		    break;
		case 'V':
		    if (mode && mode != MODE_VERSION)
			usage_excl(1);
		    mode = MODE_VERSION;
		    valid_flags = 0;
		    break;
		default:
		    usage(1);
	    }
	} else if (!got_end_of_args && is_envar) {
	    if (nenv == env_size - 2) {
		env_size *= 2;
		env_add = erealloc3(env_add, env_size, sizeof(char *));
	    }
	    env_add[nenv++] = argv[optind];

	    /* Crank optind and resume getopt. */
	    optind++;
	} else {
	    /* Not an option or an environment variable -- we're done. */
	    break;
	}
    }
    env_add[nenv] = NULL;

    argc -= optind;
    argv += optind;

    if (!mode) {
	/* Defer -k mode setting until we know whether it is a flag or not */
	if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
	    if (argc == 0) {
		mode = MODE_INVALIDATE;	/* -k by itself */
		sudo_settings[ARG_IGNORE_TICKET].value = NULL;
		valid_flags = 0;
	    }
	}
	if (!mode)
	    mode = MODE_RUN;		/* running a command */
    }

    if (argc > 0 && mode == MODE_LIST)
	mode = MODE_CHECK;

    if (ISSET(flags, MODE_LOGIN_SHELL)) {
	if (ISSET(flags, MODE_SHELL)) {
	    warningx(_("you may not specify both the `-i' and `-s' options"));
	    usage(1);
	}
	if (ISSET(flags, MODE_PRESERVE_ENV)) {
	    warningx(_("you may not specify both the `-i' and `-E' options"));
	    usage(1);
	}
	SET(flags, MODE_SHELL);
    }
    if ((flags & valid_flags) != flags)
	usage(1);
    if (mode == MODE_EDIT &&
       (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
	if (ISSET(mode, MODE_PRESERVE_ENV))
	    warningx(_("the `-E' option is not valid in edit mode"));
	if (env_add[0] != NULL)
	    warningx(_("you may not specify environment variables in edit mode"));
	usage(1);
    }
    if ((runas_user != NULL || runas_group != NULL) &&
	!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
	usage(1);
    }
    if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
	warningx(_("the `-U' option may only be used with the `-l' option"));
	usage(1);
    }
    if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
	warningx(_("the `-A' and `-S' options may not be used together"));
	usage(1);
    }
    if ((argc == 0 && mode == MODE_EDIT) ||
	(argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
	usage(1);
    if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
	SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
	sudo_settings[ARG_IMPLIED_SHELL].value = "true";
    }

    if (mode == MODE_HELP)
	help();

    /*
     * For shell mode we need to rewrite argv
     */
    if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
	char **av;
	int ac;

	if (argc == 0) {
	    /* just the shell */
	    ac = argc + 1;
	    av = emalloc2(ac + 1, sizeof(char *));
	    memcpy(av + 1, argv, argc * sizeof(char *));
	} else {
	    /* shell -c "command" */
	    char *cmnd, *src, *dst;
	    size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
		strlen(argv[argc - 1]) + 1;

	    cmnd = dst = emalloc2(cmnd_size, 2);
	    for (av = argv; *av != NULL; av++) {
		for (src = *av; *src != '\0'; src++) {
		    /* quote potential meta characters */
		    if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-')
			*dst++ = '\\';
		    *dst++ = *src;
		}
		*dst++ = ' ';
	    }
	    if (cmnd != dst)
		dst--;  /* replace last space with a NUL */
	    *dst = '\0';

	    ac = 3;
	    av = emalloc2(ac + 1, sizeof(char *));
	    av[1] = "-c";
	    av[2] = cmnd;
	}
	av[0] = (char *)user_details.shell; /* plugin may override shell */
	av[ac] = NULL;

	argv = av;
	argc = ac;
    }

    /*
     * Format setting_pairs into settings array.
     */
    settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
    for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
	if (sudo_settings[i].value) {
	    sudo_debug(9, "settings: %s=%s", sudo_settings[i].name,
		sudo_settings[i].value);
	    settings[j] = fmt_string(sudo_settings[i].name,
		sudo_settings[i].value);
	    if (settings[j] == NULL)
		errorx(1, _("unable to allocate memory"));
	    j++;
	}
    }
    settings[j] = NULL;

    if (mode == MODE_EDIT) {
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
	/* Must have the command in argv[0]. */
	argc++;
	argv--;
	argv[0] = "sudoedit";
#else
	errorx(1, _("sudoedit is not supported on this platform"));
#endif
    }

    *settingsp = settings;
    *env_addp = env_add;
    *nargc = argc;
    *nargv = argv;
    return mode | flags;
}
Пример #12
0
int
sudo_rfc1938_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
{
    char challenge[256];
    static char *orig_prompt = NULL, *new_prompt = NULL;
    static int op_len, np_size;
    static struct RFC1938 rfc1938;
    debug_decl(sudo_rfc1938_setup, SUDO_DEBUG_AUTH)

    /* Stash a pointer to the rfc1938 struct if we have not initialized */
    if (!auth->data)
	auth->data = &rfc1938;

    /* Save the original prompt */
    if (orig_prompt == NULL) {
	orig_prompt = *promptp;
	op_len = strlen(orig_prompt);

	/* Ignore trailing colon (we will add our own) */
	if (orig_prompt[op_len - 1] == ':')
	    op_len--;
	else if (op_len >= 2 && orig_prompt[op_len - 1] == ' '
	    && orig_prompt[op_len - 2] == ':')
	    op_len -= 2;
    }

#ifdef HAVE_SKEY
    /* Close old stream */
    if (rfc1938.keyfile)
	(void) fclose(rfc1938.keyfile);
#endif

    /*
     * Look up the user and get the rfc1938 challenge.
     * If the user is not in the OTP db, only post a fatal error if
     * we are running alone (since they may just use a normal passwd).
     */
    if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) {
	if (IS_ONEANDONLY(auth)) {
	    warningx(_("you do not exist in the %s database"), auth->name);
	    debug_return_int(AUTH_FATAL);
	} else {
	    debug_return_int(AUTH_FAILURE);
	}
    }

    /* Get space for new prompt with embedded challenge */
    if (np_size < op_len + strlen(challenge) + 7) {
	np_size = op_len + strlen(challenge) + 7;
	new_prompt = (char *) erealloc(new_prompt, np_size);
    }

    if (def_long_otp_prompt)
	(void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt);
    else
	(void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len,
	    orig_prompt, challenge);

    *promptp = new_prompt;
    debug_return_int(AUTH_SUCCESS);
}
Пример #13
0
/*
 * Returns a new security context based on the old context and the
 * specified role and type.
 */
security_context_t
get_exec_context(security_context_t old_context, const char *role, const char *type)
{
    security_context_t new_context = NULL;
    context_t context = NULL;
    char *typebuf = NULL;
    
    /* We must have a role, the type is optional (we can use the default). */
    if (!role) {
	warningx("you must specify a role for type %s", type);
	errno = EINVAL;
	return NULL;
    }
    if (!type) {
	if (get_default_type(role, &typebuf)) {
	    warningx("unable to get default type for role %s", role);
	    errno = EINVAL;
	    return NULL;
	}
	type = typebuf;
    }
    
    /* 
     * Expand old_context into a context_t so that we extract and modify 
     * its components easily. 
     */
    context = context_new(old_context);
    
    /*
     * Replace the role and type in "context" with the role and
     * type we will be running the command as.
     */
    if (context_role_set(context, role)) {
	warning("failed to set new role %s", role);
	goto bad;
    }
    if (context_type_set(context, type)) {
	warning("failed to set new type %s", type);
	goto bad;
    }
      
    /*
     * Convert "context" back into a string and verify it.
     */
    new_context = estrdup(context_str(context));
    if (security_check_context(new_context) < 0) {
	warningx("%s is not a valid context", new_context);
	errno = EINVAL;
	goto bad;
    }

#ifdef DEBUG
    warningx("Your new context is %s", new_context);
#endif

    context_free(context);
    return new_context;

bad:
    free(typebuf);
    context_free(context);
    freecon(new_context);
    return NULL;
}
Пример #14
0
/*
 * Extract a zipfile entry: first perform some sanity checks to ensure
 * that it is either a directory or a regular file and that the path is
 * not absolute and does not try to break out of the current directory;
 * then call either extract_dir() or extract_file() as appropriate.
 *
 * This is complicated a bit by the various ways in which we need to
 * manipulate the path name.  Case conversion (if requested by the -L
 * option) happens first, but the include / exclude patterns are applied
 * to the full converted path name, before the directory part of the path
 * is removed in accordance with the -j option.  Sanity checks are
 * intentionally done earlier than they need to be, so the user will get a
 * warning about insecure paths even for files or directories which
 * wouldn't be extracted anyway.
 */
static void
extract(struct archive *a, struct archive_entry *e)
{
	char *pathname, *realpathname;
	mode_t filetype;
	char *p, *q;

	pathname = pathdup(archive_entry_pathname(e));
	filetype = archive_entry_filetype(e);

	/* sanity checks */
	if (pathname[0] == '/' ||
	    strncmp(pathname, "../", 3) == 0 ||
	    strstr(pathname, "/../") != NULL) {
		warningx("skipping insecure entry '%s'", pathname);
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* I don't think this can happen in a zipfile.. */
	if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
		warningx("skipping non-regular entry '%s'", pathname);
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* skip directories in -j case */
	if (S_ISDIR(filetype) && j_opt) {
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* apply include / exclude patterns */
	if (!accept_pathname(pathname)) {
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* apply -j and -d */
	if (j_opt) {
		for (p = q = pathname; *p; ++p)
			if (*p == '/')
				q = p + 1;
		realpathname = pathcat(d_arg, q);
	} else {
		realpathname = pathcat(d_arg, pathname);
	}

	/* ensure that parent directory exists */
	make_parent(realpathname);

	if (S_ISDIR(filetype))
		extract_dir(a, e, realpathname);
	else
		extract_file(a, e, &realpathname);

	free(realpathname);
	free(pathname);
}
Пример #15
0
/*
 * Tell which options are mutually exclusive and exit.
 */
static void
usage_excl(int fatal)
{
    warningx(_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
    usage(fatal);
}
Пример #16
0
static void
extract_stdout(struct archive *a, struct archive_entry *e)
{
	char *pathname;
	mode_t filetype;
	int cr, text, warn;
	ssize_t len;
	unsigned char *p, *q, *end;

	pathname = pathdup(archive_entry_pathname(e));
	filetype = archive_entry_filetype(e);

	/* I don't think this can happen in a zipfile.. */
	if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
		warningx("skipping non-regular entry '%s'", pathname);
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* skip directories in -j case */
	if (S_ISDIR(filetype)) {
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	/* apply include / exclude patterns */
	if (!accept_pathname(pathname)) {
		ac(archive_read_data_skip(a));
		free(pathname);
		return;
	}

	if (c_opt)
		info("x %s\n", pathname);

	text = a_opt;
	warn = 0;
	cr = 0;
	for (int n = 0; ; n++) {
		len = archive_read_data(a, buffer, sizeof buffer);

		if (len < 0)
			ac(len);

		/* left over CR from previous buffer */
		if (a_opt && cr) {
			if (len == 0 || buffer[0] != '\n') {
				if (fwrite("\r", 1, 1, stderr) != 1)
					error("write('%s')", pathname);
			}
			cr = 0;
		}

		/* EOF */
		if (len == 0)
			break;
		end = buffer + len;

		/*
		 * Detect whether this is a text file.  The correct way to
		 * do this is to check the least significant bit of the
		 * "internal file attributes" field of the corresponding
		 * file header in the central directory, but libarchive
		 * does not read the central directory, so we have to
		 * guess by looking for non-ASCII characters in the
		 * buffer.  Hopefully we won't guess wrong.  If we do
		 * guess wrong, we print a warning message later.
		 */
		if (a_opt && n == 0) {
			for (p = buffer; p < end; ++p) {
				if (!isascii((unsigned char)*p)) {
					text = 0;
					break;
				}
			}
		}

		/* simple case */
		if (!a_opt || !text) {
			if (fwrite(buffer, 1, len, stdout) != (size_t)len)
				error("write('%s')", pathname);
			continue;
		}

		/* hard case: convert \r\n to \n (sigh...) */
		for (p = buffer; p < end; p = q + 1) {
			for (q = p; q < end; q++) {
				if (!warn && !isascii(*q)) {
					warningx("%s may be corrupted due"
					    " to weak text file detection"
					    " heuristic", pathname);
					warn = 1;
				}
				if (q[0] != '\r')
					continue;
				if (&q[1] == end) {
					cr = 1;
					break;
				}
				if (q[1] == '\n')
					break;
			}
			if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p))
				error("write('%s')", pathname);
		}
	}

	free(pathname);
}
void
set_project(struct passwd *pw)
{
    struct project proj;
    char buf[PROJECT_BUFSZ];
    int errval;
    debug_decl(set_project, SUDO_DEBUG_UTIL)

    /*
     * Collect the default project for the user and settaskid
     */
    setprojent();
    if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
	errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
	switch(errval) {
	case 0:
	    break;
	case SETPROJ_ERR_TASK:
	    switch (errno) {
	    case EAGAIN:
		warningx(U_("resource control limit has been reached"));
		break;
	    case ESRCH:
		warningx(U_("user \"%s\" is not a member of project \"%s\""),
		    pw->pw_name, proj.pj_name);
		break;
	    case EACCES:
		warningx(U_("the invoking task is final"));
		break;
	    default:
		warningx(U_("could not join project \"%s\""), proj.pj_name);
	    }
	case SETPROJ_ERR_POOL:
	    switch (errno) {
	    case EACCES:
		warningx(U_("no resource pool accepting default bindings "
		    "exists for project \"%s\""), proj.pj_name);
		break;
	    case ESRCH:
		warningx(U_("specified resource pool does not exist for "
		    "project \"%s\""), proj.pj_name);
		break;
	    default:
		warningx(U_("could not bind to default resource pool for "
		    "project \"%s\""), proj.pj_name);
	    }
	    break;
	default:
	    if (errval <= 0) {
		warningx(U_("setproject failed for project \"%s\""), proj.pj_name);
	    } else {
		warningx(U_("warning, resource control assignment failed for "
		    "project \"%s\""), proj.pj_name);
	    }
	}
    } else {
	warning("getdefaultproj");
    }
    endprojent();
    debug_return;
}
Пример #18
0
static int
sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
    sudo_printf_t plugin_printf, char * const settings[],
    char * const user_info[], char * const envp[])
{
    volatile int sources = 0;
    sigaction_t sa;
    struct sudo_nss *nss;

    if (!sudo_conv)
	sudo_conv = conversation;
    if (!sudo_printf)
	sudo_printf = plugin_printf;

    if (sigsetjmp(error_jmp, 1)) {
	/* called via error(), errorx() or log_error() */
	rewind_perms();
	return -1;
    }

    bindtextdomain("sudoers", LOCALEDIR);

    /*
     * Signal setup:
     *	Ignore keyboard-generated signals so the user cannot interrupt
     *  us at some point and avoid the logging.
     *  Install handler to wait for children when they exit.
     */
    zero_bytes(&sa, sizeof(sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = SIG_IGN;
    (void) sigaction(SIGINT, &sa, &saved_sa_int);
    (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
    (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);

    sudo_setpwent();
    sudo_setgrent();

    /* Initialize environment functions (including replacements). */
    env_init(envp);

    /* Setup defaults data structures. */
    init_defaults();

    /* Parse settings and user_info */
    sudo_mode = deserialize_info(settings, user_info);

    init_vars(envp);		/* XXX - move this later? */

    /* Parse nsswitch.conf for sudoers order. */
    snl = sudo_read_nss();

    /* LDAP or NSS may modify the euid so we need to be root for the open. */
    set_perms(PERM_INITIAL);
    set_perms(PERM_ROOT);

    /* Open and parse sudoers, set global defaults */
    tq_foreach_fwd(snl, nss) {
	if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
	    sources++;
	    if (nss->setdefs(nss) != 0)
		log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
	}
    }
    if (sources == 0) {
	warningx(_("no valid sudoers sources found, quitting"));
	return -1;
    }

    /* XXX - collect post-sudoers parse settings into a function */

    /*
     * Initialize external group plugin, if any.
     */
    if (def_group_plugin) {
	if (group_plugin_load(def_group_plugin) != TRUE)
	    def_group_plugin = NULL;
    }

    /*
     * Set runas passwd/group entries based on command line or sudoers.
     * Note that if runas_group was specified without runas_user we
     * defer setting runas_pw so the match routines know to ignore it.
     */
    if (runas_group != NULL) {
	set_runasgr(runas_group);
	if (runas_user != NULL)
	    set_runaspw(runas_user);
    } else
	set_runaspw(runas_user ? runas_user : def_runas_default);

    if (!update_defaults(SETDEF_RUNAS))
	log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));

    if (def_fqdn)
	set_fqdn();	/* deferred until after sudoers is parsed */

    /* Set login class if applicable. */
    set_loginclass(sudo_user.pw);

    restore_perms();

    return TRUE;
}
Пример #19
0
/*
 * Load the specified plugin and run its init function.
 * Returns -1 if unable to open the plugin, else it returns
 * the value from the plugin's init function.
 */
int
group_plugin_load(char *plugin_info)
{
    struct stat sb;
    char *args, path[PATH_MAX];
    char **argv = NULL;
    int len, rc = -1;
    debug_decl(group_plugin_load, SUDO_DEBUG_UTIL)

    /*
     * Fill in .so path and split out args (if any).
     */
    if ((args = strpbrk(plugin_info, " \t")) != NULL) {
	len = snprintf(path, sizeof(path), "%s%.*s",
	    (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "",
	    (int)(args - plugin_info), plugin_info);
	args++;
    } else {
	len = snprintf(path, sizeof(path), "%s%s",
	    (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info);
    }
    if (len <= 0 || len >= sizeof(path)) {
	errno = ENAMETOOLONG;
	warning("%s%s",
	    (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info);
	goto done;
    }

    /* Sanity check plugin path. */
    if (stat(path, &sb) != 0) {
	warning("%s", path);
	goto done;
    }
    if (sb.st_uid != ROOT_UID) {
	warningx(_("%s must be owned by uid %d"), path, ROOT_UID);
	goto done;
    }
    if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
	warningx(_("%s must only be writable by owner"), path);
	goto done;
    }

    /* Open plugin and map in symbol. */
    group_handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
    if (!group_handle) {
	warningx(_("unable to dlopen %s: %s"), path, dlerror());
	goto done;
    }
    group_plugin = dlsym(group_handle, "group_plugin");
    if (group_plugin == NULL) {
	warningx(_("unable to find symbol \"group_plugin\" in %s"), path);
	goto done;
    }

    if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
	warningx(_("%s: incompatible group plugin major version %d, expected %d"),
	    path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version),
	    GROUP_API_VERSION_MAJOR);
	goto done;
    }

    /*
     * Split args into a vector if specified.
     */
    if (args != NULL) {
	int ac = 0;
	bool wasblank = true;
	char *cp;

        for (cp = args; *cp != '\0'; cp++) {
            if (isblank((unsigned char)*cp)) {
                wasblank = true;
            } else if (wasblank) {
                wasblank = false;
                ac++;
            }
        }
	if (ac != 0) 	{
	    argv = emalloc2(ac, sizeof(char *));
	    ac = 0;
	    for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
		argv[ac++] = cp;
	}
    }

    rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);

done:
    efree(argv);

    if (rc != true) {
	if (group_handle != NULL) {
	    dlclose(group_handle);
	    group_handle = NULL;
	    group_plugin = NULL;
	}
    }

    debug_return_bool(rc);
}
Пример #20
0
static int
sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
    char **command_infop[], char **argv_out[], char **user_env_out[])
{
    static char *command_info[32]; /* XXX */
    char **edit_argv = NULL;
    struct sudo_nss *nss;
    int cmnd_status = -1, validated;
    volatile int info_len = 0;
    volatile int rval = TRUE;

    if (sigsetjmp(error_jmp, 1)) {
	/* error recovery via error(), errorx() or log_error() */
	rval = -1;
	goto done;
    }

    /* Is root even allowed to run sudo? */
    if (user_uid == 0 && !def_root_sudo) {
        warningx(_("sudoers specifies that root is not allowed to sudo"));
        goto bad;
    }    

    /* Check for -C overriding def_closefrom. */
    if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
	if (!def_closefrom_override) {
	    warningx(_("you are not permitted to use the -C option"));
	    goto bad;
	}
	def_closefrom = user_closefrom;
    }

    set_perms(PERM_INITIAL);

    /* Environment variables specified on the command line. */
    if (env_add != NULL && env_add[0] != NULL)
	sudo_user.env_vars = env_add;

    /*
     * Make a local copy of argc/argv, with special handling
     * for pseudo-commands and the '-i' option.
     */
    if (argc == 0) {
	NewArgc = 1;
	NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
	NewArgv[0] = user_cmnd;
	NewArgv[1] = NULL;
    } else {
	/* Must leave an extra slot before NewArgv for bash's --login */
	NewArgc = argc;
	NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
	memcpy(++NewArgv, argv, argc * sizeof(char *));
	NewArgv[NewArgc] = NULL;
	if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
	    NewArgv[0] = estrdup(runas_pw->pw_shell);
    }

    /* If given the -P option, set the "preserve_groups" flag. */
    if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
	def_preserve_groups = TRUE;

    /* Find command in path */
    cmnd_status = set_cmnd();
    if (cmnd_status == -1) {
	rval = -1;
	goto done;
    }

#ifdef HAVE_SETLOCALE
    if (!setlocale(LC_ALL, def_sudoers_locale)) {
	warningx(_("unable to set locale to \"%s\", using \"C\""),
	    def_sudoers_locale);
	setlocale(LC_ALL, "C");
    }
#endif

    /*
     * Check sudoers sources.
     */
    validated = FLAG_NO_USER | FLAG_NO_HOST;
    tq_foreach_fwd(snl, nss) {
	validated = nss->lookup(nss, validated, pwflag);

	if (ISSET(validated, VALIDATE_OK)) {
	    /* Handle "= auth" in netsvc.conf */
	    if (nss->ret_if_found)
		break;
	} else {
	    /* Handle [NOTFOUND=return] */
	    if (nss->ret_if_notfound)
		break;
	}
    }
Пример #21
0
/*
 * Fill in the interfaces string with the machine's ip addresses and netmasks
 * and return the number of interfaces found.
 */
int
get_net_ifs(char **addrinfo)
{
    struct ifaddrs *ifa, *ifaddrs;
    struct sockaddr_in *sin;
#ifdef HAVE_STRUCT_IN6_ADDR
    struct sockaddr_in6 *sin6;
    char addrbuf[INET6_ADDRSTRLEN];
#endif
    int ailen, i, len, num_interfaces = 0;
    char *cp;
    debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)

    if (getifaddrs(&ifaddrs))
	debug_return_int(0);

    /* Allocate space for the interfaces info string. */
    for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
	/* Skip interfaces marked "down" and "loopback". */
	if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
	    !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
	    continue;

	switch (ifa->ifa_addr->sa_family) {
	    case AF_INET:
#ifdef HAVE_STRUCT_IN6_ADDR
	    case AF_INET6:
#endif
		num_interfaces++;
		break;
	}
    }
    if (num_interfaces == 0)
	debug_return_int(0);
    ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
    *addrinfo = cp = emalloc(ailen);

    /* Store the IP addr/netmask pairs. */
    for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
	/* Skip interfaces marked "down" and "loopback". */
	if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
	    !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
		continue;

	switch (ifa->ifa_addr->sa_family) {
	    case AF_INET:
		sin = (struct sockaddr_in *)ifa->ifa_addr;
		len = snprintf(cp, ailen - (*addrinfo - cp),
		    "%s%s/", cp == *addrinfo ? "" : " ",
		    inet_ntoa(sin->sin_addr));
		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
		    warningx(_("load_interfaces: overflow detected"));
		    goto done;
		}
		cp += len;

		sin = (struct sockaddr_in *)ifa->ifa_netmask;
		len = snprintf(cp, ailen - (*addrinfo - cp),
		    "%s", inet_ntoa(sin->sin_addr));
		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
		    warningx(_("load_interfaces: overflow detected"));
		    goto done;
		}
		cp += len;
		break;
#ifdef HAVE_STRUCT_IN6_ADDR
	    case AF_INET6:
		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
		inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
		len = snprintf(cp, ailen - (*addrinfo - cp),
		    "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
		    warningx(_("load_interfaces: overflow detected"));
		    goto done;
		}
		cp += len;

		sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
		inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
		len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
		if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
		    warningx(_("load_interfaces: overflow detected"));
		    goto done;
		}
		cp += len;
		break;
#endif /* HAVE_STRUCT_IN6_ADDR */
	}
    }

done:
#ifdef HAVE_FREEIFADDRS
    freeifaddrs(ifaddrs);
#else
    efree(ifaddrs);
#endif
    debug_return_int(num_interfaces);
}