aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2018-11-04 17:56:16 +0000
committerConrad Meyer <cem@FreeBSD.org>2018-11-04 17:56:16 +0000
commitd83db3fb6a3c2ffeaafd5e688a2653f39a7be9d9 (patch)
tree8804013c87f78b80afb64fedd4f16724a5f8d36e /bin
parent5a453d5f5b8cff5a58b7c65df3822a2a6094f7b4 (diff)
downloadsrc-d83db3fb6a3c2ffeaafd5e688a2653f39a7be9d9.tar.gz
src-d83db3fb6a3c2ffeaafd5e688a2653f39a7be9d9.zip
Drop ed(1) "crypto"
You should not be using DES. You should not have been using DES for the past 30 years. The ed DES-CBC scheme lacked several desirable properties of a sealed document system, even ignoring DES itself. In particular, it did not provide the "integrity" cryptographic property (detection of tampering), and it treated ASCII passwords as 64-bit keys (instead of using a KDF like scrypt or PBKDF2). Some general approaches ed(1) users might consider to replace the removed DES mode: 1. Full disk encryption with something like AES-XTS. This is easy to conceptualize, design, and implement, and it provides confidentiality for data at rest. Like CBC, it lacks tampering protection. Examples include GELI, LUKS, FileVault2. 2. Encrypted overlay ("stackable") filesystems (EncFS, PEFS?, CryptoFS, others). 3. Native encryption at the filesystem layer. Ext4/F2FS, ZFS, APFS, and NTFS all have some flavor of this. 4. Storing your files unencrypted. It's not like DES was doing you much good. If you have DES-CBC scrambled files produced by ed(1) prior to this change, you may decrypt them with: openssl des-cbc -d -iv 0 -K <key in hex> -in <inputfile> -out <plaintext> Reviewed by: allanjude, bapt, emaste Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D17829
Notes
Notes: svn path=/head/; revision=340132
Diffstat (limited to 'bin')
-rw-r--r--bin/ed/Makefile7
-rw-r--r--bin/ed/POSIX15
-rw-r--r--bin/ed/README1
-rw-r--r--bin/ed/cbc.c395
-rw-r--r--bin/ed/ed.117
-rw-r--r--bin/ed/ed.h12
-rw-r--r--bin/ed/io.c16
-rw-r--r--bin/ed/main.c14
8 files changed, 10 insertions, 467 deletions
diff --git a/bin/ed/Makefile b/bin/ed/Makefile
index 40e06134e87d..1d4b7685c025 100644
--- a/bin/ed/Makefile
+++ b/bin/ed/Makefile
@@ -4,13 +4,8 @@
PACKAGE=runtime
PROG= ed
-SRCS= buf.c cbc.c glbl.c io.c main.c re.c sub.c undo.c
+SRCS= buf.c glbl.c io.c main.c re.c sub.c undo.c
LINKS= ${BINDIR}/ed ${BINDIR}/red
MLINKS= ed.1 red.1
-.if ${MK_OPENSSL} != "no" && ${MK_ED_CRYPTO} != "no"
-CFLAGS+=-DDES
-LIBADD= crypto
-.endif
-
.include <bsd.prog.mk>
diff --git a/bin/ed/POSIX b/bin/ed/POSIX
index dab1a2bc90f3..53d6b5328ca5 100644
--- a/bin/ed/POSIX
+++ b/bin/ed/POSIX
@@ -25,29 +25,20 @@ EXTENSIONS
iv) `z' for scrolling through the buffer, and
v) BSD line addressing syntax (i.e., `^' and `%') is recognized.
-2) If crypt(3) is available, files can be read and written using DES
- encryption. The `x' command prompts the user to enter a key used for
- encrypting/ decrypting subsequent reads and writes. If only a newline
- is entered as the key, then encryption is disabled. Otherwise, a key
- is read in the same manner as a password entry. The key remains in
- effect until encryption is disabled. For more information on the
- encryption algorithm, see the bdes(1) man page. Encryption/decryption
- should be fully compatible with SunOS des(1).
-
-3) The POSIX interactive global commands `G' and `V' are extended to
+2) The POSIX interactive global commands `G' and `V' are extended to
support multiple commands, including `a', `i' and `c'. The command
format is the same as for the global commands `g' and `v', i.e., one
command per line with each line, except for the last, ending in a
backslash (\).
-4) An extension to the POSIX file commands `E', `e', `r', `W' and `w' is
+3) An extension to the POSIX file commands `E', `e', `r', `W' and `w' is
that <file> arguments are processed for backslash escapes, i.e., any
character preceded by a backslash is interpreted literally. If the
first unescaped character of a <file> argument is a bang (!), then the
rest of the line is interpreted as a shell command, and no escape
processing is performed by ed.
-5) For SunOS ed(1) compatibility, ed runs in restricted mode if invoked
+4) For SunOS ed(1) compatibility, ed runs in restricted mode if invoked
as red. This limits editing of files in the local directory only and
prohibits shell commands.
diff --git a/bin/ed/README b/bin/ed/README
index 478e7af07c70..da11f9b0f32a 100644
--- a/bin/ed/README
+++ b/bin/ed/README
@@ -9,7 +9,6 @@ compile with little trouble. Otherwise, the macros SPL1() and SPL0()
should be redefined to disable interrupts.
The following compiler directives are recognized:
-DES - to add encryption support (requires crypt(3))
NO_REALLOC_NULL - if realloc(3) does not accept a NULL pointer
BACKWARDS - for backwards compatibility
NEED_INSQUE - if insque(3) is missing
diff --git a/bin/ed/cbc.c b/bin/ed/cbc.c
deleted file mode 100644
index 7e1d03c3c634..000000000000
--- a/bin/ed/cbc.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* cbc.c: This file contains the encryption routines for the ed line editor */
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 1993 The Regents of the University of California.
- * All rights reserved.
- *
- * Copyright (c) 1993 Andrew Moore, Talke Studio.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <errno.h>
-#include <pwd.h>
-#ifdef DES
-#include <time.h>
-#include <openssl/des.h>
-#define ED_DES_INCLUDES
-#endif
-
-#include "ed.h"
-
-
-/*
- * BSD and System V systems offer special library calls that do
- * block move_liness and fills, so if possible we take advantage of them
- */
-#define MEMCPY(dest,src,len) memcpy((dest),(src),(len))
-#define MEMZERO(dest,len) memset((dest), 0, (len))
-
-/* Hide the calls to the primitive encryption routines. */
-#define DES_XFORM(buf) \
- DES_ecb_encrypt(buf, buf, &schedule, \
- inverse ? DES_DECRYPT : DES_ENCRYPT);
-
-/*
- * read/write - no error checking
- */
-#define READ(buf, n, fp) fread(buf, sizeof(char), n, fp)
-#define WRITE(buf, n, fp) fwrite(buf, sizeof(char), n, fp)
-
-/*
- * global variables and related macros
- */
-
-#ifdef DES
-static DES_cblock ivec; /* initialization vector */
-static DES_cblock pvec; /* padding vector */
-
-static char bits[] = { /* used to extract bits from a char */
- '\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
-};
-
-static int pflag; /* 1 to preserve parity bits */
-
-static DES_key_schedule schedule; /* expanded DES key */
-
-static unsigned char des_buf[8];/* shared buffer for get_des_char/put_des_char */
-static int des_ct = 0; /* count for get_des_char/put_des_char */
-static int des_n = 0; /* index for put_des_char/get_des_char */
-#endif
-
-/* init_des_cipher: initialize DES */
-void
-init_des_cipher(void)
-{
-#ifdef DES
- des_ct = des_n = 0;
-
- /* initialize the initialization vector */
- MEMZERO(ivec, 8);
-
- /* initialize the padding vector */
- arc4random_buf(pvec, sizeof(pvec));
-#endif
-}
-
-
-/* get_des_char: return next char in an encrypted file */
-int
-get_des_char(FILE *fp)
-{
-#ifdef DES
- if (des_n >= des_ct) {
- des_n = 0;
- des_ct = cbc_decode(des_buf, fp);
- }
- return (des_ct > 0) ? des_buf[des_n++] : EOF;
-#else
- return (getc(fp));
-#endif
-}
-
-
-/* put_des_char: write a char to an encrypted file; return char written */
-int
-put_des_char(int c, FILE *fp)
-{
-#ifdef DES
- if (des_n == sizeof des_buf) {
- des_ct = cbc_encode(des_buf, des_n, fp);
- des_n = 0;
- }
- return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF;
-#else
- return (fputc(c, fp));
-#endif
-}
-
-
-/* flush_des_file: flush an encrypted file's output; return status */
-int
-flush_des_file(FILE *fp)
-{
-#ifdef DES
- if (des_n == sizeof des_buf) {
- des_ct = cbc_encode(des_buf, des_n, fp);
- des_n = 0;
- }
- return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF;
-#else
- return (fflush(fp));
-#endif
-}
-
-#ifdef DES
-/*
- * get keyword from tty or stdin
- */
-int
-get_keyword(void)
-{
- char *p; /* used to obtain the key */
- DES_cblock msgbuf; /* I/O buffer */
-
- /*
- * get the key
- */
- if ((p = getpass("Enter key: ")) != NULL && *p != '\0') {
-
- /*
- * copy it, nul-padded, into the key area
- */
- expand_des_key(msgbuf, p);
- MEMZERO(p, _PASSWORD_LEN);
- set_des_key(&msgbuf);
- MEMZERO(msgbuf, sizeof msgbuf);
- return 1;
- }
- return 0;
-}
-
-
-/*
- * print a warning message and, possibly, terminate
- */
-void
-des_error(const char *s)
-{
- errmsg = s ? s : strerror(errno);
-}
-
-/*
- * map a hex character to an integer
- */
-int
-hex_to_binary(int c, int radix)
-{
- switch(c) {
- case '0': return(0x0);
- case '1': return(0x1);
- case '2': return(radix > 2 ? 0x2 : -1);
- case '3': return(radix > 3 ? 0x3 : -1);
- case '4': return(radix > 4 ? 0x4 : -1);
- case '5': return(radix > 5 ? 0x5 : -1);
- case '6': return(radix > 6 ? 0x6 : -1);
- case '7': return(radix > 7 ? 0x7 : -1);
- case '8': return(radix > 8 ? 0x8 : -1);
- case '9': return(radix > 9 ? 0x9 : -1);
- case 'A': case 'a': return(radix > 10 ? 0xa : -1);
- case 'B': case 'b': return(radix > 11 ? 0xb : -1);
- case 'C': case 'c': return(radix > 12 ? 0xc : -1);
- case 'D': case 'd': return(radix > 13 ? 0xd : -1);
- case 'E': case 'e': return(radix > 14 ? 0xe : -1);
- case 'F': case 'f': return(radix > 15 ? 0xf : -1);
- }
- /*
- * invalid character
- */
- return(-1);
-}
-
-/*
- * convert the key to a bit pattern
- * obuf bit pattern
- * kbuf the key itself
- */
-void
-expand_des_key(char *obuf, char *kbuf)
-{
- int i, j; /* counter in a for loop */
- int nbuf[64]; /* used for hex/key translation */
-
- /*
- * leading '0x' or '0X' == hex key
- */
- if (kbuf[0] == '0' && (kbuf[1] == 'x' || kbuf[1] == 'X')) {
- kbuf = &kbuf[2];
- /*
- * now translate it, bombing on any illegal hex digit
- */
- for (i = 0; i < 16 && kbuf[i]; i++)
- if ((nbuf[i] = hex_to_binary((int) kbuf[i], 16)) == -1)
- des_error("bad hex digit in key");
- while (i < 16)
- nbuf[i++] = 0;
- for (i = 0; i < 8; i++)
- obuf[i] =
- ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
- /* preserve parity bits */
- pflag = 1;
- return;
- }
- /*
- * leading '0b' or '0B' == binary key
- */
- if (kbuf[0] == '0' && (kbuf[1] == 'b' || kbuf[1] == 'B')) {
- kbuf = &kbuf[2];
- /*
- * now translate it, bombing on any illegal binary digit
- */
- for (i = 0; i < 16 && kbuf[i]; i++)
- if ((nbuf[i] = hex_to_binary((int) kbuf[i], 2)) == -1)
- des_error("bad binary digit in key");
- while (i < 64)
- nbuf[i++] = 0;
- for (i = 0; i < 8; i++)
- for (j = 0; j < 8; j++)
- obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
- /* preserve parity bits */
- pflag = 1;
- return;
- }
- /*
- * no special leader -- ASCII
- */
- (void)strncpy(obuf, kbuf, 8);
-}
-
-/*****************
- * DES FUNCTIONS *
- *****************/
-/*
- * This sets the DES key and (if you're using the deszip version)
- * the direction of the transformation. This uses the Sun
- * to map the 64-bit key onto the 56 bits that the key schedule
- * generation routines use: the old way, which just uses the user-
- * supplied 64 bits as is, and the new way, which resets the parity
- * bit to be the same as the low-order bit in each character. The
- * new way generates a greater variety of key schedules, since many
- * systems set the parity (high) bit of each character to 0, and the
- * DES ignores the low order bit of each character.
- */
-void
-set_des_key(DES_cblock *buf) /* key block */
-{
- int i, j; /* counter in a for loop */
- int par; /* parity counter */
-
- /*
- * if the parity is not preserved, flip it
- */
- if (!pflag) {
- for (i = 0; i < 8; i++) {
- par = 0;
- for (j = 1; j < 8; j++)
- if ((bits[j] & (*buf)[i]) != 0)
- par++;
- if ((par & 0x01) == 0x01)
- (*buf)[i] &= 0x7f;
- else
- (*buf)[i] = ((*buf)[i] & 0x7f) | 0x80;
- }
- }
-
- DES_set_odd_parity(buf);
- DES_set_key(buf, &schedule);
-}
-
-
-/*
- * This encrypts using the Cipher Block Chaining mode of DES
- */
-int
-cbc_encode(unsigned char *msgbuf, int n, FILE *fp)
-{
- int inverse = 0; /* 0 to encrypt, 1 to decrypt */
-
- /*
- * do the transformation
- */
- if (n == 8) {
- for (n = 0; n < 8; n++)
- msgbuf[n] ^= ivec[n];
- DES_XFORM((DES_cblock *)msgbuf);
- MEMCPY(ivec, msgbuf, 8);
- return WRITE(msgbuf, 8, fp);
- }
- /*
- * at EOF or last block -- in either case, the last byte contains
- * the character representation of the number of bytes in it
- */
-/*
- MEMZERO(msgbuf + n, 8 - n);
-*/
- /*
- * Pad the last block randomly
- */
- (void)MEMCPY(msgbuf + n, pvec, 8 - n);
- msgbuf[7] = n;
- for (n = 0; n < 8; n++)
- msgbuf[n] ^= ivec[n];
- DES_XFORM((DES_cblock *)msgbuf);
- return WRITE(msgbuf, 8, fp);
-}
-
-/*
- * This decrypts using the Cipher Block Chaining mode of DES
- * msgbuf I/O buffer
- * fp input file descriptor
- */
-int
-cbc_decode(unsigned char *msgbuf, FILE *fp)
-{
- DES_cblock tbuf; /* temp buffer for initialization vector */
- int n; /* number of bytes actually read */
- int c; /* used to test for EOF */
- int inverse = 1; /* 0 to encrypt, 1 to decrypt */
-
- if ((n = READ(msgbuf, 8, fp)) == 8) {
- /*
- * do the transformation
- */
- MEMCPY(tbuf, msgbuf, 8);
- DES_XFORM((DES_cblock *)msgbuf);
- for (c = 0; c < 8; c++)
- msgbuf[c] ^= ivec[c];
- MEMCPY(ivec, tbuf, 8);
- /*
- * if the last one, handle it specially
- */
- if ((c = fgetc(fp)) == EOF) {
- n = msgbuf[7];
- if (n < 0 || n > 7) {
- des_error("decryption failed (block corrupted)");
- return EOF;
- }
- } else
- (void)ungetc(c, fp);
- return n;
- }
- if (n > 0)
- des_error("decryption failed (incomplete block)");
- else if (n < 0)
- des_error("cannot read file");
- return EOF;
-}
-#endif /* DES */
diff --git a/bin/ed/ed.1 b/bin/ed/ed.1
index 6876c5cfb3f1..0cdd1b9c3e3c 100644
--- a/bin/ed/ed.1
+++ b/bin/ed/ed.1
@@ -1,5 +1,5 @@
.\" $FreeBSD$
-.Dd February 5, 2017
+.Dd November 3, 2018
.Dt ED 1
.Os
.Sh NAME
@@ -9,12 +9,12 @@
.Sh SYNOPSIS
.Nm
.Op Fl
-.Op Fl sx
+.Op Fl s
.Op Fl p Ar string
.Op Ar file
.Nm red
.Op Fl
-.Op Fl sx
+.Op Fl s
.Op Fl p Ar string
.Op Ar file
.Sh DESCRIPTION
@@ -141,11 +141,6 @@ Suppress diagnostics.
This should be used if
.Nm Ns 's
standard input is from a script.
-.It Fl x
-Prompt for an encryption key to be used in subsequent reads and writes
-(see the
-.Em x
-command).
.It Fl p Ar string
Specify a command prompt.
This may be toggled on and off with the
@@ -865,12 +860,6 @@ This is similar to the
.Em w
command, expect that the previous contents of file is not clobbered.
The current address is unchanged.
-.It x
-Prompt for an encryption key which is used in subsequent reads and
-writes.
-If a newline alone is entered as the key, then encryption is
-turned off.
-Otherwise, echoing is disabled while a key is read.
.It Pf (.+1)z n
Scroll
.Ar n
diff --git a/bin/ed/ed.h b/bin/ed/ed.h
index 597e3464e7fa..4dcf5eb36f37 100644
--- a/bin/ed/ed.h
+++ b/bin/ed/ed.h
@@ -175,17 +175,6 @@ if ((i) > (n)) { \
/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
-#ifdef ED_DES_INCLUDES
-void des_error(const char *);
-void expand_des_key(char *, char *);
-void set_des_key(DES_cblock *);
-#endif
-
-/* Other DES support stuff */
-void init_des_cipher(void);
-int flush_des_file(FILE *);
-int get_des_char(FILE *);
-int put_des_char(int, FILE *);
/* Local Function Declarations */
void add_line_node(line_t *);
@@ -280,6 +269,5 @@ extern long u_current_addr;
extern long rows;
extern int cols;
extern int newline_added;
-extern int des;
extern int scripted;
extern int patlock;
diff --git a/bin/ed/io.c b/bin/ed/io.c
index 1907e7a95472..697e0a4c7ab5 100644
--- a/bin/ed/io.c
+++ b/bin/ed/io.c
@@ -76,8 +76,6 @@ read_stream(FILE *fp, long n)
int len;
isbinary = newline_added = 0;
- if (des)
- init_des_cipher();
for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
SPL1();
if (put_sbuf_line(sbuf) == NULL) {
@@ -106,8 +104,6 @@ read_stream(FILE *fp, long n)
newline_added = 1;
newline_added = appended ? newline_added : o_newline_added;
isbinary = isbinary | o_isbinary;
- if (des)
- size += 8 - size % 8; /* adjust DES size */
return size;
}
@@ -119,8 +115,8 @@ get_stream_line(FILE *fp)
int c;
int i = 0;
- while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
- !ferror(fp))) && c != '\n') {
+ while (((c = getc(fp)) != EOF || (!feof(fp) && !ferror(fp))) &&
+ c != '\n') {
REALLOC(sbuf, sbufsz, i + 1, ERR);
if (!(sbuf[i++] = c))
isbinary = 1;
@@ -180,8 +176,6 @@ write_stream(FILE *fp, long n, long m)
char *s;
int len;
- if (des)
- init_des_cipher();
for (; n && n <= m; n++, lp = lp->q_forw) {
if ((s = get_sbuf_line(lp)) == NULL)
return ERR;
@@ -192,10 +186,6 @@ write_stream(FILE *fp, long n, long m)
return ERR;
size += len;
}
- if (des) {
- flush_des_file(fp); /* flush buffer */
- size += 8 - size % 8; /* adjust DES size */
- }
return size;
}
@@ -205,7 +195,7 @@ int
put_stream_line(FILE *fp, const char *s, int len)
{
while (len--)
- if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
+ if (fputc(*s++, fp) < 0) {
fprintf(stderr, "%s\n", strerror(errno));
errmsg = "cannot write file";
return ERR;
diff --git a/bin/ed/main.c b/bin/ed/main.c
index babffa813088..82ab6d195038 100644
--- a/bin/ed/main.c
+++ b/bin/ed/main.c
@@ -47,10 +47,6 @@ __FBSDID("$FreeBSD$");
* The buffering algorithm is attributed to Rodney Ruddock of
* the University of Guelph, Guelph, Ontario.
*
- * The cbc.c encryption code is adapted from
- * the bdes program by Matt Bishop of Dartmouth College,
- * Hanover, NH.
- *
*/
#include <sys/types.h>
@@ -81,7 +77,6 @@ int ibufsz; /* ed command-line buffer size */
char *ibufp; /* pointer to ed command-line buffer */
/* global flags */
-int des = 0; /* if set, use crypt(3) for i/o */
static int garrulous = 0; /* if set, print all error messages */
int isbinary; /* if set, buffer contains ASCII NULs */
int isglobal; /* if set, doing a global command */
@@ -121,11 +116,7 @@ top:
scripted = 1;
break;
case 'x': /* use crypt */
-#ifdef DES
- des = get_keyword();
-#else
fprintf(stderr, "crypt unavailable\n?\n");
-#endif
break;
default:
@@ -821,13 +812,8 @@ exec_command(void)
return ERR;
}
GET_COMMAND_SUFFIX();
-#ifdef DES
- des = get_keyword();
- break;
-#else
errmsg = "crypt unavailable";
return ERR;
-#endif
case 'z':
#ifdef BACKWARDS
if (check_addr_range(first_addr = 1, current_addr + 1) < 0)