Пример #1
0
int
sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth)
{
    struct ktc_encryptionKey afs_key;
    struct ktc_token afs_token;
    debug_decl(sudo_afs_verify, SUDO_DEBUG_AUTH)

    /* Try to just check the password */
    ka_StringToKey(pass, NULL, &afs_key);
    if (ka_GetAdminToken(pw->pw_name,		/* name */
			 NULL,			/* instance */
			 NULL,			/* realm */
			 &afs_key,		/* key (contains password) */
			 0,			/* lifetime */
			 &afs_token,		/* token */
			 0) == 0)		/* new */
	debug_return_int(AUTH_SUCCESS);

    /* Fall back on old method XXX - needed? */
    setpag();
    if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
				   pw->pw_name,	/* name */
				   NULL,	/* instance */
				   NULL,	/* realm */
				   pass,	/* password */
				   0,		/* lifetime */
				   NULL,	/* expiration ptr (unused) */
				   0,		/* spare */
				   NULL) == 0)	/* reason */
	debug_return_int(AUTH_SUCCESS);

    debug_return_int(AUTH_FAILURE);
}
int
sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{
    const char *s;
    int *pam_status = (int *) auth->data;
    debug_decl(sudo_pam_verify, SUDO_DEBUG_AUTH)

    def_prompt = prompt;	/* for converse */

    /* PAM_SILENT prevents the authentication service from generating output. */
    *pam_status = pam_authenticate(pamh, PAM_SILENT);
    switch (*pam_status) {
	case PAM_SUCCESS:
	    *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
	    switch (*pam_status) {
		case PAM_SUCCESS:
		    debug_return_int(AUTH_SUCCESS);
		case PAM_AUTH_ERR:
		    log_warning(NO_MAIL, N_("account validation failure, "
			"is your account locked?"));
		    debug_return_int(AUTH_FATAL);
		case PAM_NEW_AUTHTOK_REQD:
		    log_warning(NO_MAIL, N_("Account or password is "
			"expired, reset your password and try again"));
		    *pam_status = pam_chauthtok(pamh,
			PAM_CHANGE_EXPIRED_AUTHTOK);
		    if (*pam_status == PAM_SUCCESS)
			debug_return_int(AUTH_SUCCESS);
		    if ((s = pam_strerror(pamh, *pam_status)) != NULL) {
			log_warning(NO_MAIL,
			    N_("unable to change expired password: %s"), s);
		    }
		    debug_return_int(AUTH_FAILURE);
		case PAM_AUTHTOK_EXPIRED:
		    log_warning(NO_MAIL,
			N_("Password expired, contact your system administrator"));
		    debug_return_int(AUTH_FATAL);
		case PAM_ACCT_EXPIRED:
		    log_warning(NO_MAIL,
			N_("Account expired or PAM config lacks an \"account\" "
			"section for sudo, contact your system administrator"));
		    debug_return_int(AUTH_FATAL);
	    }
	    /* FALLTHROUGH */
	case PAM_AUTH_ERR:
	case PAM_AUTHINFO_UNAVAIL:
	    if (getpass_error) {
		/* error or ^C from tgetpass() */
		debug_return_int(AUTH_INTR);
	    }
	    /* FALLTHROUGH */
	case PAM_MAXTRIES:
	case PAM_PERM_DENIED:
	    debug_return_int(AUTH_FAILURE);
	default:
	    if ((s = pam_strerror(pamh, *pam_status)) != NULL)
		log_warning(NO_MAIL, N_("PAM authentication error: %s"), s);
	    debug_return_int(AUTH_FATAL);
    }
}
Пример #3
0
Файл: dce.c Проект: millert/sudo
/* Returns 0 for DCE "ok" status, 1 otherwise */
static int
check_dce_status(error_status_t input_status, char *comment)
{
    int error_stat;
    unsigned char error_string[dce_c_error_string_len];
    debug_decl(check_dce_status, SUDOERS_DEBUG_AUTH)

    if (input_status == rpc_s_ok)
	debug_return_int(0);
    dce_error_inq_text(input_status, error_string, &error_stat);
    sudo_printf(SUDO_CONV_ERROR_MSG, "%s %s\n", comment, error_string);
    debug_return_int(1);
}
static int
get_ttysize_ioctl(int *rowp, int *colp)
{
    struct winsize wsize;
    debug_decl(get_ttysize_ioctl, SUDO_DEBUG_EXEC)

    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &wsize) == 0 &&
	wsize.ws_row != 0 && wsize.ws_col  != 0) {
	*rowp = wsize.ws_row;
	*colp = wsize.ws_col;
	debug_return_int(0);
    }
    debug_return_int(-1);
}
Пример #5
0
int
sudo_pam_cleanup(struct passwd *pw, sudo_auth *auth)
{
    int *pam_status = (int *) auth->data;
    debug_decl(sudo_pam_cleanup, SUDO_DEBUG_AUTH)

    /* If successful, we can't close the session until pam_end_session() */
    if (*pam_status == AUTH_SUCCESS)
	debug_return_int(AUTH_SUCCESS);

    *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
    pamh = NULL;
    debug_return_int(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
Пример #6
0
/*
 * securid_init - Initialises communications with ACE server
 * Arguments in:
 *     pw - UNUSED
 *     auth - sudo authentication structure
 *
 * Results out:
 *     auth - auth->data contains pointer to new SecurID handle
 *     return code - Fatal if initialization unsuccessful, otherwise
 *                   success.
 */
int
sudo_securid_init(struct passwd *pw, sudo_auth *auth)
{
    static SDI_HANDLE sd_dat;			/* SecurID handle */
    debug_decl(sudo_securid_init, SUDOERS_DEBUG_AUTH)

    auth->data = (void *) &sd_dat;		/* For method-specific data */

    /* Start communications */
    if (AceInitialize() != SD_FALSE)
	debug_return_int(AUTH_SUCCESS);

    sudo_warnx(U_("failed to initialise the ACE API library"));
    debug_return_int(AUTH_FATAL);
}
Пример #7
0
static int
audit_role_change(const security_context_t old_context,
    const security_context_t new_context, const char *ttyn, int result)
{
    int au_fd, rc = -1;
    char *message;
    debug_decl(audit_role_change, SUDO_DEBUG_SELINUX)

    au_fd = audit_open();
    if (au_fd == -1) {
        /* Kernel may not have audit support. */
        if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT
)
            sudo_fatal(U_("unable to open audit system"));
    } else {
	/* audit role change using the same format as newrole(1) */
	rc = asprintf(&message, "newrole: old-context=%s new-context=%s",
	    old_context, new_context);
	if (rc == -1)
	    sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
	rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE,
	    message, NULL, NULL, ttyn, result);
	if (rc <= 0)
	    sudo_warn(U_("unable to send audit message"));
	free(message);
	close(au_fd);
    }

    debug_return_int(rc);
}
Пример #8
0
/*
 * Verify that path is the right type and not writable by other users.
 */
