2 * Copyright (c) 1993-1996,1998-2005, 2007-2013
3 * Todd C. Miller <Todd.Miller@courtesan.com>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Sponsored in part by the Defense Advanced Research Projects
18 * Agency (DARPA) and Air Force Research Laboratory, Air Force
19 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
24 #include <sys/types.h>
34 #endif /* STDC_HEADERS */
37 #endif /* HAVE_STRING_H */
40 #endif /* HAVE_STRINGS_H */
43 #endif /* HAVE_UNISTD_H */
44 #if TIME_WITH_SYS_TIME
55 static bool display_lecture(int);
56 static struct passwd *get_authpw(void);
59 * Returns true if the user successfully authenticates, false if not
63 check_user_interactive(int validated, int mode, struct passwd *auth_pw)
65 int status, rval = true;
66 debug_decl(check_user_interactive, SUDO_DEBUG_AUTH)
68 /* Always need a password when -k was specified with the command. */
69 if (ISSET(mode, MODE_IGNORE_TICKET))
70 SET(validated, FLAG_CHECK_USER);
72 if (build_timestamp(auth_pw) == -1) {
77 status = timestamp_status(auth_pw);
79 if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
83 /* Bail out if we are non-interactive and a password is required */
84 if (ISSET(mode, MODE_NONINTERACTIVE)) {
85 validated |= FLAG_NON_INTERACTIVE;
86 log_auth_failure(validated, 0);
91 /* XXX - should not lecture if askpass helper is being used. */
92 lectured = display_lecture(status);
94 /* Expand any escapes in the prompt. */
95 prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
96 user_name, user_shost);
98 rval = verify_user(auth_pw, prompt, validated);
99 if (rval == true && lectured)
103 /* Only update timestamp if user was validated. */
104 if (rval == true && ISSET(validated, VALIDATE_OK) &&
105 !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)
106 update_timestamp(auth_pw);
108 debug_return_bool(rval);
112 * Returns true if the user successfully authenticates, false if not
116 check_user(int validated, int mode)
118 struct passwd *auth_pw;
120 debug_decl(check_user, SUDO_DEBUG_AUTH)
123 * Init authentication system regardless of whether we need a password.
124 * Required for proper PAM session support.
126 auth_pw = get_authpw();
127 if (sudo_auth_init(auth_pw) == -1) {
133 * Don't prompt for the root passwd or if the user is exempt.
134 * If the user is not changing uid/gid, no need for a password.
136 if (!def_authenticate || user_uid == 0 || user_is_exempt())
138 if (user_uid == runas_pw->pw_uid &&
139 (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) {
141 if (user_role == NULL && user_type == NULL)
144 if (runas_privs == NULL && runas_limitprivs == NULL)
149 rval = check_user_interactive(validated, mode, auth_pw);
152 sudo_auth_cleanup(auth_pw);
153 sudo_pw_delref(auth_pw);
155 debug_return_bool(rval);
159 * Display sudo lecture (standard or custom).
160 * Returns true if the user was lectured, else false.
163 display_lecture(int status)
168 struct sudo_conv_message msg;
169 struct sudo_conv_reply repl;
170 debug_decl(lecture, SUDO_DEBUG_AUTH)
172 if (def_lecture == never ||
173 (def_lecture == once && already_lectured(status)))
174 debug_return_bool(false);
176 memset(&msg, 0, sizeof(msg));
177 memset(&repl, 0, sizeof(repl));
179 if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) {
180 while ((nread = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0) {
182 msg.msg_type = SUDO_CONV_ERROR_MSG;
184 sudo_conv(1, &msg, &repl);
188 msg.msg_type = SUDO_CONV_ERROR_MSG;
190 "We trust you have received the usual lecture from the local System\n"
191 "Administrator. It usually boils down to these three things:\n\n"
192 " #1) Respect the privacy of others.\n"
193 " #2) Think before you type.\n"
194 " #3) With great power comes great responsibility.\n\n");
195 sudo_conv(1, &msg, &repl);
197 debug_return_bool(true);
201 * Checks if the user is exempt from supplying a password.
207 debug_decl(user_is_exempt, SUDO_DEBUG_AUTH)
209 if (def_exempt_group)
210 rval = user_in_group(sudo_user.pw, def_exempt_group);
211 debug_return_bool(rval);
215 * Get passwd entry for the user we are going to authenticate as.
216 * By default, this is the user invoking sudo. In the most common
217 * case, this matches sudo_user.pw or runas_pw.
219 static struct passwd *
223 debug_decl(get_authpw, SUDO_DEBUG_AUTH)
226 if ((pw = sudo_getpwuid(ROOT_UID)) == NULL)
227 log_fatal(0, N_("unknown uid: %u"), ROOT_UID);
228 } else if (def_runaspw) {
229 if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
230 log_fatal(0, N_("unknown user: %s"), def_runas_default);
231 } else if (def_targetpw) {
232 if (runas_pw->pw_name == NULL)
233 log_fatal(NO_MAIL|MSG_ONLY, N_("unknown uid: %u"),
234 (unsigned int) runas_pw->pw_uid);
235 sudo_pw_addref(runas_pw);
238 sudo_pw_addref(sudo_user.pw);
242 debug_return_ptr(pw);