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); } }
/* 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); }
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); }
/* * 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); }
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); }
/* * 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); }
/* * 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)); }
/* * 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); }
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); }
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); }
/* * 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); }
/* * 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); }
/* * 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); }
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); }
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); }
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); }
/* * 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); } }
/* * 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); }
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); }
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); }
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); }