static int
sudo_secure_path(const char *path, unsigned int type, uid_t uid, gid_t gid, struct stat *sbp)
{
    struct stat sb;
    int ret = SUDO_PATH_MISSING;
    debug_decl(sudo_secure_path, SUDO_DEBUG_UTIL)

    if (path != NULL && stat(path, &sb) == 0) {
	if ((sb.st_mode & _S_IFMT) != type) {
	    ret = SUDO_PATH_BAD_TYPE;
	} else if (uid != (uid_t)-1 && sb.st_uid != uid) {
	    ret = SUDO_PATH_WRONG_OWNER;
	} else if (sb.st_mode & S_IWOTH) {
	    ret = SUDO_PATH_WORLD_WRITABLE;
	} else if (ISSET(sb.st_mode, S_IWGRP) &&
	    (gid == (gid_t)-1 || sb.st_gid != gid)) {
	    ret = SUDO_PATH_GROUP_WRITABLE;
	} else {
	    ret = SUDO_PATH_SECURE;
	}
	if (sbp)
	    (void) memcpy(sbp, &sb, sizeof(struct stat));
    }

    debug_return_int(ret);
}
Пример #9
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;
    debug_decl(selinux_restore_tty, SUDO_DEBUG_SELINUX)

    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) {
	sudo_warn(U_("unable to fgetfilecon %s"), se_state.ttyn);
	goto skip_relabel;
    }

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

    if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0)
	sudo_warn(U_("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;
    }
    debug_return_int(retval);
}
static int
output(const char *buf)
{
    struct sudo_conv_message msg;
    struct sudo_conv_reply repl;
    debug_decl(output, SUDO_DEBUG_NSS)

    /* Call conversation function */
    memset(&msg, 0, sizeof(msg));
    msg.msg_type = SUDO_CONV_INFO_MSG;
    msg.msg = buf;
    memset(&repl, 0, sizeof(repl));
    if (sudo_conv(1, &msg, &repl) == -1)
	debug_return_int(0);
    debug_return_int(strlen(buf));
}
Пример #11
0
/*
 * Parse a comma-separated list of gids into an allocated array of GETGROUPS_T.
 * If a pointer to the base gid is specified, it is stored as the first element
 * in the array.
 * Returns the number of gids in the allocated array.
 */
int
sudo_parse_gids_v1(const char *gidstr, const gid_t *basegid, GETGROUPS_T **gidsp)
{
    int ngids = 0;
    GETGROUPS_T *gids;
    const char *cp = gidstr;
    const char *errstr;
    char *ep;
    debug_decl(sudo_parse_gids, SUDO_DEBUG_UTIL)

    /* Count groups. */
    if (*cp != '\0') {
	ngids++;
	do {
	    if (*cp++ == ',')
		ngids++;
	} while (*cp != '\0');
    }
    /* Base gid is optional. */
    if (basegid != NULL)
	ngids++;
    /* Allocate and fill in array. */
    if (ngids != 0) {
	gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T));
	if (gids == NULL) {
	    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
	    debug_return_int(-1);
	}
	ngids = 0;
	if (basegid != NULL)
	    gids[ngids++] = *basegid;
	cp = gidstr;
	do {
	    gids[ngids] = (GETGROUPS_T) sudo_strtoid(cp, ",", &ep, &errstr);
	    if (errstr != NULL) {
		sudo_warnx(U_("%s: %s"), cp, U_(errstr));
		free(gids);
		debug_return_int(-1);
	    }
	    if (basegid == NULL || gids[ngids] != *basegid)
		ngids++;
	    cp = ep + 1;
	} while (*ep != '\0');
	*gidsp = gids;
    }
    debug_return_int(ngids);
}
int
sudo_pam_init(struct passwd *pw, sudo_auth *auth)
{
    static struct pam_conv pam_conv;
    static int pam_status;
    debug_decl(sudo_pam_init, SUDO_DEBUG_AUTH)

    /* Initial PAM setup */
    auth->data = (void *) &pam_status;
    pam_conv.conv = converse;
    pam_status = pam_start(ISSET(sudo_mode, MODE_LOGIN_SHELL) ?
	def_pam_login_service : def_pam_service, pw->pw_name, &pam_conv, &pamh);
    if (pam_status != PAM_SUCCESS) {
	log_warning(USE_ERRNO|NO_MAIL, N_("unable to initialize PAM"));
	debug_return_int(AUTH_FATAL);
    }

    /*
     * Set PAM_RUSER to the invoking user (the "from" user).
     * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
     */
    (void) pam_set_item(pamh, PAM_RUSER, user_name);
#ifdef __sun__
    (void) pam_set_item(pamh, PAM_RHOST, user_host);
#endif

    /*
     * Some versions of pam_lastlog have a bug that
     * will cause a crash if PAM_TTY is not set so if
     * there is no tty, set PAM_TTY to the empty string.
     */
    if (user_ttypath == NULL)
	(void) pam_set_item(pamh, PAM_TTY, "");
    else
	(void) pam_set_item(pamh, PAM_TTY, user_ttypath);

    /*
     * If PAM session and setcred support is disabled we don't
     * need to keep a sudo process around to close the session.
     */
    if (!def_pam_session && !def_pam_setcred)
	auth->end_session = NULL;

    debug_return_int(AUTH_SUCCESS);
}
Пример #13
0
int
sudo_pam_init(struct passwd *pw, sudo_auth *auth)
{
    static struct pam_conv pam_conv;
    static int pam_status;
    debug_decl(sudo_pam_init, SUDO_DEBUG_AUTH)

    /* Initial PAM setup */
    if (auth != NULL)
	auth->data = (void *) &pam_status;
    pam_conv.conv = converse;
#ifdef HAVE_PAM_LOGIN
    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
	pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh);
    else
#endif
	pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
    if (pam_status != PAM_SUCCESS) {
	log_error(USE_ERRNO|NO_MAIL, _("unable to initialize PAM"));
	debug_return_int(AUTH_FATAL);
    }

    /*
     * Set PAM_RUSER to the invoking user (the "from" user).
     * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
     */
    (void) pam_set_item(pamh, PAM_RUSER, user_name);
#ifdef __sun__
    (void) pam_set_item(pamh, PAM_RHOST, user_host);
#endif

    /*
     * Some versions of pam_lastlog have a bug that
     * will cause a crash if PAM_TTY is not set so if
     * there is no tty, set PAM_TTY to the empty string.
     */
    if (user_ttypath == NULL)
	(void) pam_set_item(pamh, PAM_TTY, "");
    else
	(void) pam_set_item(pamh, PAM_TTY, user_ttypath);

    debug_return_int(AUTH_SUCCESS);
}
int
sudo_aix_cleanup(struct passwd *pw, sudo_auth *auth)
{
    debug_decl(sudo_aix_cleanup, SUDO_DEBUG_AUTH)

    /* Unset AUTHSTATE as it may not be correct for the runas user. */
    sudo_unsetenv("AUTHSTATE");

    debug_return_int(AUTH_SUCCESS);
}
Пример #15
0
int
linux_audit_command(char *argv[], int result)
{
    int au_fd, rc = -1;
    char *command, *cp, **av;
    size_t size, n;
    debug_decl(linux_audit_command, SUDOERS_DEBUG_AUDIT)

    /* Don't return an error if auditing is not configured. */
    if ((au_fd = linux_audit_open()) < 0)
	debug_return_int(au_fd == AUDIT_NOT_CONFIGURED ? 0 : -1);

    /* Convert argv to a flat string. */
    for (size = 0, av = argv; *av != NULL; av++)
	size += strlen(*av) + 1;
    command = cp = sudo_emalloc(size);
    for (av = argv; *av != NULL; av++) {
	n = strlcpy(cp, *av, size - (cp - command));
	if (n >= size - (cp - command)) {
	    sudo_warnx(U_("internal error, %s overflow"), __func__);
	    goto done;
	}
	cp += n;
	*cp++ = ' ';
    }
    *--cp = '\0';

    /* Log command, ignoring ECONNREFUSED on error. */
    if (audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result) <= 0) {
	if (errno != ECONNREFUSED) {
	    sudo_warn(U_("unable to send audit message"));
	    goto done;
	}
    }

    rc = 0;

done:
    sudo_efree(command);

    debug_return_int(rc);
}
Пример #16
0
/*
 * Open audit connection if possible.
 * Returns audit fd on success and -1 on failure.
 */
static int
linux_audit_open(void)
{
    static int au_fd = -1;
    debug_decl(linux_audit_open, SUDOERS_DEBUG_AUDIT)

    if (au_fd != -1)
	debug_return_int(au_fd);
    au_fd = audit_open();
    if (au_fd == -1) {
	/* Kernel may not have audit support. */
	if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
	    au_fd = AUDIT_NOT_CONFIGURED;
	else
	    sudo_warn(U_("unable to open audit system"));
    } else {
	(void)fcntl(au_fd, F_SETFD, FD_CLOEXEC);
    }
    debug_return_int(au_fd);
}
Пример #17
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 ret = -1;
    debug_decl(selinux_setup, SUDO_DEBUG_SELINUX)

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

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

#ifdef DEBUG
    sudo_warnx("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) {
#ifdef HAVE_LINUX_AUDIT
	audit_role_change(se_state.old_context, "?",
	  se_state.ttyn, 0);
#endif
	goto done;
    }
    
    if (relabel_tty(ttyn, ptyfd) < 0) {
	sudo_warn(U_("unable to set tty context to %s"), se_state.new_context);
	goto done;
    }

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

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

    ret = 0;

done:
    debug_return_int(ret);
}
int
sudo_ev_base_alloc_impl(struct sudo_event_base *base)
{
    debug_decl(sudo_ev_base_alloc_impl, SUDO_DEBUG_EVENT)

    base->maxfd = NFDBITS - 1;
    base->readfds_in = ecalloc(1, sizeof(fd_mask));
    base->writefds_in = ecalloc(1, sizeof(fd_mask));
    base->readfds_out = ecalloc(1, sizeof(fd_mask));
    base->writefds_out = ecalloc(1, sizeof(fd_mask));

    debug_return_int(0);
}
/*
 * Add an fd to preserve.
 */
int
add_preserved_fd(struct preserved_fd_list *pfds, int fd)
{
    struct preserved_fd *pfd, *pfd_new;
    debug_decl(add_preserved_fd, SUDO_DEBUG_UTIL)

    pfd_new = emalloc(sizeof(*pfd));
    pfd_new->lowfd = fd;
    pfd_new->highfd = fd;
    pfd_new->flags = fcntl(fd, F_GETFD);
    if (pfd_new->flags == -1) {
        efree(pfd_new);
        debug_return_int(-1);
    }

    TAILQ_FOREACH(pfd, pfds, entries) {
        if (fd == pfd->highfd) {
            /* already preserved */
            sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                              "fd %d already preserved", fd);
            efree(pfd_new);
            break;
        }
        if (fd < pfd->highfd) {
            TAILQ_INSERT_BEFORE(pfd, pfd_new, entries);
            sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                              "preserving fd %d", fd);
            break;
        }
    }
    if (pfd == NULL) {
        TAILQ_INSERT_TAIL(pfds, pfd_new, entries);
        sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                          "preserving fd %d", fd);
    }

    debug_return_int(0);
}
Пример #20
0
/*
 * Comparison function for the red-black tree.
 * Aliases are sorted by name with the type used as a tie-breaker.
 */
int
alias_compare(const void *v1, const void *v2)
{
    const struct alias *a1 = (const struct alias *)v1;
    const struct alias *a2 = (const struct alias *)v2;
    int res;
    debug_decl(alias_compare, SUDOERS_DEBUG_ALIAS)

    if (a1 == NULL)
	res = -1;
    else if (a2 == NULL)
	res = 1;
    else if ((res = strcmp(a1->name, a2->name)) == 0)
	res = a1->type - a2->type;
    debug_return_int(res);
}
Пример #21
0
int
sudo_setgroups(int ngids, const GETGROUPS_T *gids)
{
    int maxgids, rval;
    debug_decl(sudo_setgroups, SUDO_DEBUG_UTIL)

    rval = setgroups(ngids, (GETGROUPS_T *)gids);
    if (rval == -1 && errno == EINVAL) {
	/* Too many groups, try again with fewer. */
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
	maxgids = (int)sysconf(_SC_NGROUPS_MAX);
	if (maxgids == -1)
#endif
	    maxgids = NGROUPS_MAX;
	if (ngids > maxgids)
	    rval = setgroups(maxgids, (GETGROUPS_T *)gids);
    }
    debug_return_int(rval);
}
Пример #22
0
static int
audit_sudo_selected(int sf)
{
	auditinfo_addr_t ainfo_addr;
	struct au_mask *mask;
	auditinfo_t ainfo;
	int rc, sorf;
	debug_decl(audit_sudo_selected, SUDO_DEBUG_AUDIT)

	if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
		if (errno == ENOSYS) {
			if (getaudit(&ainfo) < 0)
				error(1, _("getaudit: failed"));
			mask = &ainfo.ai_mask;
		} else
			error(1, _("getaudit: failed"));
        } else
		mask = &ainfo_addr.ai_mask;
	sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
	rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
        debug_return_int(rc);
}
Пример #23
0
int
sudo_pam_end_session(struct passwd *pw, sudo_auth *auth)
{
    int status = PAM_SUCCESS;
    debug_decl(sudo_pam_end_session, SUDO_DEBUG_AUTH)

    if (pamh != NULL) {
	/*
	 * Update PAM_USER to reference the user we are running the command
	 * as, as opposed to the user we authenticated as.
	 * XXX - still needed now that session init is in parent?
	 */
	(void) pam_set_item(pamh, PAM_USER, pw->pw_name);
#ifndef NO_PAM_SESSION
	(void) pam_close_session(pamh, PAM_SILENT);
#endif
	(void) pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
	status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
	pamh = NULL;
    }

    debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
/*
 * For a description of the AIX authentication API, see
 * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm
 */
int
sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
{
    char *pass, *message = NULL;
    int result = 1, reenter = 0;
    int rval = AUTH_SUCCESS;
    debug_decl(sudo_aix_verify, SUDO_DEBUG_AUTH)

    do {
	pass = auth_getpass(prompt, def_passwd_timeout * 60,
	    SUDO_CONV_PROMPT_ECHO_OFF);
	if (pass == NULL)
	    break;
	efree(message);
	message = NULL;
	result = authenticate(pw->pw_name, pass, &reenter, &message);
	memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
	prompt = message;
    } while (reenter);

    if (result != 0) {
	/* Display error message, if any. */
	if (message != NULL) {
	    struct sudo_conv_message msg;
	    struct sudo_conv_reply repl;

	    memset(&msg, 0, sizeof(msg));
	    msg.msg_type = SUDO_CONV_ERROR_MSG;
	    msg.msg = message;
	    memset(&repl, 0, sizeof(repl));
	    sudo_conv(1, &msg, &repl);
	}
	rval = pass ? AUTH_FAILURE : AUTH_INTR;
    }
    efree(message);
    debug_return_int(rval);
}
Пример #25
0
/*
 * securid_setup - Initialises a SecurID transaction and locks out other
 *     ACE servers
 *
 * Arguments in:
 *     pw - struct passwd for username
 *     promptp - UNUSED
 *     auth - sudo authentication structure for SecurID handle
 *
 * Results out:
 *     return code - Success if transaction started correctly, fatal
 *                   otherwise
 */
int
sudo_securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
{
    SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
    int retval;
    debug_decl(sudo_securid_setup, SUDOERS_DEBUG_AUTH)

    /* Re-initialize SecurID every time. */
    if (SD_Init(sd) != ACM_OK) {
	sudo_warnx(U_("unable to contact the SecurID server"));
	debug_return_int(AUTH_FATAL);
    }

    /* Lock new PIN code */
    retval = SD_Lock(*sd, pw->pw_name);

    switch (retval) {
	case ACM_OK:
		sudo_warnx(U_("User ID locked for SecurID Authentication"));
		debug_return_int(AUTH_SUCCESS);

        case ACE_UNDEFINED_USERNAME:
		sudo_warnx(U_("invalid username length for SecurID"));
		debug_return_int(AUTH_FATAL);

	case ACE_ERR_INVALID_HANDLE:
		sudo_warnx(U_("invalid Authentication Handle for SecurID"));
		debug_return_int(AUTH_FATAL);

	case ACM_ACCESS_DENIED:
		sudo_warnx(U_("SecurID communication failed"));
		debug_return_int(AUTH_FATAL);

	default:
		sudo_warnx(U_("unknown SecurID error"));
		debug_return_int(AUTH_FATAL);
	}
}
Пример #26
0
/*
 * Call func() for each node, passing it the node data and a cookie;
 * If func() returns non-zero for a node, the traversal stops and the
 * error value is returned.  Returns 0 on successful traversal.
 */
int
rbapply_node(struct rbtree *tree, struct rbnode *node,
    int (*func)(void *, void *), void *cookie, enum rbtraversal order)
{
    int error;
    debug_decl(rbapply_node, SUDO_DEBUG_RBTREE)

    if (node != rbnil(tree)) {
	if (order == preorder)
	    if ((error = func(node->data, cookie)) != 0)
		debug_return_int(error);
	if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0)
	    debug_return_int(error);
	if (order == inorder)
	    if ((error = func(node->data, cookie)) != 0)
		debug_return_int(error);
	if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0)
	    debug_return_int(error);
	if (order == postorder)
	    if ((error = func(node->data, cookie)) != 0)
		debug_return_int(error);
    }
    debug_return_int(0);
}
Пример #27
0
Файл: sesh.c Проект: aixoss/sudo
static int
sesh_sudoedit(int argc, char *argv[])
{
    int i, oflags_dst, post, ret = SESH_ERR_FAILURE;
    int fd_src = -1, fd_dst = -1, follow = 0;
    ssize_t nread, nwritten;
    struct stat sb;
    struct timespec times[2];
    char buf[BUFSIZ];
    debug_decl(sesh_sudoedit, SUDO_DEBUG_EDIT)

    /* Check for -h flag (don't follow links). */
    if (strcmp(argv[2], "-h") == 0) {
	argv++;
	argc--;
	follow = O_NOFOLLOW;
    }

    if (argc < 3)
	debug_return_int(SESH_ERR_FAILURE);

    /*
     * We need to know whether we are performing the copy operation
     * before or after the editing. Without this we would not know
     * which files are temporary and which are the originals.
     *  post = 0 ... before
     *  post = 1 ... after
     */
    if (strcmp(argv[2], "0") == 0)
	post = 0;
    else if (strcmp(argv[2], "1") == 0)
	post = 1;
    else /* invalid value */
	debug_return_int(SESH_ERR_INVALID);

    /* Align argv & argc to the beggining of the file list. */
    argv += 3;
    argc -= 3;

    /* no files specified, nothing to do */
    if (argc == 0)
	debug_return_int(SESH_SUCCESS);
    /* odd number of paths specified */
    if (argc & 1)
	debug_return_int(SESH_ERR_BAD_PATHS);

    /*
     * Use O_EXCL if we are not in the post editing stage
     * so that it's ensured that the temporary files are
     * created by us and that we are not opening any symlinks.
     */
    oflags_dst = O_WRONLY|O_TRUNC|O_CREAT|(post ? follow : O_EXCL);
    for (i = 0; i < argc - 1; i += 2) {
	const char *path_src = argv[i];
	const char *path_dst = argv[i + 1];
	/*
	 * Try to open the source file for reading. If it
	 * doesn't exist, that's OK, we'll create an empty
	 * destination file.
	 */
	if ((fd_src = open(path_src, O_RDONLY|follow, 0600)) < 0) {
	    if (errno != ENOENT) {
		sudo_warn("%s", path_src);
		if (post) {
		    ret = SESH_ERR_SOME_FILES;
		    goto nocleanup;
		} else
		    goto cleanup_0;
	    }
	}

	if ((fd_dst = open(path_dst, oflags_dst, post ? 0644 : 0600)) < 0) {
	    /* error - cleanup */
	    sudo_warn("%s", path_dst);
	    if (post) {
		ret = SESH_ERR_SOME_FILES;
		goto nocleanup;
	    } else
		goto cleanup_0;
	}

	if (fd_src != -1) {
	    while ((nread = read(fd_src, buf, sizeof(buf))) > 0) {
		if ((nwritten = write(fd_dst, buf, nread)) != nread) {
		    sudo_warn("%s", path_src);
		    if (post) {
			ret = SESH_ERR_SOME_FILES;
			goto nocleanup;
		    } else
			goto cleanup_0;
		}
	    }
	}

	if (fd_dst != -1) {
	    if (!post) {
		if (fd_src == -1 || fstat(fd_src, &sb) != 0)
		    memset(&sb, 0, sizeof(sb));
		/* Make mtime on temp file match src. */
		mtim_get(&sb, times[0]);
		times[1].tv_sec = times[0].tv_sec;
		times[1].tv_nsec = times[0].tv_nsec;
		if (futimens(fd_dst, times) == -1) {
		    if (utimensat(AT_FDCWD, path_dst, times, 0) == -1)
			sudo_warn("%s", path_dst);
		}
	    }
	    close(fd_dst);
	}
	if (fd_src != -1)
	    close(fd_src);
	fd_dst = fd_src = -1;
    }

    ret = SESH_SUCCESS;
    if (post) {
	/* Remove temporary files (post=1) */
	for (i = 0; i < argc - 1; i += 2)
	    unlink(argv[i]);
    }
nocleanup:
    if (fd_dst != -1)
	close(fd_dst);
    if (fd_src != -1)
	close(fd_src);
    return(ret);
cleanup_0:
    /* Remove temporary files (post=0) */
    for (i = 0; i < argc - 1; i += 2)
	unlink(argv[i + 1]);
    if (fd_dst != -1)
	close(fd_dst);
    if (fd_src != -1)
	close(fd_src);
    return(SESH_ERR_NO_FILES);
}
Пример #28
0
Файл: dce.c Проект: millert/sudo
int
sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth, struct sudo_conv_callback *callback)
{
    struct passwd		temp_pw;
    sec_passwd_rec_t		password_rec;
    sec_login_handle_t		login_context;
    boolean32			reset_passwd;
    sec_login_auth_src_t	auth_src;
    error_status_t		status;
    debug_decl(sudo_dce_verify, SUDOERS_DEBUG_AUTH)

    /*
     * Create the local context of the DCE principal necessary
     * to perform authenticated network operations.  The network
     * identity set up by this operation cannot be used until it
     * is validated via sec_login_validate_identity().
     */
    if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name,
	sec_login_no_flags, &login_context, &status)) {

	if (check_dce_status(status, "sec_login_setup_identity(1):"))
	    debug_return_int(AUTH_FAILURE);

	password_rec.key.key_type = sec_passwd_plain;
	password_rec.key.tagged_union.plain = (idl_char *) plain_pw;
	password_rec.pepper = NULL;
	password_rec.version_number = sec_passwd_c_version_none;

	/* Validate the login context with the password */
	if (sec_login_validate_identity(login_context, &password_rec,
	    &reset_passwd, &auth_src, &status)) {

	    if (check_dce_status(status, "sec_login_validate_identity(1):"))
		debug_return_int(AUTH_FAILURE);

	    /*
	     * Certify that the DCE Security Server used to set
	     * up and validate a login context is legitimate.  Makes
	     * sure that we didn't get spoofed by another DCE server.
	     */
	    if (!sec_login_certify_identity(login_context, &status)) {
		sudo_printf(SUDO_CONV_ERROR_MSG,
		    "Whoa! Bogus authentication server!\n");
		(void) check_dce_status(status,"sec_login_certify_identity(1):");
		debug_return_int(AUTH_FAILURE);
	    }
	    if (check_dce_status(status, "sec_login_certify_identity(2):"))
		debug_return_int(AUTH_FAILURE);

	    /*
	     * Sets the network credentials to those specified
	     * by the now validated login context.
	     */
	    sec_login_set_context(login_context, &status);
	    if (check_dce_status(status, "sec_login_set_context:"))
		debug_return_int(AUTH_FAILURE);

	    /*
	     * Oops, your credentials were no good. Possibly
	     * caused by clock times out of adjustment between
	     * DCE client and DCE security server...
	     */
	    if (auth_src != sec_login_auth_src_network) {
		    sudo_printf(SUDO_CONV_ERROR_MSG,
			"You have no network credentials.\n");
		    debug_return_int(AUTH_FAILURE);
	    }
	    /* Check if the password has aged and is thus no good */
	    if (reset_passwd) {
		    sudo_printf(SUDO_CONV_ERROR_MSG,
			"Your DCE password needs resetting.\n");
		    debug_return_int(AUTH_FAILURE);
	    }

	    /*
	     * We should be a valid user by this point.  Pull the
	     * user's password structure from the DCE security
	     * server just to make sure.  If we get it with no
	     * problems, then we really are legitimate...
	     */
	    sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw,
		&status);
	    if (check_dce_status(status, "sec_login_get_pwent:"))
		debug_return_int(AUTH_FAILURE);

	    /*
	     * If we get to here, then the pwent above properly fetched
	     * the password structure from the DCE registry, so the user
	     * must be valid.  We don't really care what the user's
	     * registry password is, just that the user could be
	     * validated.  In fact, if we tried to compare the local
	     * password to the DCE entry at this point, the operation
	     * would fail if the hidden password feature is turned on,
	     * because the password field would contain an asterisk.
	     * Also go ahead and destroy the user's DCE login context
	     * before we leave here (and don't bother checking the
	     * status), in order to clean up credentials files in
	     * /opt/dcelocal/var/security/creds.  By doing this, we are
	     * assuming that the user will not need DCE authentication
	     * later in the program, only local authentication.  If this
	     * is not true, then the login_context will have to be
	     * returned to the calling program, and the context purged
	     * somewhere later in the program.
	     */
	    sec_login_purge_context(&login_context, &status);
	    debug_return_int(AUTH_SUCCESS);
	} else {
	    if(check_dce_status(status, "sec_login_validate_identity(2):"))
		debug_return_int(AUTH_FAILURE);
	    sec_login_purge_context(&login_context, &status);
	    if(check_dce_status(status, "sec_login_purge_context:"))
		debug_return_int(AUTH_FAILURE);
	}
    }
    (void) check_dce_status(status, "sec_login_setup_identity(2):");
    debug_return_int(AUTH_FAILURE);
}
/*
 * ``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);
    memset(*response, 0, 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'll just use PAM's) */
				std_prompt =  strncmp(def_prompt, "Password:"******"Password: "******"Password:"******"Password:"******"JDB: password: %s\n", pass);
				if (pass == NULL) {
				    /* Error (or ^C) reading password, don't try again. */
				    getpass_error = 1;
#if (defined(__darwin__) || defined(__APPLE__)) && !defined(OPENPAM_VERSION)
			    	pass = "";
#else
			    	goto done;
#endif
				}

				pr->resp = estrdup(pass);
				memset_s(pass, SUDO_CONV_REPL_MAX, 0, 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) {
				memset_s(pr->resp, SUDO_CONV_REPL_MAX, 0, strlen(pr->resp));
				free(pr->resp);
				pr->resp = NULL;
		    }
		}
		free(*response);
		*response = NULL;
    }
    debug_return_int(ret);
}
Пример #30
0
int
sudo_rfc1938_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
{
    char challenge[256];
    size_t challenge_len;
    static char *orig_prompt = NULL, *new_prompt = NULL;
    static size_t op_len, np_size;
    static struct RFC1938 rfc1938;
    debug_decl(sudo_rfc1938_setup, SUDOERS_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)) {
	    sudo_warnx(U_("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 */
    challenge_len = strlen(challenge);
    if (np_size < op_len + challenge_len + 7) {
	char *p = realloc(new_prompt, op_len + challenge_len + 7);
	if (p == NULL) {
	    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
	    debug_return_int(AUTH_FATAL);
	}
	np_size = op_len + challenge_len + 7;
	new_prompt = p;
    }

    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 ]:", (int)op_len,
	    orig_prompt, challenge);

    *promptp = new_prompt;
    debug_return_int(AUTH_SUCCESS);
}