Index: share/man/man7/symlink.7
===================================================================
RCS file: /cvsroot/src/share/man/man7/symlink.7,v
retrieving revision 1.12
diff -u -r1.12 symlink.7
--- share/man/man7/symlink.7	7 Feb 2007 06:41:50 -0000	1.12
+++ share/man/man7/symlink.7	3 Dec 2007 23:22:11 -0000
@@ -432,11 +432,13 @@
 .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 @@
 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
Index: sys/kern/vfs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.100
diff -u -r1.100 vfs_lookup.c
--- sys/kern/vfs_lookup.c	26 Nov 2007 19:02:07 -0000	1.100
+++ sys/kern/vfs_lookup.c	3 Dec 2007 23:22:12 -0000
@@ -120,6 +120,8 @@
 	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 @@
 			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)
Index: etc/rc.d/perusertmp
===================================================================
RCS file: /cvsroot/src/etc/rc.d/perusertmp,v
retrieving revision 1.6
diff -u -r1.6 perusertmp
--- etc/rc.d/perusertmp	15 Feb 2007 13:27:35 -0000	1.6
+++ etc/rc.d/perusertmp	3 Dec 2007 23:22:12 -0000
@@ -40,9 +40,9 @@
 	/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
 }
 
Index: lib/libutil/login_cap.c
===================================================================
RCS file: /cvsroot/src/lib/libutil/login_cap.c,v
retrieving revision 1.28
diff -u -r1.28 login_cap.c
--- lib/libutil/login_cap.c	6 Oct 2007 21:51:22 -0000	1.28
+++ lib/libutil/login_cap.c	3 Dec 2007 23:22:13 -0000
@@ -559,9 +559,11 @@
 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 @@
 	}
 
 	/* 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 @@
 
 	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
