1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-03 06:45:37 -08:00

Add a set of flags to rmt(8) to make it run in a restricted mode,

designed to work with rdump(8) to remote disk.

  -d <directory>   confines rmt to operate within a single directory.
  -r               enforces read-only mode.
  -w               enforces write-only mode.

This is quite usable with public ssh key setup, e.g. having the following in .ssh/authorized/keys:

  command="/etc/rmt -rd /backups/machine.example.conf",no-agent-forwarding,... ssh-rsa AAAAB3...

ok semarie@
This commit is contained in:
halex 2015-09-20 10:05:48 +00:00
parent e9abc84819
commit 71c04358ef
2 changed files with 138 additions and 13 deletions

View File

@ -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

View File

@ -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);
}