Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / check.c
1 /*
2  * Copyright (c) 1993-1996,1998-2005, 2007-2013
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
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.
8  *
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.
16  *
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.
20  */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <stdio.h>
27 #ifdef STDC_HEADERS
28 # include <stdlib.h>
29 # include <stddef.h>
30 #else
31 # ifdef HAVE_STDLIB_H
32 #  include <stdlib.h>
33 # endif
34 #endif /* STDC_HEADERS */
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif /* HAVE_STRING_H */
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif /* HAVE_STRINGS_H */
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 #if TIME_WITH_SYS_TIME
45 # include <time.h>
46 #endif
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <pwd.h>
50 #include <grp.h>
51
52 #include "sudoers.h"
53 #include "check.h"
54
55 static bool display_lecture(int);
56 static struct passwd *get_authpw(void);
57
58 /*
59  * Returns true if the user successfully authenticates, false if not
60  * or -1 on error.
61  */
62 static int
63 check_user_interactive(int validated, int mode, struct passwd *auth_pw)
64 {
65     int status, rval = true;
66     debug_decl(check_user_interactive, SUDO_DEBUG_AUTH)
67
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);
71
72     if (build_timestamp(auth_pw) == -1) {
73         rval = -1;
74         goto done;
75     }
76
77     status = timestamp_status(auth_pw);
78
79     if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
80         char *prompt;
81         bool lectured;
82
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);
87             rval = -1;
88             goto done;
89         }
90
91         /* XXX - should not lecture if askpass helper is being used. */
92         lectured = display_lecture(status);
93
94         /* Expand any escapes in the prompt. */
95         prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
96             user_name, user_shost);
97
98         rval = verify_user(auth_pw, prompt, validated);
99         if (rval == true && lectured)
100             set_lectured();
101         efree(prompt);
102     }
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);
107 done:
108     debug_return_bool(rval);
109 }
110
111 /*
112  * Returns true if the user successfully authenticates, false if not
113  * or -1 on error.
114  */
115 int
116 check_user(int validated, int mode)
117 {
118     struct passwd *auth_pw;
119     int rval = true;
120     debug_decl(check_user, SUDO_DEBUG_AUTH)
121
122     /*
123      * Init authentication system regardless of whether we need a password.
124      * Required for proper PAM session support.
125      */
126     auth_pw = get_authpw();
127     if (sudo_auth_init(auth_pw) == -1) {
128         rval = -1;
129         goto done;
130     }
131
132     /*
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.
135      */
136     if (!def_authenticate || user_uid == 0 || user_is_exempt())
137         goto done;
138     if (user_uid == runas_pw->pw_uid &&
139         (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) {
140 #ifdef HAVE_SELINUX
141         if (user_role == NULL && user_type == NULL)
142 #endif
143 #ifdef HAVE_PRIV_SET
144         if (runas_privs == NULL && runas_limitprivs == NULL)
145 #endif
146             goto done;
147     }
148
149     rval = check_user_interactive(validated, mode, auth_pw);
150
151 done:
152     sudo_auth_cleanup(auth_pw);
153     sudo_pw_delref(auth_pw);
154
155     debug_return_bool(rval);
156 }
157
158 /*
159  * Display sudo lecture (standard or custom).
160  * Returns true if the user was lectured, else false.
161  */
162 static bool
163 display_lecture(int status)
164 {
165     FILE *fp;
166     char buf[BUFSIZ];
167     ssize_t nread;
168     struct sudo_conv_message msg;
169     struct sudo_conv_reply repl;
170     debug_decl(lecture, SUDO_DEBUG_AUTH)
171
172     if (def_lecture == never ||
173         (def_lecture == once && already_lectured(status)))
174         debug_return_bool(false);
175
176     memset(&msg, 0, sizeof(msg));
177     memset(&repl, 0, sizeof(repl));
178
179     if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) {
180         while ((nread = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0) {
181             buf[nread] = '\0';
182             msg.msg_type = SUDO_CONV_ERROR_MSG;
183             msg.msg = buf;
184             sudo_conv(1, &msg, &repl);
185         }
186         fclose(fp);
187     } else {
188         msg.msg_type = SUDO_CONV_ERROR_MSG;
189         msg.msg = _("\n"
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);
196     }
197     debug_return_bool(true);
198 }
199
200 /*
201  * Checks if the user is exempt from supplying a password.
202  */
203 bool
204 user_is_exempt(void)
205 {
206     bool rval = false;
207     debug_decl(user_is_exempt, SUDO_DEBUG_AUTH)
208
209     if (def_exempt_group)
210         rval = user_in_group(sudo_user.pw, def_exempt_group);
211     debug_return_bool(rval);
212 }
213
214 /*
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.
218  */
219 static struct passwd *
220 get_authpw(void)
221 {
222     struct passwd *pw;
223     debug_decl(get_authpw, SUDO_DEBUG_AUTH)
224
225     if (def_rootpw) {
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);
236         pw = runas_pw;
237     } else {
238         sudo_pw_addref(sudo_user.pw);
239         pw = sudo_user.pw;
240     }
241
242     debug_return_ptr(pw);
243 }