Added a restricted mode in the form of a new command: red
This commit is contained in:
parent
9030436006
commit
f7f6e6ffd5
@ -1,6 +1,8 @@
|
||||
PROG= ed
|
||||
CFLAGS=-g -DVI_BANG -DDES -DGNU_REGEX
|
||||
CFLAGS+=-DVI_BANG -DDES -DGNU_REGEX
|
||||
SRCS= ed.c re.c buf.c cbc.c
|
||||
LDADD= -lgnuregex -lcrypt
|
||||
LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||
MLINKS= ed.1 red.1
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -40,3 +40,7 @@ The vi editor's bang command syntax is supported, i.e.,
|
||||
If ed is invoked with a name argument prefixed by a bang, then the
|
||||
remainder of the argument is interpreted as a shell command. To invoke
|
||||
ed on a file whose name starts with bang, prefix the name with a backslash.
|
||||
|
||||
A restricted version of ed is supported when invoked as red. This limits
|
||||
editing of files in the local directory only and prohibits !<shell-cmd>
|
||||
commands.
|
||||
|
118
bin/ed/ed.1
118
bin/ed/ed.1
@ -1,15 +1,22 @@
|
||||
.TH ED 1 386BSD
|
||||
.TH ED 1 "21 May 1993"
|
||||
.SH NAME
|
||||
ed \- text editor
|
||||
ed, red \- text editor
|
||||
.SH SYNOPSIS
|
||||
ed [-] [-sx] [-p \fIstring\fR] [\fIfile\fR]
|
||||
.LP
|
||||
red [-] [-sx] [-p \fIstring\fR] [\fIfile\fR]
|
||||
.SH DESCRIPTION
|
||||
.B ed
|
||||
is a line-oriented text editor.
|
||||
It is used to create, display, modify and otherwise manipulate text
|
||||
files.
|
||||
.B red
|
||||
is a restricted
|
||||
.BR ed :
|
||||
it can edit files only in the current
|
||||
directory and cannot execute shell commands.
|
||||
|
||||
If invoked with the
|
||||
If invoked with a
|
||||
.I file
|
||||
argument, then a copy of
|
||||
.I file
|
||||
@ -35,7 +42,7 @@ executed to manipulate the contents of the editor buffer.
|
||||
A typical command might look like:
|
||||
.sp
|
||||
.RS
|
||||
,s/\fIold\fR/\fInew\fR/gp
|
||||
,s/\fIold\fR/\fInew\fR/g
|
||||
.RE
|
||||
.sp
|
||||
which replaces all occurences of the string
|
||||
@ -55,7 +62,10 @@ enters input mode. This is the primary means
|
||||
of adding text to a file.
|
||||
In this mode, no commands are available;
|
||||
instead, the standard input is written
|
||||
directly to the editor buffer. Input mode is terminated by
|
||||
directly to the editor buffer. Lines must end with a
|
||||
.IR newline
|
||||
character (entered by hitting the RETURN key).
|
||||
Input mode is terminated by
|
||||
entering a single period (\fI.\fR) on a line.
|
||||
|
||||
All
|
||||
@ -106,18 +116,21 @@ Specifies a command prompt. This may be toggled on and off with the
|
||||
command.
|
||||
|
||||
.TP 8
|
||||
name
|
||||
.I file
|
||||
Specifies the name of a file to read. If
|
||||
.I name
|
||||
.I file
|
||||
is prefixed with a
|
||||
bang (!), then it is interpreted as a shell command. In this case,
|
||||
what is read is
|
||||
the standard output of
|
||||
.I name
|
||||
.I file
|
||||
executed via
|
||||
.IR sh (1).
|
||||
To read a file whose name begins with a bang, prefix the
|
||||
name with a backslash (\\).
|
||||
The default filename is set to
|
||||
.I file
|
||||
only if it is not prefixed with a bang.
|
||||
|
||||
.SS LINE ADDRESSING
|
||||
An address represents the number of line in the buffer.
|
||||
@ -144,7 +157,7 @@ relative to the current address.
|
||||
|
||||
One exception to the rule that addresses represent line numbers is the
|
||||
address
|
||||
.I `0'
|
||||
.I 0
|
||||
(zero).
|
||||
This means "before the first line,"
|
||||
and is legal wherever it makes sense.
|
||||
@ -317,6 +330,16 @@ in
|
||||
it must be the first character.
|
||||
A range of characters may be specified by separating the end characters
|
||||
of the range with a `-', e.g., `a-z' specifies the lower case characters.
|
||||
The following literal expressions can also be used in
|
||||
.I char-class
|
||||
to specify sets of characters:
|
||||
|
||||
\ \ [:alnum:]\ \ [:cntrl:]\ \ [:lower:]\ \ [:space:]
|
||||
.PD 0
|
||||
\ \ [:alpha:]\ \ [:digit:]\ \ [:print:]\ \ [:upper:]
|
||||
.PD 0
|
||||
\ \ [:blank:]\ \ [:graph:]\ \ [:punct:]\ \ [:xdigit:]
|
||||
|
||||
If `-' appears as the first or last
|
||||
character of
|
||||
.IR char-class ,
|
||||
@ -325,6 +348,26 @@ All other characters in
|
||||
.I char-class
|
||||
match themselves.
|
||||
|
||||
Patterns in
|
||||
.I char-class
|
||||
of the form:
|
||||
|
||||
\ \ [.\fIcol-elm\fR.] or,
|
||||
.PD 0
|
||||
\ \ [=\fIcol-elm\fR=]
|
||||
|
||||
where
|
||||
.I col-elm
|
||||
is a
|
||||
.I collating element
|
||||
are interpreted according to
|
||||
.IR locale (5)
|
||||
(not currently supported).
|
||||
See
|
||||
.IR regex (3)
|
||||
for an explanation of these constructs.
|
||||
|
||||
|
||||
.TP 8
|
||||
[^\fIchar-class\fR]
|
||||
Matches any single character, other than newline, not in
|
||||
@ -399,13 +442,19 @@ If the comma is also omitted, then it matches exactly
|
||||
.I n
|
||||
times.
|
||||
|
||||
.LP
|
||||
Additional regular expression operators may be defined depending on the
|
||||
particular
|
||||
.IR regex (3)
|
||||
implementation.
|
||||
|
||||
.SS COMMANDS
|
||||
All
|
||||
.B ed
|
||||
commands are single characters, though some require additonal parameters.
|
||||
If a command's paramters extend over several lines, then
|
||||
If a command's parameters extend over several lines, then
|
||||
each line except for the last
|
||||
must end in a backslash (\\).
|
||||
must be terminated with a backslash (\\).
|
||||
|
||||
In general, at most one command is allowed per line.
|
||||
However, most commands accept a print suffix, which is any of
|
||||
@ -461,9 +510,8 @@ The current address is set to the last line read.
|
||||
.TP 8
|
||||
.RI e \ !command
|
||||
Edits the standard output of
|
||||
.I command
|
||||
executed via
|
||||
.IR sh (1).
|
||||
.I !command
|
||||
executed as described below.
|
||||
The default filename is unchanged.
|
||||
Any lines in the buffer are deleted before the output of
|
||||
.I command
|
||||
@ -570,7 +618,7 @@ The current address is set to the resultant line.
|
||||
Marks a line with a lower case letter
|
||||
.IR lc .
|
||||
The line can then be addressed as
|
||||
.I `'lc'
|
||||
.I 'lc
|
||||
(i.e., a single quote followed by
|
||||
.I lc
|
||||
) in subsequent commands. The mark is not cleared until the line is
|
||||
@ -586,7 +634,7 @@ printed.
|
||||
(.,.)m(.)
|
||||
Moves lines in the buffer. The addressed lines are moved to after the
|
||||
right-hand destination address, which may be the address
|
||||
.IR `0'
|
||||
.IR 0
|
||||
(zero).
|
||||
The current address is set to the
|
||||
last line moved.
|
||||
@ -636,9 +684,8 @@ The current address is set to the last line read.
|
||||
.TP 8
|
||||
.RI ($)r \ !command
|
||||
Reads the standard output of
|
||||
.I command
|
||||
executed via
|
||||
.IR sh (1)
|
||||
.I !command
|
||||
executed as described below.
|
||||
to after the addressed line.
|
||||
The default filename is unchanged.
|
||||
The current address is set to the last line read.
|
||||
@ -663,6 +710,16 @@ is a postive number, causes only the
|
||||
match to be replaced.
|
||||
The current address is set the last line affected.
|
||||
|
||||
.I re
|
||||
and
|
||||
.I replacement
|
||||
may be delimited by any character other than space and newline.
|
||||
If one or two of the last delimiters is omitted, then the last line
|
||||
affected is printed as though the print suffix
|
||||
.I `p'
|
||||
were specified.
|
||||
|
||||
|
||||
An unescaped `&' in
|
||||
.I replacement
|
||||
is replaced by the currently matched text.
|
||||
@ -682,15 +739,6 @@ Newlines may be included in
|
||||
.I replacement
|
||||
if they are escaped with a backslash (\\).
|
||||
|
||||
.I re
|
||||
and
|
||||
.I replacement
|
||||
may be delimited by any character other than space and newline.
|
||||
If one or two of the last delimiters is omitted, then the last line
|
||||
affected is printed as though the print suffix
|
||||
.I `p'
|
||||
were specified.
|
||||
|
||||
.TP 8
|
||||
.RI (.,.)s [rgp]*
|
||||
Repeats the last substitution.
|
||||
@ -719,7 +767,7 @@ The current address is set to the last line affected.
|
||||
(.,.)t(.)
|
||||
Copies (i.e., transfers) the addressed lines to after the right-hand
|
||||
destination address, which may be the address
|
||||
.IR `0'
|
||||
.IR 0
|
||||
(zero).
|
||||
The current address is set to the last line
|
||||
copied.
|
||||
@ -780,9 +828,8 @@ command.
|
||||
.TP 8
|
||||
.RI (1,$)w \ !command
|
||||
Writes the addressed lines to the standard input of
|
||||
.I command
|
||||
executed via
|
||||
.IR sh (1).
|
||||
.I !command
|
||||
executed as described below.
|
||||
The default filename and current address are unchanged.
|
||||
|
||||
.TP 8
|
||||
@ -835,9 +882,8 @@ The current line is unchanged.
|
||||
.TP 8
|
||||
.RI (.,.)! command
|
||||
Replaces the addressed lines with the output of
|
||||
.I command
|
||||
executed via
|
||||
.IR sh (1).
|
||||
.I !command
|
||||
as described above.
|
||||
The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
@ -853,7 +899,7 @@ that line.
|
||||
.TP 20
|
||||
/tmp/ed.*
|
||||
Buffer file
|
||||
|
||||
.PD 0
|
||||
.TP 20
|
||||
\fR./ed.hup\fR, $HOME/ed.hup
|
||||
First and second files to which
|
||||
|
57
bin/ed/ed.c
57
bin/ed/ed.c
@ -114,6 +114,7 @@ int des = 0; /* if set, use crypt(3) for i/o */
|
||||
int mutex = 0; /* if set, signals set "sigflags" */
|
||||
int sigflags = 0; /* if set, signals received while mutex set */
|
||||
int sigactive = 0; /* if set, signal handlers are enabled */
|
||||
int red = 0; /* if set, restrict shell/directory access */
|
||||
|
||||
char dfn[MAXFNAME + 1] = ""; /* default filename */
|
||||
long curln; /* current address */
|
||||
@ -136,6 +137,7 @@ main(argc, argv)
|
||||
int c, n;
|
||||
long status = 0;
|
||||
|
||||
red = (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r';
|
||||
while ((c = getopt(argc, argv, "p:sx")) != EOF)
|
||||
switch(c) {
|
||||
case 'p': /* set prompt */
|
||||
@ -182,11 +184,17 @@ main(argc, argv)
|
||||
} else {
|
||||
init_buf();
|
||||
sigactive = 1; /* enable signal handlers */
|
||||
if (argc) {
|
||||
if (**argv != '!')
|
||||
strcpy(dfn, *argv);
|
||||
if (argc && **argv && ckfn(*argv)) {
|
||||
if (doread(0, *argv) < 0 && !isatty(0))
|
||||
quit(2);
|
||||
else if (**argv != '!')
|
||||
strcpy(dfn, *argv);
|
||||
} else if (argc) {
|
||||
fputs("?\n", stderr);
|
||||
if (**argv == '\0')
|
||||
sprintf(errmsg, "invalid filename");
|
||||
if (!isatty(0))
|
||||
quit(2);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
@ -638,7 +646,7 @@ docmd(glob)
|
||||
}
|
||||
VRFYCMD();
|
||||
if (*fnp) strcpy(dfn, fnp);
|
||||
printf("%s\n", dfn);
|
||||
printf("%s\n", esctos(dfn));
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
@ -1065,9 +1073,10 @@ getfn()
|
||||
for (n = 0; *ibufp != '\n';)
|
||||
file[n++] = *ibufp++;
|
||||
file[n] = '\0';
|
||||
return file;
|
||||
return ckfn(file);
|
||||
}
|
||||
|
||||
|
||||
/* getrhs: extract substitution template from the command buffer */
|
||||
getrhs(glob)
|
||||
int glob;
|
||||
@ -1142,11 +1151,14 @@ getshcmd()
|
||||
static char *buf = NULL;
|
||||
static int n = 0;
|
||||
|
||||
char *ip;
|
||||
char *s; /* substitution char pointer */
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
if ((ip = ibufp = getcmdv(&j, 1)) == NULL)
|
||||
if (red) {
|
||||
sprintf(errmsg, "shell access restricted");
|
||||
return ERR;
|
||||
} else if ((s = ibufp = getcmdv(&j, 1)) == NULL)
|
||||
return ERR;
|
||||
CKBUF(buf, n, j + 1, ERR);
|
||||
buf[i++] = '!'; /* prefix command w/ bang */
|
||||
@ -1159,7 +1171,7 @@ getshcmd()
|
||||
buf[i++] = *ibufp++;
|
||||
break;
|
||||
case '!':
|
||||
if (ip != ibufp) {
|
||||
if (s != ibufp) {
|
||||
CKBUF(buf, n, i + 1, ERR);
|
||||
buf[i++] = *ibufp++;
|
||||
}
|
||||
@ -1173,9 +1185,9 @@ getshcmd()
|
||||
return ERR;
|
||||
} else {
|
||||
CKBUF(buf, n, i + shcmdi, ERR);
|
||||
for (ip = shcmd + 1; ip < shcmd + shcmdi;)
|
||||
buf[i++] = *ip++;
|
||||
ip = ibufp++;
|
||||
for (s = shcmd + 1; s < shcmd + shcmdi;)
|
||||
buf[i++] = *s++;
|
||||
s = ibufp++;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
@ -1183,17 +1195,17 @@ getshcmd()
|
||||
sprintf(errmsg, "no current filename");
|
||||
return ERR;
|
||||
}
|
||||
j = strlen(dfn);
|
||||
j = strlen(s = esctos(dfn));
|
||||
CKBUF(buf, n, i + j, ERR);
|
||||
for (ip = dfn; ip < dfn + j;)
|
||||
buf[i++] = *ip++;
|
||||
ip = ibufp++;
|
||||
while (j--)
|
||||
buf[i++] = *s++;
|
||||
s = ibufp++;
|
||||
break;
|
||||
}
|
||||
CKBUF(shcmd, shcmdsz, i + 1, ERR);
|
||||
memcpy(shcmd, buf, i);
|
||||
shcmd[shcmdi = i] = '\0';
|
||||
return *ip == '!' || *ip == '%';
|
||||
return *s == '!' || *s == '%';
|
||||
}
|
||||
|
||||
|
||||
@ -2182,3 +2194,16 @@ init_buf()
|
||||
for (i = 0; i < 256; i++)
|
||||
ctab[i] = i;
|
||||
}
|
||||
|
||||
|
||||
/* ckfn: return a legal filename */
|
||||
char *
|
||||
ckfn(s)
|
||||
char *s;
|
||||
{
|
||||
if (red && (*s == '!' || !strcmp(s, "..") || strchr(s, '/'))) {
|
||||
sprintf(errmsg, "shell access restricted");
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ if ((i) > (n)) { \
|
||||
int append __P((long, int));
|
||||
int cbcdec __P((char *, FILE *));
|
||||
int cbcenc __P((char *, int, FILE *));
|
||||
char *ckfn __P((char *));
|
||||
int ckglob __P((void));
|
||||
int ckrange __P((long, long));
|
||||
int desflush __P((FILE *));
|
||||
|
Loading…
Reference in New Issue
Block a user