Add a .pragma directive for configuration files
Currently added pragma: .pragma dollarid:on This allows dollar signs to be a keyword character unless it's followed by a opening brace or parenthesis. Fixes #8207 Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8882)
This commit is contained in:
parent
4d301427a9
commit
0255c1742a
9 changed files with 120 additions and 7 deletions
12
CHANGES
12
CHANGES
|
@ -9,6 +9,18 @@
|
||||||
|
|
||||||
Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
|
Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
|
||||||
|
|
||||||
|
*) Added a .pragma directive to the syntax of configuration files, to
|
||||||
|
allow varying behavior in a supported and predictable manner.
|
||||||
|
Currently added pragma:
|
||||||
|
|
||||||
|
.pragma dollarid:on
|
||||||
|
|
||||||
|
This allows dollar signs to be a keyword character unless it's
|
||||||
|
followed by a opening brace or parenthesis. This is useful for
|
||||||
|
platforms where dollar signs are commonly used in names, such as
|
||||||
|
volume names and system directory names on VMS.
|
||||||
|
[Richard Levitte]
|
||||||
|
|
||||||
*) Added functionality to create an EVP_PKEY from user data. This
|
*) Added functionality to create an EVP_PKEY from user data. This
|
||||||
is effectively the same as creating a RSA, DH or DSA object and
|
is effectively the same as creating a RSA, DH or DSA object and
|
||||||
then assigning them to an EVP_PKEY, but directly using algorithm
|
then assigning them to an EVP_PKEY, but directly using algorithm
|
||||||
|
|
|
@ -354,7 +354,49 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
|
||||||
psection = section;
|
psection = section;
|
||||||
}
|
}
|
||||||
p = eat_ws(conf, end);
|
p = eat_ws(conf, end);
|
||||||
if (strncmp(pname, ".include", 8) == 0
|
if (strncmp(pname, ".pragma", 7) == 0
|
||||||
|
&& (p != pname + 7 || *p == '=')) {
|
||||||
|
char *pval;
|
||||||
|
|
||||||
|
if (*p == '=') {
|
||||||
|
p++;
|
||||||
|
p = eat_ws(conf, p);
|
||||||
|
}
|
||||||
|
trim_ws(conf, p);
|
||||||
|
|
||||||
|
/* Pragma values take the form keyword:value */
|
||||||
|
pval = strchr(p, ':');
|
||||||
|
if (pval == NULL || pval == p || pval[1] == '\0') {
|
||||||
|
CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_INVALID_PRAGMA);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pval++ = '\0';
|
||||||
|
trim_ws(conf, p);
|
||||||
|
pval = eat_ws(conf, pval);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known pragmas:
|
||||||
|
*
|
||||||
|
* dollarid takes "on", "true or "off", "false"
|
||||||
|
*/
|
||||||
|
if (strcmp(p, "dollarid") == 0) {
|
||||||
|
if (strcmp(pval, "on") == 0
|
||||||
|
|| strcmp(pval, "true") == 0) {
|
||||||
|
conf->flag_dollarid = 1;
|
||||||
|
} else if (strcmp(pval, "off") == 0
|
||||||
|
|| strcmp(pval, "false") == 0) {
|
||||||
|
conf->flag_dollarid = 0;
|
||||||
|
} else {
|
||||||
|
CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_INVALID_PRAGMA);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We *ignore* any unknown pragma.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
} else if (strncmp(pname, ".include", 8) == 0
|
||||||
&& (p != pname + 8 || *p == '=')) {
|
&& (p != pname + 8 || *p == '=')) {
|
||||||
char *include = NULL;
|
char *include = NULL;
|
||||||
BIO *next;
|
BIO *next;
|
||||||
|
@ -590,7 +632,10 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from)
|
||||||
buf->data[to++] = v;
|
buf->data[to++] = v;
|
||||||
} else if (IS_EOF(conf, *from))
|
} else if (IS_EOF(conf, *from))
|
||||||
break;
|
break;
|
||||||
else if (*from == '$') {
|
else if (*from == '$'
|
||||||
|
&& (!conf->flag_dollarid
|
||||||
|
|| from[1] == '{'
|
||||||
|
|| from[1] == '(')) {
|
||||||
size_t newsize;
|
size_t newsize;
|
||||||
|
|
||||||
/* try to expand it */
|
/* try to expand it */
|
||||||
|
@ -607,7 +652,8 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from)
|
||||||
s++;
|
s++;
|
||||||
cp = section;
|
cp = section;
|
||||||
e = np = s;
|
e = np = s;
|
||||||
while (IS_ALNUM(conf, *e))
|
while (IS_ALNUM(conf, *e)
|
||||||
|
|| (conf->flag_dollarid && IS_DOLLAR(conf, *e)))
|
||||||
e++;
|
e++;
|
||||||
if ((e[0] == ':') && (e[1] == ':')) {
|
if ((e[0] == ':') && (e[1] == ':')) {
|
||||||
cp = np;
|
cp = np;
|
||||||
|
@ -616,7 +662,8 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from)
|
||||||
*rrp = '\0';
|
*rrp = '\0';
|
||||||
e += 2;
|
e += 2;
|
||||||
np = e;
|
np = e;
|
||||||
while (IS_ALNUM(conf, *e))
|
while (IS_ALNUM(conf, *e)
|
||||||
|
|| (conf->flag_dollarid && IS_DOLLAR(conf, *e)))
|
||||||
e++;
|
e++;
|
||||||
}
|
}
|
||||||
r = *e;
|
r = *e;
|
||||||
|
@ -832,7 +879,8 @@ static char *eat_alpha_numeric(CONF *conf, char *p)
|
||||||
p = scan_esc(conf, p);
|
p = scan_esc(conf, p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!IS_ALNUM_PUNCT(conf, *p))
|
if (!(IS_ALNUM_PUNCT(conf, *p)
|
||||||
|
|| (conf->flag_dollarid && IS_DOLLAR(conf, *p))))
|
||||||
return p;
|
return p;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define CONF_DQUOTE 1024
|
#define CONF_DQUOTE 1024
|
||||||
#define CONF_COMMENT 128
|
#define CONF_COMMENT 128
|
||||||
#define CONF_FCOMMENT 2048
|
#define CONF_FCOMMENT 2048
|
||||||
|
#define CONF_DOLLAR 4096
|
||||||
#define CONF_EOF 8
|
#define CONF_EOF 8
|
||||||
#define CONF_ALPHA (CONF_UPPER|CONF_LOWER)
|
#define CONF_ALPHA (CONF_UPPER|CONF_LOWER)
|
||||||
#define CONF_ALNUM (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
|
#define CONF_ALNUM (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
|
||||||
|
@ -36,13 +37,14 @@
|
||||||
#define IS_ALNUM_PUNCT(conf,c) is_keytype(conf, c, CONF_ALNUM_PUNCT)
|
#define IS_ALNUM_PUNCT(conf,c) is_keytype(conf, c, CONF_ALNUM_PUNCT)
|
||||||
#define IS_QUOTE(conf,c) is_keytype(conf, c, CONF_QUOTE)
|
#define IS_QUOTE(conf,c) is_keytype(conf, c, CONF_QUOTE)
|
||||||
#define IS_DQUOTE(conf,c) is_keytype(conf, c, CONF_DQUOTE)
|
#define IS_DQUOTE(conf,c) is_keytype(conf, c, CONF_DQUOTE)
|
||||||
|
#define IS_DOLLAR(conf,c) is_keytype(conf, c, CONF_DOLLAR)
|
||||||
|
|
||||||
static const unsigned short CONF_type_default[128] = {
|
static const unsigned short CONF_type_default[128] = {
|
||||||
0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
|
0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
|
||||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
0x0010, 0x0200, 0x0040, 0x0080, 0x0000, 0x0200, 0x0200, 0x0040,
|
0x0010, 0x0200, 0x0040, 0x0080, 0x1000, 0x0200, 0x0200, 0x0040,
|
||||||
0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||||
0x0001, 0x0001, 0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x0200,
|
0x0001, 0x0001, 0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x0200,
|
||||||
|
@ -62,7 +64,7 @@ static const unsigned short CONF_type_win32[128] = {
|
||||||
0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
|
0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
|
||||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
0x0010, 0x0200, 0x0400, 0x0000, 0x0000, 0x0200, 0x0200, 0x0000,
|
0x0010, 0x0200, 0x0400, 0x0000, 0x1000, 0x0200, 0x0200, 0x0000,
|
||||||
0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
||||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||||
0x0001, 0x0001, 0x0000, 0x0A00, 0x0000, 0x0000, 0x0000, 0x0200,
|
0x0001, 0x0001, 0x0000, 0x0A00, 0x0000, 0x0000, 0x0000, 0x0200,
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
|
|
||||||
static const ERR_STRING_DATA CONF_str_reasons[] = {
|
static const ERR_STRING_DATA CONF_str_reasons[] = {
|
||||||
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_ERROR_LOADING_DSO), "error loading dso"},
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_ERROR_LOADING_DSO), "error loading dso"},
|
||||||
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_INVALID_PRAGMA), "invalid pragma"},
|
||||||
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_LIST_CANNOT_BE_NULL),
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_LIST_CANNOT_BE_NULL),
|
||||||
"list cannot be null"},
|
"list cannot be null"},
|
||||||
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION),
|
||||||
|
"mandatory braces in variable expansion"},
|
||||||
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_CLOSE_SQUARE_BRACKET),
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_CLOSE_SQUARE_BRACKET),
|
||||||
"missing close square bracket"},
|
"missing close square bracket"},
|
||||||
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_EQUAL_SIGN),
|
{ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_EQUAL_SIGN),
|
||||||
|
|
|
@ -20,6 +20,7 @@ my $QUOTE = 0x0040;
|
||||||
my $DQUOTE = 0x0400;
|
my $DQUOTE = 0x0400;
|
||||||
my $COMMENT = 0x0080;
|
my $COMMENT = 0x0080;
|
||||||
my $FCOMMENT = 0x0800;
|
my $FCOMMENT = 0x0800;
|
||||||
|
my $DOLLAR = 0x1000;
|
||||||
my $EOF = 0x0008;
|
my $EOF = 0x0008;
|
||||||
my @V_def;
|
my @V_def;
|
||||||
my @V_w32;
|
my @V_w32;
|
||||||
|
@ -38,6 +39,7 @@ foreach (0 .. 127) {
|
||||||
$v |= $ESC if $c =~ /\\/;
|
$v |= $ESC if $c =~ /\\/;
|
||||||
$v |= $QUOTE if $c =~ /['`"]/; # for emacs: "`'
|
$v |= $QUOTE if $c =~ /['`"]/; # for emacs: "`'
|
||||||
$v |= $COMMENT if $c =~ /\#/;
|
$v |= $COMMENT if $c =~ /\#/;
|
||||||
|
$v |= $DOLLAR if $c eq '$';
|
||||||
$v |= $EOF if $c =~ /\0/;
|
$v |= $EOF if $c =~ /\0/;
|
||||||
push(@V_def, $v);
|
push(@V_def, $v);
|
||||||
|
|
||||||
|
@ -50,6 +52,7 @@ foreach (0 .. 127) {
|
||||||
$v |= $WS if $c =~ /[ \t\r\n]/;
|
$v |= $WS if $c =~ /[ \t\r\n]/;
|
||||||
$v |= $DQUOTE if $c =~ /["]/; # for emacs: "
|
$v |= $DQUOTE if $c =~ /["]/; # for emacs: "
|
||||||
$v |= $FCOMMENT if $c =~ /;/;
|
$v |= $FCOMMENT if $c =~ /;/;
|
||||||
|
$v |= $DOLLAR if $c eq '$';
|
||||||
$v |= $EOF if $c =~ /\0/;
|
$v |= $EOF if $c =~ /\0/;
|
||||||
push(@V_w32, $v);
|
push(@V_w32, $v);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +83,7 @@ print <<"EOF";
|
||||||
#define CONF_DQUOTE $DQUOTE
|
#define CONF_DQUOTE $DQUOTE
|
||||||
#define CONF_COMMENT $COMMENT
|
#define CONF_COMMENT $COMMENT
|
||||||
#define CONF_FCOMMENT $FCOMMENT
|
#define CONF_FCOMMENT $FCOMMENT
|
||||||
|
#define CONF_DOLLAR $DOLLAR
|
||||||
#define CONF_EOF $EOF
|
#define CONF_EOF $EOF
|
||||||
#define CONF_ALPHA (CONF_UPPER|CONF_LOWER)
|
#define CONF_ALPHA (CONF_UPPER|CONF_LOWER)
|
||||||
#define CONF_ALNUM (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
|
#define CONF_ALNUM (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
|
||||||
|
@ -96,6 +100,7 @@ print <<"EOF";
|
||||||
#define IS_ALNUM_PUNCT(conf,c) is_keytype(conf, c, CONF_ALNUM_PUNCT)
|
#define IS_ALNUM_PUNCT(conf,c) is_keytype(conf, c, CONF_ALNUM_PUNCT)
|
||||||
#define IS_QUOTE(conf,c) is_keytype(conf, c, CONF_QUOTE)
|
#define IS_QUOTE(conf,c) is_keytype(conf, c, CONF_QUOTE)
|
||||||
#define IS_DQUOTE(conf,c) is_keytype(conf, c, CONF_DQUOTE)
|
#define IS_DQUOTE(conf,c) is_keytype(conf, c, CONF_DQUOTE)
|
||||||
|
#define IS_DOLLAR(conf,c) is_keytype(conf, c, CONF_DOLLAR)
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
@ -2163,7 +2163,10 @@ COMP_R_ZLIB_DEFLATE_ERROR:99:zlib deflate error
|
||||||
COMP_R_ZLIB_INFLATE_ERROR:100:zlib inflate error
|
COMP_R_ZLIB_INFLATE_ERROR:100:zlib inflate error
|
||||||
COMP_R_ZLIB_NOT_SUPPORTED:101:zlib not supported
|
COMP_R_ZLIB_NOT_SUPPORTED:101:zlib not supported
|
||||||
CONF_R_ERROR_LOADING_DSO:110:error loading dso
|
CONF_R_ERROR_LOADING_DSO:110:error loading dso
|
||||||
|
CONF_R_INVALID_PRAGMA:122:invalid pragma
|
||||||
CONF_R_LIST_CANNOT_BE_NULL:115:list cannot be null
|
CONF_R_LIST_CANNOT_BE_NULL:115:list cannot be null
|
||||||
|
CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION:123:\
|
||||||
|
mandatory braces in variable expansion
|
||||||
CONF_R_MISSING_CLOSE_SQUARE_BRACKET:100:missing close square bracket
|
CONF_R_MISSING_CLOSE_SQUARE_BRACKET:100:missing close square bracket
|
||||||
CONF_R_MISSING_EQUAL_SIGN:101:missing equal sign
|
CONF_R_MISSING_EQUAL_SIGN:101:missing equal sign
|
||||||
CONF_R_MISSING_INIT_FUNCTION:112:missing init function
|
CONF_R_MISSING_INIT_FUNCTION:112:missing init function
|
||||||
|
|
|
@ -50,6 +50,9 @@ not support the B<.include> syntax. They would bail out with error
|
||||||
if the B<=> character is not present but with it they just ignore
|
if the B<=> character is not present but with it they just ignore
|
||||||
the include.
|
the include.
|
||||||
|
|
||||||
|
Pragmas can be specified with the B<.pragma> directive.
|
||||||
|
See L</PRAGMAS> for mor information.
|
||||||
|
|
||||||
Each section in a configuration file consists of a number of name and
|
Each section in a configuration file consists of a number of name and
|
||||||
value pairs of the form B<name=value>
|
value pairs of the form B<name=value>
|
||||||
|
|
||||||
|
@ -78,6 +81,40 @@ the sequences B<\n>, B<\r>, B<\b> and B<\t> are recognized.
|
||||||
All expansion and escape rules as described above that apply to B<value>
|
All expansion and escape rules as described above that apply to B<value>
|
||||||
also apply to the path of the B<.include> directive.
|
also apply to the path of the B<.include> directive.
|
||||||
|
|
||||||
|
=head1 PRAGMAS
|
||||||
|
|
||||||
|
Pragmas can be used to change the behavior of the configuration file
|
||||||
|
parser, among others. Currently supported pragmas are:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<.pragma> B<dollarid>:I<value>
|
||||||
|
|
||||||
|
I<value> can be one of:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<"on"> or B<"true">
|
||||||
|
|
||||||
|
this signifies that dollar signs are considered an identity character
|
||||||
|
from this point on and that variable expansion requires the use of
|
||||||
|
braces or parentheses. In other words, C<foo$bar> will be considered
|
||||||
|
a name instead of C<foo> followed by the expansion of the variable
|
||||||
|
C<bar>.
|
||||||
|
This is suitable for platforms where the dollar sign is commonly used
|
||||||
|
as part of names.
|
||||||
|
|
||||||
|
=item B<"off"> or B<"false">
|
||||||
|
|
||||||
|
Turns this pragma off, i.e. C<foo$bar> will be interpreted as C<foo>
|
||||||
|
followed by the expansion of the variable C<bar>.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
By default, this pragma is turned off.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
=head1 OPENSSL LIBRARY CONFIGURATION
|
=head1 OPENSSL LIBRARY CONFIGURATION
|
||||||
|
|
||||||
Applications can automatically configure certain
|
Applications can automatically configure certain
|
||||||
|
|
|
@ -110,6 +110,7 @@ struct conf_st {
|
||||||
CONF_METHOD *meth;
|
CONF_METHOD *meth;
|
||||||
void *meth_data;
|
void *meth_data;
|
||||||
LHASH_OF(CONF_VALUE) *data;
|
LHASH_OF(CONF_VALUE) *data;
|
||||||
|
unsigned int flag_dollarid:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
CONF *NCONF_new(CONF_METHOD *meth);
|
CONF *NCONF_new(CONF_METHOD *meth);
|
||||||
|
|
|
@ -59,7 +59,9 @@ int ERR_load_CONF_strings(void);
|
||||||
* CONF reason codes.
|
* CONF reason codes.
|
||||||
*/
|
*/
|
||||||
# define CONF_R_ERROR_LOADING_DSO 110
|
# define CONF_R_ERROR_LOADING_DSO 110
|
||||||
|
# define CONF_R_INVALID_PRAGMA 122
|
||||||
# define CONF_R_LIST_CANNOT_BE_NULL 115
|
# define CONF_R_LIST_CANNOT_BE_NULL 115
|
||||||
|
# define CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION 123
|
||||||
# define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 100
|
# define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 100
|
||||||
# define CONF_R_MISSING_EQUAL_SIGN 101
|
# define CONF_R_MISSING_EQUAL_SIGN 101
|
||||||
# define CONF_R_MISSING_INIT_FUNCTION 112
|
# define CONF_R_MISSING_INIT_FUNCTION 112
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue