Example #1
0
/*
 * Take a uid in string form "#123" and return a faked up passwd struct.
 */
struct passwd *
sudo_fakepwnam(const char *user, gid_t gid)
{
    struct cache_item *item;
    struct passwd *pw;
    struct rbnode *node;
    size_t len, namelen;
    int i;

    namelen = strlen(user);
    len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
	sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
	sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);

    for (i = 0; i < 2; i++) {
	item = emalloc(len);
	zero_bytes(item, sizeof(*item) + sizeof(*pw));
	pw = (struct passwd *) ((char *)item + sizeof(*item));
	pw->pw_uid = (uid_t) atoi(user + 1);
	pw->pw_gid = gid;
	pw->pw_name = (char *)pw + sizeof(struct passwd);
	memcpy(pw->pw_name, user, namelen + 1);
	pw->pw_passwd = pw->pw_name + namelen + 1;
	memcpy(pw->pw_passwd, "*", 2);
	pw->pw_gecos = pw->pw_passwd + 2;
	pw->pw_gecos[0] = '\0';
	pw->pw_dir = pw->pw_gecos + 1;
	memcpy(pw->pw_dir, "/", 2);
	pw->pw_shell = pw->pw_dir + 2;
	memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));

	item->refcnt = 1;
	item->d.pw = pw;
	if (i == 0) {
	    /* Store by uid, overwriting cached version. */
	    item->k.uid = pw->pw_uid;
	    if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
		pw_delref_item(node->data);
		node->data = item;
	    }
	} else {
	    /* Store by name, overwriting cached version. */
	    item->k.name = pw->pw_name;
	    if ((node = rbinsert(pwcache_byname, item)) != NULL) {
		pw_delref_item(node->data);
		node->data = item;
	    }
	}
    }
    item->refcnt++;
    return pw;
}
Example #2
0
struct passwd *
getpwent(void)
{
    static struct passwd pw;
    static char pwbuf[LINE_MAX];
    size_t len;
    char *cp, *colon;

    if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
	return NULL;

    zero_bytes(&pw, sizeof(pw));
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_name = cp;
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_passwd = cp;
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_uid = atoi(cp);
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_gid = atoi(cp);
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_gecos = cp;
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    pw.pw_dir = cp;
    pw.pw_shell = colon;
    len = strlen(colon);
    if (len > 0 && colon[len - 1] == '\n')
	colon[len - 1] = '\0';
    return &pw;
}
Example #3
0
/*
 * Take a gid in string form "#123" and return a faked up group struct.
 */
struct group *
sudo_fakegrnam(const char *group)
{
    struct cache_item *item;
    struct group *gr;
    struct rbnode *node;
    size_t len, namelen;
    int i;

    namelen = strlen(group);
    len = sizeof(*item) + sizeof(*gr) + namelen + 1;

    for (i = 0; i < 2; i++) {
	item = emalloc(len);
	zero_bytes(item, sizeof(*item) + sizeof(*gr));
	gr = (struct group *) ((char *)item + sizeof(*item));
	gr->gr_gid = (gid_t) atoi(group + 1);
	gr->gr_name = (char *)gr + sizeof(struct group);
	memcpy(gr->gr_name, group, namelen + 1);

	item->refcnt = 1;
	item->d.gr = gr;
	if (i == 0) {
	    /* Store by gid, overwriting cached version. */
	    item->k.gid = gr->gr_gid;
	    if ((node = rbinsert(grcache_bygid, item)) != NULL) {
		gr_delref_item(node->data);
		node->data = item;
	    }
	} else {
	    /* Store by name, overwriting cached version. */
	    item->k.name = gr->gr_name;
	    if ((node = rbinsert(grcache_byname, item)) != NULL) {
		gr_delref_item(node->data);
		node->data = item;
	    }
	}
    }
    item->refcnt++;
    return gr;
}
Example #4
0
struct group *
getgrent(void)
{
    static struct group gr;
    static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
    size_t len;
    char *cp, *colon;
    int n;

    if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
	return NULL;

    zero_bytes(&gr, sizeof(gr));
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    gr.gr_name = cp;
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    gr.gr_passwd = cp;
    if ((colon = strchr(cp = colon, ':')) == NULL)
	return NULL;
    *colon++ = '\0';
    gr.gr_gid = atoi(cp);
    len = strlen(colon);
    if (len > 0 && colon[len - 1] == '\n')
	colon[len - 1] = '\0';
    if (*colon != '\0') {
	gr.gr_mem = gr_mem;
	cp = strtok(colon, ",");
	for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
	    gr.gr_mem[n] = cp;
	    cp = strtok(NULL, ",");
	}
	gr.gr_mem[n++] = NULL;
    } else
	gr.gr_mem = NULL;
    return &gr;
}
Example #5
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;
}
Example #6
0
File: logging.c Project: CVi/sudo
/*
 * Send a message to MAILTO user
 */
