summaryrefslogtreecommitdiff
path: root/usr.bin/sudo/sudo_edit.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2007-07-26 16:10:17 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2007-07-26 16:10:17 +0000
commit828fe35b0dee0a24eae19e816e9f6bc05c720bc0 (patch)
tree2adb27efde016e50eadcf2e74892e19861268a25 /usr.bin/sudo/sudo_edit.c
parenteb13f7f0aa17caa3bf79e5518751b3f095fb2445 (diff)
Update to sudo 1.6.9p1. Note that the environment handling in sudo
1.6.9 has changed relative to older versions. Sudo now starts commands with a minimal environment containing the variables in the env_keep and env_check lists. This behavior is configurable in the sudoers file. Please see the "SECURITY NOTES" section in the sudo manual.
Diffstat (limited to 'usr.bin/sudo/sudo_edit.c')
-rw-r--r--usr.bin/sudo/sudo_edit.c126
1 files changed, 73 insertions, 53 deletions
diff --git a/usr.bin/sudo/sudo_edit.c b/usr.bin/sudo/sudo_edit.c
index f765e8a0a7d..d92a9909479 100644
--- a/usr.bin/sudo/sudo_edit.c
+++ b/usr.bin/sudo/sudo_edit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "config.h"
+#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
@@ -48,32 +48,40 @@
#endif /* HAVE_ERR_H */
#include <ctype.h>
#include <pwd.h>
+#include <grp.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
-#include <time.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifndef HAVE_TIMESPEC
+# include <emul/timespec.h>
+#endif
#include "sudo.h"
#ifndef lint
-static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.16 2004/09/15 16:16:20 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.6.2.7 2007/07/08 18:44:41 millert Exp $";
#endif /* lint */
extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
+extern char **environ;
/*
* Wrapper to allow users to edit privileged files with their own uid.
*/
-int sudo_edit(argc, argv)
+int sudo_edit(argc, argv, envp)
int argc;
char **argv;
+ char **envp;
{
ssize_t nread, nwritten;
pid_t kidpid, pid;
const char *tmpdir;
char **nargv, **ap, *editor, *cp;
char buf[BUFSIZ];
- int i, ac, ofd, tfd, nargc, rval, tmplen;
+ int error, i, ac, ofd, tfd, nargc, rval, tmplen, wasblank;
sigaction_t sa;
struct stat sb;
struct timespec ts1, ts2;
@@ -102,36 +110,38 @@ int sudo_edit(argc, argv)
/*
* For each file specified by the user, make a temporary version
* and copy the contents of the original to it.
- * XXX - It would be nice to lock the original files but that means
- * keeping an extra fd open for each file.
*/
tf = emalloc2(argc - 1, sizeof(*tf));
memset(tf, 0, (argc - 1) * sizeof(*tf));
for (i = 0, ap = argv + 1; i < argc - 1 && *ap != NULL; i++, ap++) {
+ error = -1;
set_perms(PERM_RUNAS);
- ofd = open(*ap, O_RDONLY, 0644);
- if (ofd != -1) {
+
+ /*
+ * We close the password file before we try to open the user-specified
+ * path to prevent the opening of things like /dev/fd/4.
+ */
+ endpwent();
+ if ((ofd = open(*ap, O_RDONLY, 0644)) != -1 || errno == ENOENT) {
+ if (ofd == -1) {
+ memset(&sb, 0, sizeof(sb)); /* new file */
+ error = 0;
+ } else {
#ifdef HAVE_FSTAT
- if (fstat(ofd, &sb) != 0) {
+ error = fstat(ofd, &sb);
#else
- if (stat(tf[i].ofile, &sb) != 0) {
+ error = stat(tf[i].ofile, &sb);
#endif
- close(ofd); /* XXX - could reset errno */
- ofd = -1;
}
}
set_perms(PERM_ROOT);
- if (ofd == -1) {
- if (errno != ENOENT) {
+ if (error || !S_ISREG(sb.st_mode)) {
+ if (error)
warn("%s", *ap);
- argc--;
- i--;
- continue;
- }
- memset(&sb, 0, sizeof(sb));
- } else if (!S_ISREG(sb.st_mode)) {
- warnx("%s: not a regular file", *ap);
- close(ofd);
+ else
+ warnx("%s: not a regular file", *ap);
+ if (ofd != -1)
+ close(ofd);
argc--;
i--;
continue;
@@ -189,6 +199,7 @@ int sudo_edit(argc, argv)
* based on def_env_editor or def_editor since the editor runs with
* the uid of the invoking user, not the runas (privileged) user.
*/
+ environ = envp;
if (((editor = getenv("VISUAL")) != NULL && *editor != '\0') ||
((editor = getenv("EDITOR")) != NULL && *editor != '\0')) {
editor = estrdup(editor);
@@ -204,9 +215,13 @@ int sudo_edit(argc, argv)
* line args so look for those and alloc space for them too.
*/
nargc = argc;
- for (cp = editor + 1; *cp != '\0'; cp++) {
- if (isblank((unsigned char)cp[0]) && !isblank((unsigned char)cp[-1]))
+ for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) {
+ if (isblank((unsigned char) *cp))
+ wasblank = TRUE;
+ else if (wasblank) {
+ wasblank = FALSE;
nargc++;
+ }
}
nargv = (char **) emalloc2(nargc + 1, sizeof(char *));
ac = 0;
@@ -238,6 +253,9 @@ int sudo_edit(argc, argv)
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
(void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
set_perms(PERM_FULL_USER);
+ endpwent();
+ endgrent();
+ closefrom(STDERR_FILENO + 1);
execvp(nargv[0], nargv);
warn("unable to execute %s", nargv[0]);
_exit(127);
@@ -246,7 +264,7 @@ int sudo_edit(argc, argv)
/*
* Wait for status from the child. Most modern kernels
* will not let an unprivileged child process send a
- * signal to its privileged parent to we have to request
+ * signal to its privileged parent so we have to request
* status when the child is stopped and then send the
* same signal to our own pid.
*/
@@ -271,42 +289,44 @@ int sudo_edit(argc, argv)
/* Copy contents of temp files to real ones */
for (i = 0; i < argc - 1; i++) {
+ error = -1;
set_perms(PERM_USER);
- tfd = open(tf[i].tfile, O_RDONLY, 0644);
+ if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) {
+#ifdef HAVE_FSTAT
+ error = fstat(tfd, &sb);
+#else
+ error = stat(tf[i].tfile, &sb);
+#endif
+ }
set_perms(PERM_ROOT);
- if (tfd < 0) {
- warn("unable to read %s", tf[i].tfile);
+ if (error || !S_ISREG(sb.st_mode)) {
+ if (error)
+ warn("%s", tf[i].tfile);
+ else
+ warnx("%s: not a regular file", tf[i].tfile);
warnx("%s left unmodified", tf[i].ofile);
+ if (tfd != -1)
+ close(tfd);
continue;
}
-#ifdef HAVE_FSTAT
- if (fstat(tfd, &sb) == 0) {
- if (!S_ISREG(sb.st_mode)) {
- warnx("%s: not a regular file", tf[i].tfile);
- warnx("%s left unmodified", tf[i].ofile);
- continue;
- }
- if (tf[i].osize == sb.st_size &&
- tf[i].omtim.tv_sec == mtim_getsec(sb) &&
- tf[i].omtim.tv_nsec == mtim_getnsec(sb)) {
- /*
- * If mtime and size match but the user spent no measurable
- * time in the editor we can't tell if the file was changed.
- */
+ if (tf[i].osize == sb.st_size && tf[i].omtim.tv_sec == mtim_getsec(sb)
+ && tf[i].omtim.tv_nsec == mtim_getnsec(sb)) {
+ /*
+ * If mtime and size match but the user spent no measurable
+ * time in the editor we can't tell if the file was changed.
+ */
#ifdef HAVE_TIMESPECSUB2
- timespecsub(&ts1, &ts2);
+ timespecsub(&ts1, &ts2);
#else
- timespecsub(&ts1, &ts2, &ts2);
+ timespecsub(&ts1, &ts2, &ts2);
#endif
- if (timespecisset(&ts2)) {
- warnx("%s unchanged", tf[i].ofile);
- unlink(tf[i].tfile);
- close(tfd);
- continue;
- }
+ if (timespecisset(&ts2)) {
+ warnx("%s unchanged", tf[i].ofile);
+ unlink(tf[i].tfile);
+ close(tfd);
+ continue;
}
}
-#endif
set_perms(PERM_RUNAS);
ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
set_perms(PERM_ROOT);