* NEWS, libmisc/chowntty.c: Fix a race condition that could lead
to gaining ownership or changing mode of arbitrary files.
+ * NEWS, libmisc/chowntty.c, libmisc/utmp.c: is_my_tty() moved from
+ utmp.c to chowntty.c. checkutmp() now only uses an existing utmp
+ entry if the pid matches and ut_line matches with the current tty.
+ This fixes a possible DOS when entries can be forged in the utmp
+ file.
+ * libmisc/chowntty.c, src/login.c, lib/prototypes.h: Remove the
+ tty argument from chown_tty. chown_tty always changes stdin and
+ does not need this argument anymore.
2008-06-26 Nicolas François <nicolas.francois@centraliens.net>
*** security
- Fix a race condition in login that could lead to gaining ownership or
changing mode of arbitrary files.
+- Fix a possible login DOS, which could be caused by injecting forged
+ entries in utmp.
shadow-4.1.2 -> shadow-4.1.2.1 26-06-2008
extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t);
/* chowntty.c */
-extern void chown_tty (const char *, const struct passwd *);
+extern void chown_tty (const struct passwd *);
/* console.c */
extern int console (const char *);
#include "defines.h"
#include <pwd.h>
#include "getdef.h"
-/*
- * is_my_tty -- determine if "tty" is the same as TTY stdin is using
- */
-static int is_my_tty (const char *tty)
-{
- struct stat by_name, by_fd;
-
- if (stat (tty, &by_name) || fstat (0, &by_fd))
- return 0;
-
- if (by_name.st_rdev != by_fd.st_rdev)
- return 0;
- else
- return 1;
-}
-
/*
* chown_tty() sets the login tty to be owned by the new user ID
* with TTYPERM modes
*/
-void chown_tty (const char *tty, const struct passwd *info)
+void chown_tty (const struct passwd *info)
{
- char buf[200], full_tty[200];
char *group; /* TTY group name or number */
struct group *grent;
gid_t gid;
* the group as determined above.
*/
- if (*tty != '/') {
- snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
- tty = full_tty;
- }
-
- if (!is_my_tty (tty)) {
- SYSLOG ((LOG_WARN,
- "unable to determine TTY name, got %s\n", tty));
- closelog ();
- exit (1);
- }
-
if (fchown (STDIN_FILENO, info->pw_uid, gid) ||
fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600))) {
int err = errno;
#define NO_TTY \
_("Unable to determine your tty name.")
+/*
+ * is_my_tty -- determine if "tty" is the same TTY stdin is using
+ */
+static int is_my_tty (const char *tty)
+{
+ char full_tty[200];
+ struct stat by_name, by_fd;
+
+ if ('/' != *tty) {
+ snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
+ tty = full_tty;
+ }
+
+ if ((stat (tty, &by_name) != 0) || (fstat (STDIN_FILENO, &by_fd) != 0)) {
+ return 0;
+ }
+
+ if (by_name.st_rdev != by_fd.st_rdev) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
/*
* checkutmp - see if utmp file is correct for this process
*
while ((ut = getutent ()))
if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
(ut->ut_type == LOGIN_PROCESS
- || ut->ut_type == USER_PROCESS))
+ || ut->ut_type == USER_PROCESS) &&
+ is_my_tty (ut->ut_line))
break;
/* If there is one, just use it, otherwise create a new one. */
}
setup_limits (&pwent); /* nice, ulimit etc. */
#endif /* ! USE_PAM */
- chown_tty (tty, &pwent);
+ chown_tty (&pwent);
#ifdef USE_PAM
/*