static void
send_mail(const char *fmt, ...)
{
    FILE *mail;
    char *p;
    int fd, pfd[2], status;
    pid_t pid, rv;
    sigaction_t sa;
    va_list ap;
#ifndef NO_ROOT_MAILER
    static char *root_envp[] = {
	"HOME=/",
	"PATH=/usr/bin:/bin:/usr/sbin:/sbin",
	"LOGNAME=root",
	"USERNAME=root",
	"USER=root",
	NULL
    };
#endif /* NO_ROOT_MAILER */

    /* Just return if mailer is disabled. */
    if (!def_mailerpath || !def_mailto)
	return;

    /* Fork and return, child will daemonize. */
    switch (pid = fork()) {
	case -1:
	    /* Error. */
	    error(1, _("unable to fork"));
	    break;
	case 0:
	    /* Child. */
	    switch (pid = fork()) {
		case -1:
		    /* Error. */
		    mysyslog(LOG_ERR, _("unable to fork: %m"));
		    _exit(1);
		case 0:
		    /* Grandchild continues below. */
		    break;
		default:
		    /* Parent will wait for us. */
		    _exit(0);
	    }
	    break;
	default:
	    /* Parent. */
	    do {
		rv = waitpid(pid, &status, 0);
	    } while (rv == -1 && errno == EINTR);
	    return;
    }

    /* Daemonize - disassociate from session/tty. */
    if (setsid() == -1)
      warning("setsid");
    if (chdir("/") == -1)
      warning("chdir(/)");
    if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
	(void) dup2(fd, STDIN_FILENO);
	(void) dup2(fd, STDOUT_FILENO);
	(void) dup2(fd, STDERR_FILENO);
    }

#ifdef HAVE_SETLOCALE
    if (!setlocale(LC_ALL, def_sudoers_locale)) {
	setlocale(LC_ALL, "C");
	efree(def_sudoers_locale);
	def_sudoers_locale = estrdup("C");
    }
