nsprpub/config/nsinstall.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7 ** Netscape portable install command.
     8 **
     9 ** Brendan Eich, 7/20/95
    10 */
    11 #include <stdio.h>  /* OSF/1 requires this before grp.h, so put it first */
    12 #include <assert.h>
    13 #include <fcntl.h>
    14 #include <grp.h>
    15 #include <pwd.h>
    16 #include <stdlib.h>
    17 #include <string.h>
    18 #include <unistd.h>
    19 #include <utime.h>
    20 #include <sys/types.h>
    21 #include <sys/stat.h>
    22 #include <dirent.h>
    23 #include <errno.h>
    24 #include <stdarg.h>
    25 #ifdef USE_REENTRANT_LIBC
    26 #include "libc_r.h"
    27 #endif /* USE_REENTRANT_LIBC */
    29 #include "pathsub.h"
    31 #define HAVE_FCHMOD
    33 #if defined(BEOS)
    34 #undef HAVE_FCHMOD
    35 #endif
    37 /*
    38  * Does getcwd() take NULL as the first argument and malloc
    39  * the result buffer?
    40  */
    41 #if !defined(DARWIN)
    42 #define GETCWD_CAN_MALLOC
    43 #endif
    45 #if defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) 
    46 #include <getopt.h>
    47 #endif
    49 #if defined(SCO) || defined(UNIXWARE)
    50 #if !defined(S_ISLNK) && defined(S_IFLNK)
    51 #define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
    52 #endif
    53 #endif
    55 #ifdef QNX
    56 #define d_ino d_stat.st_ino
    57 #endif
    59 static void
    60 usage(void)
    61 {
    62     fprintf(stderr,
    63 	"usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
    64 	"       %*s [-DdltR] file [file ...] directory\n",
    65 	program, (int)strlen(program), "");
    66     exit(2);
    67 }
    69 static int
    70 mkdirs(char *path, mode_t mode)
    71 {
    72     char *cp;
    73     struct stat sb;
    74     int res;
    76     while (*path == '/' && path[1] == '/')
    77 	path++;
    78     for (cp = strrchr(path, '/'); cp && cp != path && cp[-1] == '/'; cp--)
    79 	;
    80     if (cp && cp != path) {
    81 	*cp = '\0';
    82 	if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
    83 	    mkdirs(path, mode) < 0) {
    84 	    return -1;
    85 	}
    86 	*cp = '/';
    87     }
    88     res = mkdir(path, mode);
    89     if ((res != 0) && (errno == EEXIST))
    90 	return 0;
    91      else
    92 	return res;
    93 }
    95 static uid_t
    96 touid(char *owner)
    97 {
    98     struct passwd *pw;
    99     uid_t uid;
   100     char *cp;
   102     pw = getpwnam(owner);
   103     if (pw)
   104 	return pw->pw_uid;
   105     uid = strtol(owner, &cp, 0);
   106     if (uid == 0 && cp == owner)
   107 	fail("cannot find uid for %s", owner);
   108     return uid;
   109 }
   111 static gid_t
   112 togid(char *group)
   113 {
   114     struct group *gr;
   115     gid_t gid;
   116     char *cp;
   118     gr = getgrnam(group);
   119     if (gr)
   120 	return gr->gr_gid;
   121     gid = strtol(group, &cp, 0);
   122     if (gid == 0 && cp == group)
   123 	fail("cannot find gid for %s", group);
   124     return gid;
   125 }
   127 int
   128 main(int argc, char **argv)
   129 {
   130     int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
   131     mode_t mode = 0755;
   132     char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
   133     uid_t uid;
   134     gid_t gid;
   135     struct stat sb, tosb;
   136     struct utimbuf utb;
   138     program = argv[0];
   139     cwd = linkname = linkprefix = owner = group = 0;
   140     onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0;
   142     while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
   143 	switch (opt) {
   144 	  case 'C':
   145 	    cwd = optarg;
   146 	    break;
   147 	  case 'D':
   148 	    onlydir = 1;
   149 	    break;
   150 	  case 'd':
   151 	    dodir = 1;
   152 	    break;
   153 	  case 'l':
   154 	    dolink = 1;
   155 	    break;
   156 	  case 'L':
   157 	    linkprefix = optarg;
   158 	    lplen = strlen(linkprefix);
   159 	    dolink = 1;
   160 	    break;
   161 	  case 'R':
   162 	    dolink = dorelsymlink = 1;
   163 	    break;
   164 	  case 'm':
   165 	    mode = strtoul(optarg, &cp, 8);
   166 	    if (mode == 0 && cp == optarg)
   167 		usage();
   168 	    break;
   169 	  case 'o':
   170 	    owner = optarg;
   171 	    break;
   172 	  case 'g':
   173 	    group = optarg;
   174 	    break;
   175 	  case 't':
   176 	    dotimes = 1;
   177 	    break;
   178 	  default:
   179 	    usage();
   180 	}
   181     }
   183     argc -= optind;
   184     argv += optind;
   185     if (argc < 2 - onlydir)
   186 	usage();
   188     todir = argv[argc-1];
   189     if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
   190 	mkdirs(todir, 0777) < 0) {
   191 	fail("cannot make directory %s", todir);
   192     }
   193     if (onlydir)
   194 	return 0;
   196     if (!cwd) {
   197 #ifdef GETCWD_CAN_MALLOC
   198 	cwd = getcwd(0, PATH_MAX);
   199 #else
   200 	cwd = malloc(PATH_MAX + 1);
   201 	cwd = getcwd(cwd, PATH_MAX);
   202 #endif
   203     }
   204     xchdir(todir);
   205 #ifdef GETCWD_CAN_MALLOC
   206     todir = getcwd(0, PATH_MAX);
   207 #else
   208     todir = malloc(PATH_MAX + 1);
   209     todir = getcwd(todir, PATH_MAX);
   210 #endif
   211     xchdir(cwd);
   212     tdlen = strlen(todir);
   214     uid = owner ? touid(owner) : -1;
   215     gid = group ? togid(group) : -1;
   217     while (--argc > 0) {
   218 	name = *argv++;
   219 	len = strlen(name);
   220 	base = xbasename(name);
   221 	bnlen = strlen(base);
   222 	toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
   223 	sprintf(toname, "%s/%s", todir, base);
   224 	exists = (lstat(toname, &tosb) == 0);
   226 	if (dodir) {
   227 	    /* -d means create a directory, always */
   228 	    if (exists && !S_ISDIR(tosb.st_mode)) {
   229 		(void) unlink(toname);
   230 		exists = 0;
   231 	    }
   232 	    if (!exists && mkdir(toname, mode) < 0)
   233 		fail("cannot make directory %s", toname);
   234 	    if ((owner || group) && chown(toname, uid, gid) < 0)
   235 		fail("cannot change owner of %s", toname);
   236 	} else if (dolink) {
   237 	    if (*name == '/') {
   238 		/* source is absolute pathname, link to it directly */
   239 		linkname = 0;
   240 	    } else {
   241 		if (linkprefix) {
   242 		    /* -L implies -l and prefixes names with a $cwd arg. */
   243 		    len += lplen + 1;
   244 		    linkname = (char*)xmalloc(len + 1);
   245 		    sprintf(linkname, "%s/%s", linkprefix, name);
   246 		} else if (dorelsymlink) {
   247 		    /* Symlink the relative path from todir to source name. */
   248 		    linkname = (char*)xmalloc(PATH_MAX);
   250 		    if (*todir == '/') {
   251 			/* todir is absolute: skip over common prefix. */
   252 			lplen = relatepaths(todir, cwd, linkname);
   253 			strcpy(linkname + lplen, name);
   254 		    } else {
   255 			/* todir is named by a relative path: reverse it. */
   256 			reversepath(todir, name, len, linkname);
   257 			xchdir(cwd);
   258 		    }
   260 		    len = strlen(linkname);
   261 		}
   262 		name = linkname;
   263 	    }
   265 	    /* Check for a pre-existing symlink with identical content. */
   266 	    if (exists &&
   267 		(!S_ISLNK(tosb.st_mode) ||
   268 		 readlink(toname, buf, sizeof buf) != len ||
   269 		 strncmp(buf, name, len) != 0)) {
   270 		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
   271 		exists = 0;
   272 	    }
   273 	    if (!exists && symlink(name, toname) < 0)
   274 		fail("cannot make symbolic link %s", toname);
   275 #ifdef HAVE_LCHOWN
   276 	    if ((owner || group) && lchown(toname, uid, gid) < 0)
   277 		fail("cannot change owner of %s", toname);
   278 #endif
   280 	    if (linkname) {
   281 		free(linkname);
   282 		linkname = 0;
   283 	    }
   284 	} else {
   285 	    /* Copy from name to toname, which might be the same file. */
   286 	    fromfd = open(name, O_RDONLY);
   287 	    if (fromfd < 0 || fstat(fromfd, &sb) < 0)
   288 		fail("cannot access %s", name);
   289 	    if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
   290 		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
   291 	    tofd = open(toname, O_CREAT | O_WRONLY, 0666);
   292 	    if (tofd < 0)
   293 		fail("cannot create %s", toname);
   295 	    bp = buf;
   296 	    while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
   297 		while ((wc = write(tofd, bp, cc)) > 0) {
   298 		    if ((cc -= wc) == 0)
   299 			break;
   300 		    bp += wc;
   301 		}
   302 		if (wc < 0)
   303 		    fail("cannot write to %s", toname);
   304 	    }
   305 	    if (cc < 0)
   306 		fail("cannot read from %s", name);
   308 	    if (ftruncate(tofd, sb.st_size) < 0)
   309 		fail("cannot truncate %s", toname);
   310 	    if (dotimes) {
   311 		utb.actime = sb.st_atime;
   312 		utb.modtime = sb.st_mtime;
   313 		if (utime(toname, &utb) < 0)
   314 		    fail("cannot set times of %s", toname);
   315 	    }
   316 #ifdef HAVE_FCHMOD
   317 	    if (fchmod(tofd, mode) < 0)
   318 #else
   319 	    if (chmod(toname, mode) < 0)
   320 #endif
   321 		fail("cannot change mode of %s", toname);
   322 	    if ((owner || group) && fchown(tofd, uid, gid) < 0)
   323 		fail("cannot change owner of %s", toname);
   325 	    /* Must check for delayed (NFS) write errors on close. */
   326 	    if (close(tofd) < 0)
   327 		fail("cannot write to %s", toname);
   328 	    close(fromfd);
   329 	}
   331 	free(toname);
   332     }
   334     free(cwd);
   335     free(todir);
   336     return 0;
   337 }
   339 /*
   340 ** Pathname subroutines.
   341 **
   342 ** Brendan Eich, 8/29/95
   343 */
   345 char *program;
   347 void
   348 fail(char *format, ...)
   349 {
   350     int error;
   351     va_list ap;
   353 #ifdef USE_REENTRANT_LIBC
   354     R_STRERROR_INIT_R();
   355 #endif
   357     error = errno;
   358     fprintf(stderr, "%s: ", program);
   359     va_start(ap, format);
   360     vfprintf(stderr, format, ap);
   361     va_end(ap);
   362     if (error)
   364 #ifdef USE_REENTRANT_LIBC
   365     R_STRERROR_R(errno);
   366 	fprintf(stderr, ": %s", r_strerror_r);
   367 #else
   368 	fprintf(stderr, ": %s", strerror(errno));
   369 #endif
   371     putc('\n', stderr);
   372     exit(1);
   373 }
   375 char *
   376 getcomponent(char *path, char *name)
   377 {
   378     if (*path == '\0')
   379 	return 0;
   380     if (*path == '/') {
   381 	*name++ = '/';
   382     } else {
   383 	do {
   384 	    *name++ = *path++;
   385 	} while (*path != '/' && *path != '\0');
   386     }
   387     *name = '\0';
   388     while (*path == '/')
   389 	path++;
   390     return path;
   391 }
   393 #ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL
   394 /* Sigh.  The static buffer in Unixware's readdir is too small. */
   395 struct dirent * readdir(DIR *d)
   396 {
   397         static struct dirent *buf = NULL;
   398 #define MAX_PATH_LEN 1024
   401         if(buf == NULL)
   402                 buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
   403 ;
   404         return(readdir_r(d, buf));
   405 }
   406 #endif
   408 char *
   409 ino2name(ino_t ino, char *dir)
   410 {
   411     DIR *dp;
   412     struct dirent *ep;
   413     char *name;
   415     dp = opendir("..");
   416     if (!dp)
   417 	fail("cannot read parent directory");
   418     for (;;) {
   419 	if (!(ep = readdir(dp)))
   420 	    fail("cannot find current directory");
   421 	if (ep->d_ino == ino)
   422 	    break;
   423     }
   424     name = xstrdup(ep->d_name);
   425     closedir(dp);
   426     return name;
   427 }
   429 void *
   430 xmalloc(size_t size)
   431 {
   432     void *p = malloc(size);
   433     if (!p)
   434 	fail("cannot allocate %u bytes", size);
   435     return p;
   436 }
   438 char *
   439 xstrdup(char *s)
   440 {
   441     return strcpy((char*)xmalloc(strlen(s) + 1), s);
   442 }
   444 char *
   445 xbasename(char *path)
   446 {
   447     char *cp;
   449     while ((cp = strrchr(path, '/')) && cp[1] == '\0')
   450 	*cp = '\0';
   451     if (!cp) return path;
   452     return cp + 1;
   453 }
   455 void
   456 xchdir(char *dir)
   457 {
   458     if (chdir(dir) < 0)
   459 	fail("cannot change directory to %s", dir);
   460 }
   462 int
   463 relatepaths(char *from, char *to, char *outpath)
   464 {
   465     char *cp, *cp2;
   466     int len;
   467     char buf[NAME_MAX];
   469     assert(*from == '/' && *to == '/');
   470     for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
   471 	if (*cp == '\0')
   472 	    break;
   473     while (cp[-1] != '/')
   474 	cp--, cp2--;
   475     if (cp - 1 == to) {
   476 	/* closest common ancestor is /, so use full pathname */
   477 	len = strlen(strcpy(outpath, to));
   478 	if (outpath[len] != '/') {
   479 	    outpath[len++] = '/';
   480 	    outpath[len] = '\0';
   481 	}
   482     } else {
   483 	len = 0;
   484 	while ((cp2 = getcomponent(cp2, buf)) != 0) {
   485 	    strcpy(outpath + len, "../");
   486 	    len += 3;
   487 	}
   488 	while ((cp = getcomponent(cp, buf)) != 0) {
   489 	    sprintf(outpath + len, "%s/", buf);
   490 	    len += strlen(outpath + len);
   491 	}
   492     }
   493     return len;
   494 }
   496 void
   497 reversepath(char *inpath, char *name, int len, char *outpath)
   498 {
   499     char *cp, *cp2;
   500     char buf[NAME_MAX];
   501     struct stat sb;
   503     cp = strcpy(outpath + PATH_MAX - (len + 1), name);
   504     cp2 = inpath;
   505     while ((cp2 = getcomponent(cp2, buf)) != 0) {
   506 	if (strcmp(buf, ".") == 0)
   507 	    continue;
   508 	if (strcmp(buf, "..") == 0) {
   509 	    if (stat(".", &sb) < 0)
   510 		fail("cannot stat current directory");
   511 	    name = ino2name(sb.st_ino, "..");
   512 	    len = strlen(name);
   513 	    cp -= len + 1;
   514 	    strcpy(cp, name);
   515 	    cp[len] = '/';
   516 	    free(name);
   517 	    xchdir("..");
   518 	} else {
   519 	    cp -= 3;
   520 	    strncpy(cp, "../", 3);
   521 	    xchdir(buf);
   522 	}
   523     }
   524     strcpy(outpath, cp);
   525 }

mercurial