diff --git a/etc/rc.d/cleartmp b/etc/rc.d/cleartmp index 589ebd8c37a7..384bfa973d22 100755 --- a/etc/rc.d/cleartmp +++ b/etc/rc.d/cleartmp @@ -1,6 +1,6 @@ #!/bin/sh # -# $NetBSD: cleartmp,v 1.9 2007/02/15 08:47:38 xtraeme Exp $ +# $NetBSD: cleartmp,v 1.10 2007/12/04 22:09:01 mjf Exp $ # # PROVIDE: cleartmp @@ -28,7 +28,7 @@ cleartmp_start() tmp_dir="/tmp" # Check if /tmp was created by the perusertmp rc.d # script and recreate it if necessary. - if [ "$(/usr/bin/readlink /tmp)" = ${per_user_tmp_dir}/@uid ]; then + if [ "$(/usr/bin/readlink /tmp)" = ${per_user_tmp_dir}/@ruid ]; then /bin/rm -rf ${tmp_dir} /bin/mkdir ${tmp_dir} /usr/sbin/chown root:wheel ${tmp_dir} diff --git a/etc/rc.d/perusertmp b/etc/rc.d/perusertmp index 00d3d70d1265..2d757e72b0e5 100755 --- a/etc/rc.d/perusertmp +++ b/etc/rc.d/perusertmp @@ -1,6 +1,6 @@ #!/bin/sh # -# $NetBSD: perusertmp,v 1.6 2007/02/15 13:27:35 tron Exp $ +# $NetBSD: perusertmp,v 1.7 2007/12/04 22:09:01 mjf Exp $ # # PROVIDE: perusertmp @@ -40,9 +40,9 @@ perusertmp_start() /bin/chmod 0555 ${per_user_tmp_dir} # Create magic link for /tmp. - if [ "$(/usr/bin/readlink /tmp)" != ${per_user_tmp_dir}/@uid ]; then + if [ "$(/usr/bin/readlink /tmp)" != ${per_user_tmp_dir}/@ruid ]; then /bin/rm -rf /tmp - /bin/ln -s ${per_user_tmp_dir}/@uid /tmp + /bin/ln -s ${per_user_tmp_dir}/@ruid /tmp fi } diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c index ff4b3fe04435..729235f65ffe 100644 --- a/lib/libutil/login_cap.c +++ b/lib/libutil/login_cap.c @@ -1,4 +1,4 @@ -/* $NetBSD: login_cap.c,v 1.28 2007/10/06 21:51:22 christos Exp $ */ +/* $NetBSD: login_cap.c,v 1.29 2007/12/04 22:09:02 mjf Exp $ */ /*- * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved. @@ -36,7 +36,7 @@ #include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: login_cap.c,v 1.28 2007/10/06 21:51:22 christos Exp $"); +__RCSID("$NetBSD: login_cap.c,v 1.29 2007/12/04 22:09:02 mjf Exp $"); #endif /* LIBC_SCCS and not lint */ #include @@ -559,9 +559,11 @@ int setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) { char per_user_tmp[MAXPATHLEN + 1]; + const char *component_name; login_cap_t *flc; quad_t p; int i; + ssize_t len; flc = NULL; @@ -617,27 +619,73 @@ setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) } /* Create per-user temporary directories if needed. */ - if (readlink("/tmp", per_user_tmp, sizeof(per_user_tmp)) != -1) { - static const char atuid[] = "/@uid"; + if ((len = readlink("/tmp", per_user_tmp, + sizeof(per_user_tmp) - 6)) != -1) { + + static const char atuid[] = "/@ruid"; char *lp; + /* readlink does not nul-terminate the string */ + per_user_tmp[len] = '\0'; + /* Check if it's magic symlink. */ lp = strstr(per_user_tmp, atuid); if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') { lp++; - if ((sizeof(per_user_tmp) - (lp - per_user_tmp)) < 64) { + if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) { syslog(LOG_ERR, "real temporary path too long"); login_close(flc); return (-1); } - (void)sprintf(lp, "/%u", pwd->pw_uid); /* safe */ if (mkdir(per_user_tmp, S_IRWXU) != -1) { - (void)chown(per_user_tmp, pwd->pw_uid, - pwd->pw_gid); + if (chown(per_user_tmp, pwd->pw_uid, + pwd->pw_gid)) { + component_name = "chown"; + goto out; + } + + /* + * Must set sticky bit for tmp directory, some + * programs rely on this. + */ + if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) { + component_name = "chmod"; + goto out; + } } else { - syslog(LOG_ERR, "can't create `%s' directory", - per_user_tmp); + if (errno != EEXIST) { + component_name = "mkdir"; + goto out; + } else { + /* + * We must ensure that we own the + * directory and that is has the correct + * permissions, otherwise a DOS attack + * is possible. + */ + struct stat sb; + if (stat(per_user_tmp, &sb) == -1) { + component_name = "stat"; + goto out; + } + + if (sb.st_uid != pwd->pw_uid) { + if (chown(per_user_tmp, + pwd->pw_uid, pwd->pw_gid)) { + component_name = "chown"; + goto out; + } + } + + if (sb.st_mode != (S_IRWXU | S_ISVTX)) { + if (chmod(per_user_tmp, + S_IRWXU | S_ISVTX)) { + component_name = "chmod"; + goto out; + } + } + } } } } @@ -666,6 +714,17 @@ setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) login_close(flc); return (0); + +out: + if (component_name != NULL) { + syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp); + login_close(flc); + return (-1); + } else { + syslog(LOG_ERR, "%s: %m", per_user_tmp); + login_close(flc); + return (-1); + } } void diff --git a/share/man/man7/symlink.7 b/share/man/man7/symlink.7 index 0231628880ce..34083d00da7e 100644 --- a/share/man/man7/symlink.7 +++ b/share/man/man7/symlink.7 @@ -1,4 +1,4 @@ -.\" $NetBSD: symlink.7,v 1.12 2007/02/07 06:41:50 wiz Exp $ +.\" $NetBSD: symlink.7,v 1.13 2007/12/04 22:09:02 mjf Exp $ .\" .\" Copyright (c) 1992, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -432,11 +432,13 @@ or .Fl P options. .Sh MAGIC SYMLINKS -Symlinks in file systems with the -.Li MNT_MAGICLINKS -flag set have +Magic symlinks can be enabled by setting +.Dq vfs.generic.magiclinks +with +.Xr sysctl 8 . +When magic symlinks are enabled .Dq magic -patterns in symlinks expanded. +patterns in symlinks are expanded. Those patterns begin with .Dq @ .Pq an at-sign , @@ -518,6 +520,8 @@ This will always be on .Nx systems. +.It @ruid +Exapnds to the real user-id of the process. .It @uid Expands to the effective user-id of the process. .El diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index e9ac70145861..fb99d3704bc2 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_lookup.c,v 1.100 2007/11/26 19:02:07 pooka Exp $ */ +/* $NetBSD: vfs_lookup.c,v 1.101 2007/12/04 22:09:02 mjf Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.100 2007/11/26 19:02:07 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.101 2007/12/04 22:09:02 mjf Exp $"); #include "opt_systrace.h" #include "opt_magiclinks.h" @@ -120,6 +120,8 @@ symlink_magic(struct proc *p, char *cp, int *len) char *tmp; int change, i, newlen; int termchar = '/'; + char uidtmp[11]; /* XXX elad */ + tmp = PNBUF_GET(); for (change = i = newlen = 0; i < *len; ) { @@ -165,11 +167,13 @@ symlink_magic(struct proc *p, char *cp, int *len) SUBSTITUTE("ostype", ostype, strlen(ostype)); } else if (MATCH("uid")) { - char uidtmp[11]; /* XXX elad */ - (void)snprintf(uidtmp, sizeof(uidtmp), "%u", kauth_cred_geteuid(kauth_cred_get())); SUBSTITUTE("uid", uidtmp, strlen(uidtmp)); + } else if (MATCH("ruid")) { + (void)snprintf(uidtmp, sizeof(uidtmp), "%u", + kauth_cred_getuid(kauth_cred_get())); + SUBSTITUTE("ruid", uidtmp, strlen(uidtmp)); } else { tmp[newlen++] = '@'; if (termchar == VC)