mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
tools: Extend gpg-check-pattern.
* tools/gpg-check-pattern.c: Major rewrite. -- Signed-off-by: Werner Koch <wk@gnupg.org> Backported-from-master: 73c03e02322880c740310207dd2151cfd843792e Here is a simple pattern file: ==================== # Pattern to reject passwords which do not comply to # - at least 1 uppercase letter # - at least 1 lowercase letter # - at least one number # - at least one special character # and a few extra things to show the reject mode # Reject is the default mode, ignore case is the default #[reject] #[icase] # If the password starts with "foo" (case insensitive) it is rejected. /foo.*/ [case] # If the password starts with "bar" (case sensitive) it is rejected. /bar.*/ # Switch to accept mode: Only if all patterns up to the next "accept" # or "reject" tag or EOF match, the password is accepted. Otherwise # the password is rejected. [accept] /[A-Z]+/ /[a-z]+/ /[0-9]+/ /[^A-Za-z0-9]+/ =================
This commit is contained in:
parent
4952ed9584
commit
5ca15e58b2
@ -94,6 +94,7 @@ myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
|
|||||||
myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \
|
myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \
|
||||||
watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
|
watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
|
||||||
gpg-connect-agent.1 gpgparsemail.1 gpgtar.1 \
|
gpg-connect-agent.1 gpgparsemail.1 gpgtar.1 \
|
||||||
|
gpg-check-pattern.1 \
|
||||||
applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \
|
applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \
|
||||||
dirmngr-client.1
|
dirmngr-client.1
|
||||||
if USE_GPG2_HACK
|
if USE_GPG2_HACK
|
||||||
|
@ -20,6 +20,7 @@ GnuPG comes with a couple of smaller tools:
|
|||||||
* dirmngr-client:: How to use the Dirmngr client tool.
|
* dirmngr-client:: How to use the Dirmngr client tool.
|
||||||
* gpgparsemail:: Parse a mail message into an annotated format
|
* gpgparsemail:: Parse a mail message into an annotated format
|
||||||
* gpgtar:: Encrypt or sign files into an archive.
|
* gpgtar:: Encrypt or sign files into an archive.
|
||||||
|
* gpg-check-pattern:: Check a passphrase on stdin against the patternfile.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@c
|
@c
|
||||||
@ -1994,3 +1995,95 @@ gpgtar --list-archive test1
|
|||||||
@command{tar}(1),
|
@command{tar}(1),
|
||||||
@end ifset
|
@end ifset
|
||||||
@include see-also-note.texi
|
@include see-also-note.texi
|
||||||
|
|
||||||
|
@c
|
||||||
|
@c GPG-CHECK-PATTERN
|
||||||
|
@c
|
||||||
|
@manpage gpg-check-pattern.1
|
||||||
|
@node gpg-check-pattern
|
||||||
|
@section Check a passphrase on stdin against the patternfile
|
||||||
|
@ifset manverb
|
||||||
|
.B gpg-check-pattern
|
||||||
|
\- Check a passphrase on stdin against the patternfile
|
||||||
|
@end ifset
|
||||||
|
|
||||||
|
@mansect synopsis
|
||||||
|
@ifset manverb
|
||||||
|
.B gpg\-check\-pattern
|
||||||
|
.RI [ options ]
|
||||||
|
.I patternfile
|
||||||
|
@end ifset
|
||||||
|
|
||||||
|
@mansect description
|
||||||
|
@command{gpg-check-pattern} checks a passphrase given on stdin against
|
||||||
|
a specified pattern file.
|
||||||
|
|
||||||
|
The pattern file is line based with comment lines beginning on the
|
||||||
|
@emph{first} position with a @code{#}. Empty lines and lines with
|
||||||
|
only white spaces are ignored. The actual pattern lines may either be
|
||||||
|
verbatim string pattern and match as they are (trailing spaces are
|
||||||
|
ignored) or extended regular expressions indicated by a @code{/} or
|
||||||
|
@code{!/} in the first column and terminated by another @code{/} or
|
||||||
|
end of line. If a regular expression starts with @code{!/} the match
|
||||||
|
result is reversed. By default all comparisons are case insensitive.
|
||||||
|
|
||||||
|
Tag lines may be used to further control the operation of this tool.
|
||||||
|
The currently defined tags are:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item [icase]
|
||||||
|
Switch to case insensitive comparison for all further patterns. This
|
||||||
|
is the default.
|
||||||
|
|
||||||
|
@item [case]
|
||||||
|
Switch to case sensitive comparison for all further patterns.
|
||||||
|
|
||||||
|
@item [reject]
|
||||||
|
Switch to reject mode. This is the default mode.
|
||||||
|
|
||||||
|
@item [accept]
|
||||||
|
Switch to accept mode.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
In the future more tags may be introduced and thus it is advisable not to
|
||||||
|
start a plain pattern string with an open bracket. The tags must be
|
||||||
|
given verbatim on the line with no spaces to the left or any non white
|
||||||
|
space characters to the right.
|
||||||
|
|
||||||
|
In reject mode the program exits on the first match with an exit code
|
||||||
|
of 1 (failure). If at the end of the pattern list the reject mode is
|
||||||
|
still active the program exits with code 0 (success).
|
||||||
|
|
||||||
|
In accept mode blocks of patterns are used. A block starts at the
|
||||||
|
next pattern after an "accept" tag and ends with the last pattern
|
||||||
|
before the next "accept" or "reject" tag or at the end of the pattern
|
||||||
|
list. If all patterns in a block match the program exits with an exit
|
||||||
|
code of 0 (success). If any pattern in a block do not match the next
|
||||||
|
pattern block is evaluated. If at the end of the pattern list the
|
||||||
|
accept mode is still active the program exits with code 1 (failure).
|
||||||
|
|
||||||
|
|
||||||
|
@mansect options
|
||||||
|
@noindent
|
||||||
|
|
||||||
|
@table @gnupgtabopt
|
||||||
|
|
||||||
|
@item --verbose
|
||||||
|
@opindex verbose
|
||||||
|
Enable extra informational output.
|
||||||
|
|
||||||
|
@item --check
|
||||||
|
@opindex check
|
||||||
|
Run only a syntax check on the patternfile.
|
||||||
|
|
||||||
|
@item --null
|
||||||
|
@opindex null
|
||||||
|
Input is expected to be null delimited.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@mansect see also
|
||||||
|
@ifset isman
|
||||||
|
@command{gpg-agent}(1),
|
||||||
|
@end ifset
|
||||||
|
@include see-also-note.texi
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* gpg-check-pattern.c - A tool to check passphrases against pattern.
|
/* gpg-check-pattern.c - A tool to check passphrases against pattern.
|
||||||
|
* Copyright (C) 2021 g10 Code GmbH
|
||||||
* Copyright (C) 2007 Free Software Foundation, Inc.
|
* Copyright (C) 2007 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
@ -26,7 +27,6 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifdef HAVE_LOCALE_H
|
||||||
# include <locale.h>
|
# include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
@ -50,11 +50,7 @@
|
|||||||
enum cmd_and_opt_values
|
enum cmd_and_opt_values
|
||||||
{ aNull = 0,
|
{ aNull = 0,
|
||||||
oVerbose = 'v',
|
oVerbose = 'v',
|
||||||
oArmor = 'a',
|
|
||||||
oPassphrase = 'P',
|
|
||||||
|
|
||||||
oProtect = 'p',
|
|
||||||
oUnprotect = 'u',
|
|
||||||
oNull = '0',
|
oNull = '0',
|
||||||
|
|
||||||
oNoVerbose = 500,
|
oNoVerbose = 500,
|
||||||
@ -101,6 +97,10 @@ struct pattern_s
|
|||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
unsigned int lineno; /* Line number of the pattern file. */
|
unsigned int lineno; /* Line number of the pattern file. */
|
||||||
|
unsigned int newblock; /* First pattern in a new block. */
|
||||||
|
unsigned int icase:1; /* Case insensitive match. */
|
||||||
|
unsigned int accept:1; /* In accept mode. */
|
||||||
|
unsigned int reverse:1; /* Reverse the outcome of a regexp match. */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
const char *string; /* Pointer to the actual string (nul termnated). */
|
const char *string; /* Pointer to the actual string (nul termnated). */
|
||||||
@ -201,7 +201,7 @@ main (int argc, char **argv )
|
|||||||
usage (1);
|
usage (1);
|
||||||
|
|
||||||
/* We read the entire pattern file into our memory and parse it
|
/* We read the entire pattern file into our memory and parse it
|
||||||
using a separate function. This allows us to eventual do the
|
using a separate function. This allows us to eventually do the
|
||||||
reading while running setuid so that the pattern file can be
|
reading while running setuid so that the pattern file can be
|
||||||
hidden from regular users. I am not sure whether this makes
|
hidden from regular users. I am not sure whether this makes
|
||||||
sense, but lets be prepared for it. */
|
sense, but lets be prepared for it. */
|
||||||
@ -220,7 +220,7 @@ main (int argc, char **argv )
|
|||||||
#endif
|
#endif
|
||||||
process (stdin, patternarray);
|
process (stdin, patternarray);
|
||||||
|
|
||||||
return log_get_errorcount(0)? 1 : 0;
|
return 4; /*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -311,6 +311,7 @@ get_regerror (int errcode, regex_t *compiled)
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse the pattern given in the memory aread DATA/DATALEN and return
|
/* Parse the pattern given in the memory aread DATA/DATALEN and return
|
||||||
a new pattern array. The end of the array is indicated by a NULL
|
a new pattern array. The end of the array is indicated by a NULL
|
||||||
entry. On error an error message is printed and the function
|
entry. On error an error message is printed and the function
|
||||||
@ -325,6 +326,9 @@ parse_pattern_file (char *data, size_t datalen)
|
|||||||
pattern_t *array;
|
pattern_t *array;
|
||||||
size_t arraysize, arrayidx;
|
size_t arraysize, arrayidx;
|
||||||
unsigned int lineno = 0;
|
unsigned int lineno = 0;
|
||||||
|
unsigned int icase_mode = 1;
|
||||||
|
unsigned int accept_mode = 0;
|
||||||
|
unsigned int newblock = 1; /* The first implict block. */
|
||||||
|
|
||||||
/* Estimate the number of entries by counting the non-comment lines. */
|
/* Estimate the number of entries by counting the non-comment lines. */
|
||||||
arraysize = 0;
|
arraysize = 0;
|
||||||
@ -350,7 +354,7 @@ parse_pattern_file (char *data, size_t datalen)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
p2 = p + datalen;
|
p2 = p + datalen;
|
||||||
assert (!*p2);
|
log_assert (!*p2);
|
||||||
p2--;
|
p2--;
|
||||||
while (isascii (*p) && isspace (*p))
|
while (isascii (*p) && isspace (*p))
|
||||||
p++;
|
p++;
|
||||||
@ -360,23 +364,57 @@ parse_pattern_file (char *data, size_t datalen)
|
|||||||
*p2-- = 0;
|
*p2-- = 0;
|
||||||
if (!*p)
|
if (!*p)
|
||||||
continue;
|
continue;
|
||||||
assert (arrayidx < arraysize);
|
if (!strcmp (p, "[case]"))
|
||||||
|
{
|
||||||
|
icase_mode = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp (p, "[icase]"))
|
||||||
|
{
|
||||||
|
icase_mode = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp (p, "[accept]"))
|
||||||
|
{
|
||||||
|
accept_mode = 1;
|
||||||
|
newblock = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp (p, "[reject]"))
|
||||||
|
{
|
||||||
|
accept_mode = 0;
|
||||||
|
newblock = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert (arrayidx < arraysize);
|
||||||
array[arrayidx].lineno = lineno;
|
array[arrayidx].lineno = lineno;
|
||||||
if (*p == '/')
|
array[arrayidx].icase = icase_mode;
|
||||||
|
array[arrayidx].accept = accept_mode;
|
||||||
|
array[arrayidx].reverse = 0;
|
||||||
|
array[arrayidx].newblock = newblock;
|
||||||
|
newblock = 0;
|
||||||
|
|
||||||
|
if (*p == '/' || (*p == '!' && p[1] == '/'))
|
||||||
{
|
{
|
||||||
int rerr;
|
int rerr;
|
||||||
|
int reverse;
|
||||||
|
|
||||||
|
reverse = (*p == '!');
|
||||||
p++;
|
p++;
|
||||||
|
if (reverse)
|
||||||
|
p++;
|
||||||
array[arrayidx].type = PAT_REGEX;
|
array[arrayidx].type = PAT_REGEX;
|
||||||
if (*p && p[strlen(p)-1] == '/')
|
if (*p && p[strlen(p)-1] == '/')
|
||||||
p[strlen(p)-1] = 0; /* Remove optional delimiter. */
|
p[strlen(p)-1] = 0; /* Remove optional delimiter. */
|
||||||
array[arrayidx].u.r.regex = xcalloc (1, sizeof (regex_t));
|
array[arrayidx].u.r.regex = xcalloc (1, sizeof (regex_t));
|
||||||
|
array[arrayidx].reverse = reverse;
|
||||||
rerr = regcomp (array[arrayidx].u.r.regex, p,
|
rerr = regcomp (array[arrayidx].u.r.regex, p,
|
||||||
REG_ICASE|REG_EXTENDED);
|
(array[arrayidx].icase? REG_ICASE:0)|REG_EXTENDED);
|
||||||
if (rerr)
|
if (rerr)
|
||||||
{
|
{
|
||||||
char *rerrbuf = get_regerror (rerr, array[arrayidx].u.r.regex);
|
char *rerrbuf = get_regerror (rerr, array[arrayidx].u.r.regex);
|
||||||
log_error ("invalid r.e. at line %u: %s\n", lineno, rerrbuf);
|
log_error ("invalid regexp at line %u: %s\n", lineno, rerrbuf);
|
||||||
xfree (rerrbuf);
|
xfree (rerrbuf);
|
||||||
if (!opt.checkonly)
|
if (!opt.checkonly)
|
||||||
exit (1);
|
exit (1);
|
||||||
@ -384,25 +422,44 @@ parse_pattern_file (char *data, size_t datalen)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (*p == '[')
|
||||||
|
{
|
||||||
|
static int shown;
|
||||||
|
|
||||||
|
if (!shown)
|
||||||
|
{
|
||||||
|
log_info ("future warning: do no start a string with '['"
|
||||||
|
" but use a regexp (line %u)\n", lineno);
|
||||||
|
shown = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
array[arrayidx].type = PAT_STRING;
|
array[arrayidx].type = PAT_STRING;
|
||||||
array[arrayidx].u.s.string = p;
|
array[arrayidx].u.s.string = p;
|
||||||
array[arrayidx].u.s.length = strlen (p);
|
array[arrayidx].u.s.length = strlen (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayidx++;
|
arrayidx++;
|
||||||
}
|
}
|
||||||
assert (arrayidx < arraysize);
|
log_assert (arrayidx < arraysize);
|
||||||
array[arrayidx].type = PAT_NULL;
|
array[arrayidx].type = PAT_NULL;
|
||||||
|
|
||||||
|
if (lineno && newblock)
|
||||||
|
log_info ("warning: pattern list ends with a singleton"
|
||||||
|
" accept or reject tag\n");
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check whether string macthes any of the pattern in PATARRAY and
|
/* Check whether string matches any of the pattern in PATARRAY and
|
||||||
returns the matching pattern item or NULL. */
|
returns the matching pattern item or NULL. */
|
||||||
static pattern_t *
|
static pattern_t *
|
||||||
match_p (const char *string, pattern_t *patarray)
|
match_p (const char *string, pattern_t *patarray)
|
||||||
{
|
{
|
||||||
pattern_t *pat;
|
pattern_t *pat;
|
||||||
|
int match;
|
||||||
|
int accept_match; /* Tracks matchinf state in an accept block. */
|
||||||
|
int accept_skip; /* Skip remaining patterns in an accept block. */
|
||||||
|
|
||||||
if (!*string)
|
if (!*string)
|
||||||
{
|
{
|
||||||
@ -411,30 +468,84 @@ match_p (const char *string, pattern_t *patarray)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accept_match = 0;
|
||||||
|
accept_skip = 0;
|
||||||
for (pat = patarray; pat->type != PAT_NULL; pat++)
|
for (pat = patarray; pat->type != PAT_NULL; pat++)
|
||||||
{
|
{
|
||||||
|
match = 0;
|
||||||
|
if (pat->newblock)
|
||||||
|
accept_match = accept_skip = 0;
|
||||||
|
|
||||||
if (pat->type == PAT_STRING)
|
if (pat->type == PAT_STRING)
|
||||||
{
|
{
|
||||||
if (!strcasecmp (pat->u.s.string, string))
|
if (pat->icase)
|
||||||
return pat;
|
{
|
||||||
|
if (!strcasecmp (pat->u.s.string, string))
|
||||||
|
match = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!strcmp (pat->u.s.string, string))
|
||||||
|
match = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (pat->type == PAT_REGEX)
|
else if (pat->type == PAT_REGEX)
|
||||||
{
|
{
|
||||||
int rerr;
|
int rerr;
|
||||||
|
|
||||||
rerr = regexec (pat->u.r.regex, string, 0, NULL, 0);
|
rerr = regexec (pat->u.r.regex, string, 0, NULL, 0);
|
||||||
|
if (pat->reverse)
|
||||||
|
{
|
||||||
|
if (!rerr)
|
||||||
|
rerr = REG_NOMATCH;
|
||||||
|
else if (rerr == REG_NOMATCH)
|
||||||
|
rerr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!rerr)
|
if (!rerr)
|
||||||
return pat;
|
match = 1;
|
||||||
else if (rerr != REG_NOMATCH)
|
else if (rerr != REG_NOMATCH)
|
||||||
{
|
{
|
||||||
char *rerrbuf = get_regerror (rerr, pat->u.r.regex);
|
char *rerrbuf = get_regerror (rerr, pat->u.r.regex);
|
||||||
log_error ("matching r.e. failed: %s\n", rerrbuf);
|
log_error ("matching regexp failed: %s\n", rerrbuf);
|
||||||
xfree (rerrbuf);
|
xfree (rerrbuf);
|
||||||
return pat; /* Better indicate a match on error. */
|
if (pat->accept)
|
||||||
|
match = 0; /* Better indicate no match on error. */
|
||||||
|
else
|
||||||
|
match = 1; /* Better indicate a match on error. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
BUG ();
|
BUG ();
|
||||||
|
|
||||||
|
if (pat->accept)
|
||||||
|
{
|
||||||
|
/* Accept mode: all patterns in the accept block must match.
|
||||||
|
* Thus we need to check whether the next pattern has a
|
||||||
|
* transition and act only then. */
|
||||||
|
if (match && !accept_skip)
|
||||||
|
accept_match = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accept_match = 0;
|
||||||
|
accept_skip = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pat[1].type == PAT_NULL || pat[1].newblock)
|
||||||
|
{
|
||||||
|
/* Transition detected. Note that this also handles the
|
||||||
|
* end of pattern loop case. */
|
||||||
|
if (accept_match)
|
||||||
|
return pat;
|
||||||
|
/* The next is not really but we do it for clarity. */
|
||||||
|
accept_match = accept_skip = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Reject mode: Return true on the first match. */
|
||||||
|
{
|
||||||
|
if (match)
|
||||||
|
return pat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -450,6 +561,7 @@ process (FILE *fp, pattern_t *patarray)
|
|||||||
int c;
|
int c;
|
||||||
unsigned long lineno = 0;
|
unsigned long lineno = 0;
|
||||||
pattern_t *pat;
|
pattern_t *pat;
|
||||||
|
int last_is_accept;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
c = 0;
|
c = 0;
|
||||||
@ -469,17 +581,28 @@ process (FILE *fp, pattern_t *patarray)
|
|||||||
pat = match_p (buffer, patarray);
|
pat = match_p (buffer, patarray);
|
||||||
if (pat)
|
if (pat)
|
||||||
{
|
{
|
||||||
|
/* Note that the accept mode works correctly only with
|
||||||
|
* one input line. */
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_error ("input line %lu matches pattern at line %u"
|
log_info ("input line %lu matches pattern at line %u"
|
||||||
" - rejected\n",
|
" - %s\n",
|
||||||
lineno, pat->lineno);
|
lineno, pat->lineno,
|
||||||
exit (1);
|
pat->accept? "accepted":"rejected");
|
||||||
}
|
}
|
||||||
idx = 0;
|
idx = 0;
|
||||||
|
wipememory (buffer, sizeof buffer);
|
||||||
|
if (pat)
|
||||||
|
{
|
||||||
|
if (pat->accept)
|
||||||
|
exit (0);
|
||||||
|
else
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
wipememory (buffer, sizeof buffer);
|
||||||
if (c != EOF)
|
if (c != EOF)
|
||||||
{
|
{
|
||||||
log_error ("input line %lu too long - rejected\n", lineno+1);
|
log_error ("input line %lu too long - rejected\n", lineno+1);
|
||||||
@ -491,6 +614,20 @@ process (FILE *fp, pattern_t *patarray)
|
|||||||
lineno+1, strerror (errno));
|
lineno+1, strerror (errno));
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check last pattern to see whether we are in accept mode. */
|
||||||
|
last_is_accept = 0;
|
||||||
|
for (pat = patarray; pat->type != PAT_NULL; pat++)
|
||||||
|
last_is_accept = pat->accept;
|
||||||
|
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info ("no input line matches the pattern - accepted\n");
|
log_info ("no input line matches the pattern - %s\n",
|
||||||
|
last_is_accept? "rejected":"accepted");
|
||||||
|
|
||||||
|
if (log_get_errorcount(0))
|
||||||
|
exit (2); /* Ooops - reject. */
|
||||||
|
else if (last_is_accept)
|
||||||
|
exit (1); /* Reject */
|
||||||
|
else
|
||||||
|
exit (0); /* Accept */
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user