#endif /* HAVE_SETLOCALE */

    /* Close password, group and other fds so we don't leak. */
    sudo_endpwent();
    sudo_endgrent();
    closefrom(STDERR_FILENO + 1);

    /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
    zero_bytes(&sa, sizeof(sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_INTERRUPT;
    sa.sa_handler = SIG_IGN;
    (void) sigaction(SIGPIPE, &sa, NULL);

    if (pipe(pfd) == -1) {
	mysyslog(LOG_ERR, _("unable to open pipe: %m"));
	_exit(1);
    }

    switch (pid = fork()) {
	case -1:
	    /* Error. */
	    mysyslog(LOG_ERR, _("unable to fork: %m"));
	    _exit(1);
	    break;
	case 0:
	    {
		char *argv[MAX_MAILFLAGS + 1];
		char *mpath, *mflags;
		int i;

		/* Child, set stdin to output side of the pipe */
		if (pfd[0] != STDIN_FILENO) {
		    if (dup2(pfd[0], STDIN_FILENO) == -1) {
			mysyslog(LOG_ERR, _("unable to dup stdin: %m"));
			_exit(127);
		    }
		    (void) close(pfd[0]);
		}
		(void) close(pfd[1]);

		/* Build up an argv based on the mailer path and flags */
		mflags = estrdup(def_mailerflags);
		mpath = estrdup(def_mailerpath);
		if ((argv[0] = strrchr(mpath, ' ')))
		    argv[0]++;
		else
		    argv[0] = mpath;

		i = 1;
		if ((p = strtok(mflags, " \t"))) {
		    do {
			argv[i] = p;
		    } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
		}
		argv[i] = NULL;

		/*
		 * Depending on the config, either run the mailer as root
		 * (so user cannot kill it) or as the user (for the paranoid).
		 */
#ifndef NO_ROOT_MAILER
		set_perms(PERM_ROOT|PERM_NOEXIT);
		execve(mpath, argv, root_envp);
#else
		set_perms(PERM_FULL_USER|PERM_NOEXIT);
		execv(mpath, argv);
#endif /* NO_ROOT_MAILER */
		mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath);
		_exit(127);
	    }
	    break;
    }

    (void) close(pfd[0]);
    mail = fdopen(pfd[1], "w");

    /* Pipes are all setup, send message. */
    (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
	def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated");
    for (p = def_mailsub; *p; p++) {
	/* Expand escapes in the subject */
	if (*p == '%' && *(p+1) != '%') {
	    switch (*(++p)) {
		case 'h':
		    (void) fputs(user_host, mail);
		    break;
		case 'u':
		    (void) fputs(user_name, mail);
		    break;
		default:
		    p--;
		    break;
	    }
	} else
	    (void) fputc(*p, mail);
    }

#ifdef HAVE_NL_LANGINFO
    if (strcmp(def_sudoers_locale, "C") != 0)
	(void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET));
#endif /* HAVE_NL_LANGINFO */

    (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host,
	get_timestr(time(NULL), def_log_year), user_name);
    va_start(ap, fmt);
    (void) vfprintf(mail, fmt, ap);
    va_end(ap);
    fputs("\n\n", mail);

    fclose(mail);
    do {
        rv = waitpid(pid, &status, 0);
    } while (rv == -1 && errno == EINTR);
    _exit(0);
}
Example #7
0
File: sudo_auth.c Project: CVi/sudo
int
verify_user(struct passwd *pw, char *prompt)
{
    int counter = def_passwd_tries + 1;
    int success = AUTH_FAILURE;
    int flags, status, standalone, rval;
    char *p;
    sudo_auth *auth;
    sigaction_t sa, osa;

    /* Enable suspend during password entry. */
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = SIG_DFL;
    (void) sigaction(SIGTSTP, &sa, &osa);

    /* Make sure we have at least one auth method. */
    if (auth_switch[0].name == NULL) {
	audit_failure(NewArgv, "no authentication methods");
    	log_error(0,
	    _("There are no authentication methods compiled into sudo!  "
	    "If you want to turn off authentication, use the "
	    "--disable-authentication configure option."));
	return -1;
    }

    /* Make sure we haven't mixed standalone and shared auth methods. */
    standalone = IS_STANDALONE(&auth_switch[0]);
    if (standalone && auth_switch[1].name != NULL) {
	audit_failure(NewArgv, "invalid authentication methods");
    	log_error(0, _("Invalid authentication methods compiled into sudo!  "
	    "You may mix standalone and non-standalone authentication."));
	return -1;
    }

    /* Set FLAG_ONEANDONLY if there is only one auth method. */
    if (auth_switch[1].name == NULL)
	SET(auth_switch[0].flags, FLAG_ONEANDONLY);

    /* Initialize auth methods and unconfigure the method if necessary. */
    for (auth = auth_switch; auth->name; auth++) {
	if (auth->init && !IS_DISABLED(auth)) {
	    if (NEEDS_USER(auth))
		set_perms(PERM_USER);

	    status = (auth->init)(pw, &prompt, auth);
	    if (status == AUTH_FAILURE)
		SET(auth->flags, FLAG_DISABLED);
	    else if (status == AUTH_FATAL) {	/* XXX log */
		audit_failure(NewArgv, "authentication failure");
		return -1;		/* assume error msg already printed */
	    }

	    if (NEEDS_USER(auth))
		restore_perms();
	}
    }

    while (--counter) {
	/* Do any per-method setup and unconfigure the method if needed */
	for (auth = auth_switch; auth->name; auth++) {
	    if (auth->setup && !IS_DISABLED(auth)) {
		if (NEEDS_USER(auth))
		    set_perms(PERM_USER);

		status = (auth->setup)(pw, &prompt, auth);
		if (status == AUTH_FAILURE)
		    SET(auth->flags, FLAG_DISABLED);
		else if (status == AUTH_FATAL) {/* XXX log */
		    audit_failure(NewArgv, "authentication failure");
		    return -1;		/* assume error msg already printed */
		}

		if (NEEDS_USER(auth))
		    restore_perms();
	    }
	}

	/* Get the password unless the auth function will do it for us */
	if (standalone) {
	    p = prompt;
	} else {
	    p = auth_getpass(prompt, def_passwd_timeout * 60,
		SUDO_CONV_PROMPT_ECHO_OFF);
	    if (p == NULL)
		break;
	}

	/* Call authentication functions. */
	for (auth = auth_switch; auth->name; auth++) {
	    if (IS_DISABLED(auth))
		continue;

	    if (NEEDS_USER(auth))
		set_perms(PERM_USER);

	    success = auth->status = (auth->verify)(pw, p, auth);

	    if (NEEDS_USER(auth))
		restore_perms();

	    if (auth->status != AUTH_FAILURE)
		goto cleanup;
	}
	if (!standalone)
	    zero_bytes(p, strlen(p));
	pass_warn();
    }

cleanup:
    /* Call cleanup routines. */
    for (auth = auth_switch; auth->name; auth++) {
	if (auth->cleanup && !IS_DISABLED(auth)) {
	    if (NEEDS_USER(auth))
		set_perms(PERM_USER);

	    status = (auth->cleanup)(pw, auth);
	    if (status == AUTH_FATAL) {	/* XXX log */
		audit_failure(NewArgv, "authentication failure");
		return -1;		/* assume error msg already printed */
	    }

	    if (NEEDS_USER(auth))
		restore_perms();
	}
    }

    switch (success) {
	case AUTH_SUCCESS:
	    (void) sigaction(SIGTSTP, &osa, NULL);
	    rval = TRUE;
	    break;
	case AUTH_INTR:
	case AUTH_FAILURE:
	    if (counter != def_passwd_tries) {
		if (def_mail_badpass || def_mail_always)
		    flags = 0;
		else
		    flags = NO_MAIL;
		log_error(flags, ngettext("%d incorrect password attempt",
		    "%d incorrect password attempts",
		    def_passwd_tries - counter), def_passwd_tries - counter);
	    }
	    audit_failure(NewArgv, "authentication failure");
	    rval = FALSE;
	    break;
	case AUTH_FATAL:
	default:
	    audit_failure(NewArgv, "authentication failure");
	    rval = -1;
	    break;
    }

    return rval;
}
Example #8
0
File: pam.c Project: CVi/sudo
/*
 * ``Conversation function'' for PAM.
 * XXX - does not handle PAM_BINARY_PROMPT
 */
