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