示例#1
0
/*
 * Similar to putenv(3) but operates on sudo's private copy of the
 * environment (not environ) and it always overwrites.  The dupcheck param
 * determines whether we need to verify that the variable is not already set.
 * Will only overwrite an existing variable if overwrite is set.
 */
static void
sudo_putenv(char *str, int dupcheck, int overwrite)
{
    char **ep;
    size_t len;
    int found = FALSE;

    /* Make sure there is room for the new entry plus a NULL. */
    if (env.env_len + 2 > env.env_size) {
	env.env_size += 128;
	env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
#ifdef ENV_DEBUG
	memset(env.envp + env.env_len, 0,
	    (env.env_size - env.env_len) * sizeof(char *));
#endif
    }

#ifdef ENV_DEBUG
    if (env.envp[env.env_len] != NULL)
	errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));
#endif

    if (dupcheck) {
	len = (strchr(str, '=') - str) + 1;
	for (ep = env.envp; !found && *ep != NULL; ep++) {
	    if (strncmp(str, *ep, len) == 0) {
		if (overwrite)
		    *ep = str;
		found = TRUE;
	    }
	}
	/* Prune out duplicate variables. */
	if (found && overwrite) {
	    while (*ep != NULL) {
		if (strncmp(str, *ep, len) == 0) {
		    char **cur = ep;
		    while ((*cur = *(cur + 1)) != NULL)
			cur++;
		} else {
		    ep++;
		}
	    }
	    env.env_len = ep - env.envp;
	}
    }

    if (!found) {
	ep = env.envp + env.env_len;
	env.env_len++;
	*ep++ = str;
	*ep = NULL;
    }
}
示例#2
0
/*
 * Allocate and fill in the interfaces global variable with the
 * machine's ip addresses and netmasks.
 */
void
load_interfaces()
{
    struct ifconf *ifconf;
    struct ifreq *ifr, ifr_tmp;
    struct sockaddr_in *sin;
    int sock, n, i;
    size_t len = sizeof(struct ifconf) + BUFSIZ;
    char *previfname = "", *ifconf_buf = NULL;
#ifdef _ISC
    struct strioctl strioctl;
#endif /* _ISC */

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

    /*
     * Get interface configuration or return (leaving num_interfaces == 0)
     */
    for (;;) {
	ifconf_buf = erealloc(ifconf_buf, len);
	ifconf = (struct ifconf *) ifconf_buf;
	ifconf->ifc_len = len - sizeof(struct ifconf);
	ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));

#ifdef _ISC
	STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
	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 */
	    efree(ifconf_buf);
	    (void) close(sock);
	    return;
	}

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

    /* Allocate space for the maximum number of interfaces that could exist. */
    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
	return;
    interfaces = (struct interface *) emalloc2(n, sizeof(struct interface));

    /* 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_SA_LEN
	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
#endif /* HAVE_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
	zero_bytes(&ifr_tmp, 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;
	interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr;

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

	/* Get the netmask. */
	zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
#ifdef SIOCGIFNETMASK
#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;

	    interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr;
	} else {
#else
	{
#endif /* SIOCGIFNETMASK */
	    if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr))
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET);
	    else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr))
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET);
	    else
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET);
	}

	/* Only now can we be sure it was a good/interesting interface. */
	interfaces[num_interfaces].family = AF_INET;
	num_interfaces++;
    }

    /* If the expected size < real size, realloc the array. */
    if (n != num_interfaces) {
	if (num_interfaces != 0)
	    interfaces = (struct interface *) erealloc3(interfaces,
		num_interfaces, sizeof(struct interface));
	else
	    efree(interfaces);
    }
    efree(ifconf_buf);
    (void) close(sock);
}

#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */

/*
 * Stub function for those without SIOCGIFCONF
 */
void
load_interfaces()
{
    return;
}

#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

void
dump_interfaces()
{
    int i;
#ifdef HAVE_IN6_ADDR
    char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
#endif

    puts("Local IP address and netmask pairs:");
    for (i = 0; i < num_interfaces; i++) {
	switch(interfaces[i].family) {
	    case AF_INET:
		printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
		puts(inet_ntoa(interfaces[i].netmask.ip4));
		break;
#ifdef HAVE_IN6_ADDR
	    case AF_INET6:
		inet_ntop(AF_INET6, &interfaces[i].addr.ip6,
		    addrbuf, sizeof(addrbuf));
		inet_ntop(AF_INET6, &interfaces[i].netmask.ip6,
		    maskbuf, sizeof(maskbuf));
		printf("\t%s / %s\n", addrbuf, maskbuf);
		break;
#endif /* HAVE_IN6_ADDR */
	}
    }
}
示例#3
0
文件: parse_args.c 项目: CVi/sudo
/*
 * 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;
}