static int
converse(int num_msg, PAM_CONST struct pam_message **msg,
    struct pam_response **response, void *appdata_ptr)
{
    struct pam_response *pr;
    PAM_CONST struct pam_message *pm;
    const char *prompt;
    char *pass;
    int n, type, std_prompt;

    if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
	return PAM_SYSTEM_ERR;
    zero_bytes(*response, num_msg * sizeof(struct pam_response));

    for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
	type = SUDO_CONV_PROMPT_ECHO_OFF;
	switch (pm->msg_style) {
	    case PAM_PROMPT_ECHO_ON:
		type = SUDO_CONV_PROMPT_ECHO_ON;
	    case PAM_PROMPT_ECHO_OFF:
		prompt = def_prompt;

		/* Error out if the last password read was interrupted. */
		if (gotintr)
		    goto err;

		/* Is the sudo prompt standard? (If so, we'l just use PAM's) */
		std_prompt =  strncmp(def_prompt, "Password:"******"Password: "******"Password:"******"Password:"******"";
#else
		    goto err;
#endif
		}
		pr->resp = estrdup(pass);
		zero_bytes(pass, strlen(pass));
		break;
	    case PAM_TEXT_INFO:
		if (pm->msg)
		    (void) puts(pm->msg);
		break;
	    case PAM_ERROR_MSG:
		if (pm->msg) {
		    (void) fputs(pm->msg, stderr);
		    (void) fputc('\n', stderr);
		}
		break;
	    default:
		goto err;
	}
    }

    return PAM_SUCCESS;

