diff options
Diffstat (limited to 'usr.sbin/rmt')
-rw-r--r-- | usr.sbin/rmt/rmt.8 | 30 | ||||
-rw-r--r-- | usr.sbin/rmt/rmt.c | 121 |
2 files changed, 138 insertions, 13 deletions
diff --git a/usr.sbin/rmt/rmt.8 b/usr.sbin/rmt/rmt.8 index a48d3d5e3dc..daf626135e2 100644 --- a/usr.sbin/rmt/rmt.8 +++ b/usr.sbin/rmt/rmt.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rmt.8,v 1.12 2011/07/23 15:40:13 schwarze Exp $ +.\" $OpenBSD: rmt.8,v 1.13 2015/09/20 10:05:48 halex Exp $ .\" .\" Copyright (c) 1983, 1991 The Regents of the University of California. .\" All rights reserved. @@ -29,19 +29,22 @@ .\" .\" from: @(#)rmt.8 6.5 (Berkeley) 3/16/91 .\" -.Dd $Mdocdate: July 23 2011 $ +.Dd $Mdocdate: September 20 2015 $ .Dt RMT 8 .Os .Sh NAME .Nm rmt .Nd remote magtape protocol module .Sh SYNOPSIS -.Nm rmt +.Nm +.Op Fl r | w +.Op Fl d Ar directory .Sh DESCRIPTION .Nm is a program used by the remote dump and restore programs -in manipulating a magnetic tape drive through an interprocess -communication connection. +through an interprocess communication connection. +Traditionally it is used for manipulating a magnetic tape drive but it may +be used for regular file access as well. .Nm is normally started up with an .Xr rcmd 3 @@ -49,6 +52,23 @@ or .Xr rcmdsh 3 call. .Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d Ar directory +Confine file access to +.Ar directory . +Forward slashes in filenames are disallowed and symlinks are not followed. +.It Fl r +Read-only mode, suitable for use with +.Xr rrestore 8 . +.It Fl w +File write mode, suitable for use with +.Xr rdump 8 +for dumping to regular files. +Creates missing files and refuses to open existing ones. +The file permission bits are set to readonly. +.El +.Pp The .Nm program accepts requests specific to the manipulation of diff --git a/usr.sbin/rmt/rmt.c b/usr.sbin/rmt/rmt.c index 28d31dd1c33..9a887438016 100644 --- a/usr.sbin/rmt/rmt.c +++ b/usr.sbin/rmt/rmt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rmt.c,v 1.15 2015/01/16 06:40:20 deraadt Exp $ */ +/* $OpenBSD: rmt.c,v 1.16 2015/09/20 10:05:48 halex Exp $ */ /* * Copyright (c) 1983 Regents of the University of California. @@ -41,6 +41,7 @@ #include <unistd.h> #include <stdio.h> #include <stdlib.h> +#include <err.h> #include <errno.h> #include <string.h> #include <limits.h> @@ -52,6 +53,7 @@ int maxrecsize = -1; #define STRSIZE 64 char device[PATH_MAX]; +char lastdevice[PATH_MAX] = ""; char count[STRSIZE], mode[STRSIZE], pos[STRSIZE], op[STRSIZE]; char resp[BUFSIZ]; @@ -61,9 +63,10 @@ FILE *debug; #define DEBUG1(f,a) if (debug) fprintf(debug, f, a) #define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2) -char *checkbuf(char *, int); -void getstring(char *, int); -void error(int); +char *checkbuf(char *, int); +void getstring(char *, int); +void error(int); +__dead void usage(void); int main(int argc, char *argv[]) @@ -72,14 +75,50 @@ main(int argc, char *argv[]) int rval; char c; int n, i, cc; + int ch, rflag = 0, wflag = 0; + int f, acc; + mode_t m; + char *dir = NULL; + char *devp; + size_t dirlen; + + while ((ch = getopt(argc, argv, "d:rw")) != -1) { + switch (ch) { + case 'd': + dir = optarg; + if (*dir != '/') + errx(1, "directory must be absolute"); + break; + case 'r': + rflag = 1; + break; + case 'w': + wflag = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (rflag && wflag) + usage(); - argc--, argv++; if (argc > 0) { debug = fopen(*argv, "w"); if (debug == 0) - exit(1); + err(1, "cannot open debug file"); (void) setbuf(debug, (char *)0); } + + if (dir) { + if (chdir(dir) != 0) + err(1, "chdir"); + dirlen = strlen(dir); + } + top: errno = 0; rval = 0; @@ -93,10 +132,66 @@ top: getstring(device, sizeof(device)); getstring(mode, sizeof(mode)); DEBUG2("rmtd: O %s %s\n", device, mode); - tape = open(device, atoi(mode), - S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + + devp = device; + f = atoi(mode); + m = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + acc = f & O_ACCMODE; + if (dir) { + /* Strip away valid directory prefix. */ + if (strncmp(dir, devp, dirlen) == 0 && + (devp[dirlen - 1] == '/' || + devp[dirlen] == '/')) { + devp += dirlen; + while (*devp == '/') + devp++; + } + /* Don't allow directory traversal. */ + if (strchr(devp, '/')) { + errno = EACCES; + goto ioerror; + } + f |= O_NOFOLLOW; + } + if (rflag) { + /* + * Only allow readonly open and ignore file + * creation requests. + */ + if (acc != O_RDONLY) { + errno = EPERM; + goto ioerror; + } + f &= ~O_CREAT; + } else if (wflag) { + /* + * Require, and force creation of, a nonexistant file, + * unless we are reopening the last opened file again, + * in which case it is opened read-only. + */ + if (strcmp(devp, lastdevice) != 0) { + /* + * Disallow read-only open since that would + * only result in an empty file. + */ + if (acc == O_RDONLY) { + errno = EPERM; + goto ioerror; + } + f |= O_CREAT | O_EXCL; + } else { + acc = O_RDONLY; + } + /* Create readonly file */ + m = S_IRUSR|S_IRGRP|S_IROTH; + } + /* Apply new access mode. */ + f = (f & ~O_ACCMODE) | acc; + + tape = open(devp, f, m); if (tape == -1) goto ioerror; + (void)strlcpy(lastdevice, devp, sizeof(lastdevice)); goto respond; case 'C': @@ -225,3 +320,13 @@ error(int num) (void) snprintf(resp, sizeof (resp), "E%d\n%s\n", num, strerror(num)); (void) write(STDOUT_FILENO, resp, strlen(resp)); } + +__dead void +usage(void) +{ + extern char *__progname; + + (void)fprintf(stderr, "usage: %s [-r | -w] [-d directory]\n", + __progname); + exit(1); +} |