err:
    /* Zero and free allocated memory and return an error. */
    for (pr = *response, n = num_msg; n--; pr++) {
	if (pr->resp != NULL) {
	    zero_bytes(pr->resp, strlen(pr->resp));
	    free(pr->resp);
	    pr->resp = NULL;
	}
    }
    zero_bytes(*response, num_msg * sizeof(struct pam_response));
    free(*response);
    *response = NULL;
    return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR;
}
Example #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;
}
Example #10
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 */
	}
    }
}
Example #11
0
File: pam.c Project: mer-tools/sudo
/*
 * ``Conversation function'' for PAM.
 * XXX - does not handle PAM_BINARY_PROMPT
 */
static int
converse(int num_msg, PAM_CONST struct pam_message **msg,
    struct pam_response **response, void *appdata_ptr)
{
    struct pam_response *pr;
    PAM_CONST struct pam_message *pm;
    const char *prompt;
    char *pass;
    int n, type, std_prompt;
    int ret = PAM_AUTH_ERR;
    debug_decl(converse, SUDO_DEBUG_AUTH)

    if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
	debug_return_int(PAM_SYSTEM_ERR);
    zero_bytes(*response, num_msg * sizeof(struct pam_response));

    for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
	type = SUDO_CONV_PROMPT_ECHO_OFF;
	switch (pm->msg_style) {
	    case PAM_PROMPT_ECHO_ON:
		type = SUDO_CONV_PROMPT_ECHO_ON;
		/* FALLTHROUGH */
	    case PAM_PROMPT_ECHO_OFF:
		prompt = def_prompt;

		/* Error out if the last password read was interrupted. */
		if (getpass_error)
		    goto done;

		/* Is the sudo prompt standard? (If so, we'l just use PAM's) */
		std_prompt =  strncmp(def_prompt, "Password:"******"Password: "******"Password:"******"Password:"******"";
#else
		    goto done;
#endif
		}
		pr->resp = estrdup(pass);
		zero_bytes(pass, strlen(pass));
		break;
	    case PAM_TEXT_INFO:
		if (pm->msg)
		    (void) puts(pm->msg);
		break;
	    case PAM_ERROR_MSG:
		if (pm->msg) {
		    (void) fputs(pm->msg, stderr);
		    (void) fputc('\n', stderr);
		}
		break;
	    default:
		ret = PAM_CONV_ERR;
		goto done;
	}
    }
    ret = PAM_SUCCESS;

done:
    if (ret != PAM_SUCCESS) {
	/* Zero and free allocated memory and return an error. */
	for (pr = *response, n = num_msg; n--; pr++) {
	    if (pr->resp != NULL) {
		zero_bytes(pr->resp, strlen(pr->resp));
		free(pr->resp);
		pr->resp = NULL;
	    }
	}
	zero_bytes(*response, num_msg * sizeof(struct pam_response));
	free(*response);
	*response = NULL;
    }
    debug_return_int(ret);
}
Example #12
0
int
main(int argc, char *argv[])
{
    int ch, idx, plen, nready, interactive = 0, listonly = 0;
    const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = ".";
    char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
    double seconds, to_wait, speed = 1.0, max_wait = 0;
    FILE *lfile;
    fd_set *fdsw;
    sigaction_t sa;
    size_t len, nbytes, nread, off;
    ssize_t nwritten;

#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
    setprogname(argc > 0 ? argv[0] : "sudoreplay");
#endif

#ifdef HAVE_SETLOCALE
    setlocale(LC_ALL, "");
    decimal = localeconv()->decimal_point;
#endif

    while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) {
	switch(ch) {
	case 'd':
	    session_dir = optarg;
	    break;
	case 'f':
	    /* Set the replay filter. */
	    replay_filter = 0;
	    for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) {
		if (strcmp(cp, "stdout") == 0)
		    SET(replay_filter, 1 << IOFD_STDOUT);
		else if (strcmp(cp, "stderr") == 0)
		    SET(replay_filter, 1 << IOFD_STDERR);
		else if (strcmp(cp, "ttyout") == 0)
		    SET(replay_filter, 1 << IOFD_TTYOUT);
		else
		    errorx(1, "invalid filter option: %s", optarg);
	    }
	    break;
	case 'h':
	    help();
	    /* NOTREACHED */
	case 'l':
	    listonly = 1;
	    break;
	case 'm':
	    errno = 0;
	    max_wait = strtod(optarg, &ep);
	    if (*ep != '\0' || errno != 0)
		errorx(1, "invalid max wait: %s", optarg);
	    break;
	case 's':
	    errno = 0;
	    speed = strtod(optarg, &ep);
	    if (*ep != '\0' || errno != 0)
		errorx(1, "invalid speed factor: %s", optarg);
	    break;
	case 'V':
	    (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
	    exit(0);
	default:
	    usage(1);
	    /* NOTREACHED */
	}

    }
    argc -= optind;
    argv += optind;

    if (listonly)
	exit(list_sessions(argc, argv, pattern, user, tty));

    if (argc != 1)
	usage(1);

    /* 6 digit ID in base 36, e.g. 01G712AB */
    id = argv[0];
    if (!VALID_ID(id))
	errorx(1, "invalid ID %s", id);

    plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
	session_dir, id, &id[2], &id[4]);
    if (plen <= 0 || plen >= sizeof(path))
	errorx(1, "%s/%.2s/%.2s/%.2s/%.2s/timing: %s", session_dir,
	    id, &id[2], &id[4], strerror(ENAMETOOLONG));
    plen -= 7;

    /* Open files for replay, applying replay filter for the -f flag. */
    for (idx = 0; idx < IOFD_MAX; idx++) {
	if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) {
	    io_fds[idx].v = open_io_fd(path, plen, io_fnames[idx]);
	    if (io_fds[idx].v == NULL)
		error(1, "unable to open %s", path);
	}
    }

    /* Read log file. */
    path[plen] = '\0';
    strlcat(path, "/log", sizeof(path));
    lfile = fopen(path, "r");
    if (lfile == NULL)
	error(1, "unable to open %s", path);
    cp = NULL;
    len = 0;
    /* Pull out command (third line). */
    if (getline(&cp, &len, lfile) == -1 ||
	getline(&cp, &len, lfile) == -1 ||
	getline(&cp, &len, lfile) == -1) {
	errorx(1, "invalid log file %s", path);
    }
    printf("Replaying sudo session: %s", cp);
    free(cp);
    fclose(lfile);

    fflush(stdout);
    zero_bytes(&sa, sizeof(sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESETHAND;
    sa.sa_handler = cleanup;
    (void) sigaction(SIGINT, &sa, NULL);
    (void) sigaction(SIGKILL, &sa, NULL);
    (void) sigaction(SIGTERM, &sa, NULL);
    (void) sigaction(SIGHUP, &sa, NULL);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = SIG_IGN;
    (void) sigaction(SIGTSTP, &sa, NULL);
    (void) sigaction(SIGQUIT, &sa, NULL);

    /* XXX - read user input from /dev/tty and set STDOUT to raw if not a pipe */
    /* Set stdin to raw mode if it is a tty */
    interactive = isatty(STDIN_FILENO);
    if (interactive) {
	ch = fcntl(STDIN_FILENO, F_GETFL, 0);
	if (ch != -1)
	    (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK);
	if (!term_raw(STDIN_FILENO, 1))
	    error(1, "cannot set tty to raw mode");
    }
    fdsw = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS),
	sizeof(fd_mask));

    /*
     * Timing file consists of line of the format: "%f %d\n"
     */
#ifdef HAVE_ZLIB_H
    while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) {
#else
    while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
#endif
	if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
	    errorx(1, "invalid timing file line: %s", buf);

	if (interactive)
	    check_input(STDIN_FILENO, &speed);

	/* Adjust delay using speed factor and clamp to max_wait */
	to_wait = seconds / speed;
	if (max_wait && to_wait > max_wait)
	    to_wait = max_wait;
	delay(to_wait);

	/* Even if we are not relaying, we still have to delay. */
	if (io_fds[idx].v == NULL)
	    continue;

	/* All output is sent to stdout. */
	while (nbytes != 0) {
	    if (nbytes > sizeof(buf))
		len = sizeof(buf);
	    else
		len = nbytes;
#ifdef HAVE_ZLIB_H
	    nread = gzread(io_fds[idx].g, buf, len);
#else
	    nread = fread(buf, 1, len, io_fds[idx].f);
#endif
	    nbytes -= nread;
	    off = 0;
	    do {
		/* no stdio, must be unbuffered */
		nwritten = write(STDOUT_FILENO, buf + off, nread - off);
		if (nwritten == -1) {
		    if (errno == EINTR)
			continue;
		    if (errno == EAGAIN) {
			FD_SET(STDOUT_FILENO, fdsw);
			do {
			    nready = select(STDOUT_FILENO + 1, NULL, fdsw, NULL, NULL);
			} while (nready == -1 && errno == EINTR);
			if (nready == 1)
			    continue;
		    }
		    error(1, "writing to standard output");
		}
		off += nwritten;
	    } while (nread > off);
	}
    }
    term_restore(STDIN_FILENO, 1);
    exit(0);
}

static void
delay(double secs)
{
    struct timespec ts, rts;
    int rval;

    /*
     * Typical max resolution is 1/HZ but we can't portably check that.
     * If the interval is small enough, just ignore it.
     */
    if (secs < 0.0001)
	return;

    rts.tv_sec = secs;
    rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0;
    do {
      memcpy(&ts, &rts, sizeof(ts));
      rval = nanosleep(&ts, &rts);
    } while (rval == -1 && errno == EINTR);
    if (rval == -1)
	error(1, "nanosleep: tv_sec %ld, tv_nsec %ld", ts.tv_sec, ts.tv_nsec);
}

static void *
open_io_fd(char *path, int len, const char *suffix)
{
    path[len] = '\0';
    strlcat(path, suffix, PATH_MAX);

#ifdef HAVE_ZLIB_H
    return gzopen(path, "r");
#else
    return fopen(path, "r");
#endif
}
Example #13
0
void *alloc_zero(unsigned long size)
{
  void *ptr = allocfunc(size);
  if (ptr) zero_bytes(ptr, size);
  return ptr;
}