Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
openldap
OpenLDAP
Commits
bf3df2f7
Commit
bf3df2f7
authored
Aug 28, 2000
by
Kurt Zeilenga
Browse files
restrictops, requires, disallow knobs; ssf acls; and misc other changes
man pages to follow...
parent
bb996676
Changes
16
Hide whitespace changes
Inline
Side-by-side
servers/slapd/acl.c
View file @
bf3df2f7
...
...
@@ -636,6 +636,45 @@ acl_mask(
}
}
if
(
b
->
a_authz
.
sai_ssf
)
{
Debug
(
LDAP_DEBUG_ACL
,
"<= check a_authz.sai_ssf: %ud
\n
"
,
b
->
a_authz
.
sai_ssf
,
0
,
0
);
if
(
b
->
a_authz
.
sai_ssf
>
op
->
o_ssf
)
{
continue
;
}
}
if
(
b
->
a_authz
.
sai_transport_ssf
)
{
Debug
(
LDAP_DEBUG_ACL
,
"<= check a_authz.sai_transport_ssf: %ud
\n
"
,
b
->
a_authz
.
sai_transport_ssf
,
0
,
0
);
if
(
b
->
a_authz
.
sai_transport_ssf
>
op
->
o_transport_ssf
)
{
continue
;
}
}
if
(
b
->
a_authz
.
sai_tls_ssf
)
{
Debug
(
LDAP_DEBUG_ACL
,
"<= check a_authz.sai_tls_ssf: %ud
\n
"
,
b
->
a_authz
.
sai_tls_ssf
,
0
,
0
);
if
(
b
->
a_authz
.
sai_tls_ssf
>
op
->
o_tls_ssf
)
{
continue
;
}
}
if
(
b
->
a_authz
.
sai_sasl_ssf
)
{
Debug
(
LDAP_DEBUG_ACL
,
"<= check a_authz.sai_sasl_ssf: %ud
\n
"
,
b
->
a_authz
.
sai_sasl_ssf
,
0
,
0
);
if
(
b
->
a_authz
.
sai_sasl_ssf
>
op
->
o_sasl_ssf
)
{
continue
;
}
}
#ifdef SLAPD_ACI_ENABLED
if
(
b
->
a_aci_at
!=
NULL
)
{
Attribute
*
at
;
...
...
servers/slapd/aclparse.c
View file @
bf3df2f7
...
...
@@ -672,6 +672,110 @@ parse_acl(
}
#endif
/* SLAPD_ACI_ENABLED */
if
(
strcasecmp
(
left
,
"ssf"
)
==
0
)
{
if
(
b
->
a_authz
.
sai_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: ssf attribute already specified.
\n
"
,
fname
,
lineno
);
acl_usage
();
}
if
(
right
==
NULL
||
*
right
==
'\0'
)
{
fprintf
(
stderr
,
"%s: line %d: no ssf is defined
\n
"
,
fname
,
lineno
);
acl_usage
();
}
b
->
a_authz
.
sai_ssf
=
atoi
(
right
);
if
(
!
b
->
a_authz
.
sai_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: invalid ssf value (%s)
\n
"
,
fname
,
lineno
,
right
);
acl_usage
();
}
continue
;
}
if
(
strcasecmp
(
left
,
"transport_ssf"
)
==
0
)
{
if
(
b
->
a_authz
.
sai_transport_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: transport_ssf attribute already specified.
\n
"
,
fname
,
lineno
);
acl_usage
();
}
if
(
right
==
NULL
||
*
right
==
'\0'
)
{
fprintf
(
stderr
,
"%s: line %d: no transport_ssf is defined
\n
"
,
fname
,
lineno
);
acl_usage
();
}
b
->
a_authz
.
sai_transport_ssf
=
atoi
(
right
);
if
(
!
b
->
a_authz
.
sai_transport_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: invalid transport_ssf value (%s)
\n
"
,
fname
,
lineno
,
right
);
acl_usage
();
}
continue
;
}
if
(
strcasecmp
(
left
,
"tls_ssf"
)
==
0
)
{
if
(
b
->
a_authz
.
sai_tls_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: tls_ssf attribute already specified.
\n
"
,
fname
,
lineno
);
acl_usage
();
}
if
(
right
==
NULL
||
*
right
==
'\0'
)
{
fprintf
(
stderr
,
"%s: line %d: no tls_ssf is defined
\n
"
,
fname
,
lineno
);
acl_usage
();
}
b
->
a_authz
.
sai_tls_ssf
=
atoi
(
right
);
if
(
!
b
->
a_authz
.
sai_tls_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: invalid tls_ssf value (%s)
\n
"
,
fname
,
lineno
,
right
);
acl_usage
();
}
continue
;
}
if
(
strcasecmp
(
left
,
"sasl_ssf"
)
==
0
)
{
if
(
b
->
a_authz
.
sai_sasl_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: sasl_ssf attribute already specified.
\n
"
,
fname
,
lineno
);
acl_usage
();
}
if
(
right
==
NULL
||
*
right
==
'\0'
)
{
fprintf
(
stderr
,
"%s: line %d: no sasl_ssf is defined
\n
"
,
fname
,
lineno
);
acl_usage
();
}
b
->
a_authz
.
sai_sasl_ssf
=
atoi
(
right
);
if
(
!
b
->
a_authz
.
sai_sasl_ssf
)
{
fprintf
(
stderr
,
"%s: line %d: invalid sasl_ssf value (%s)
\n
"
,
fname
,
lineno
,
right
);
acl_usage
();
}
continue
;
}
if
(
right
!=
NULL
)
{
/* unsplit */
right
[
-
1
]
=
'='
;
...
...
@@ -969,6 +1073,7 @@ acl_usage( void )
#ifdef SLAPD_ACI_ENABLED
"
\t
[aci=<attrname>]
\n
"
#endif
"
\t
[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]
\n
"
"<access> ::= [self]{<level>|<priv>}
\n
"
"<level> ::= none | auth | compare | search | read | write
\n
"
"<priv> ::= {=|+|-}{w|r|s|c|x}+
\n
"
...
...
@@ -1129,6 +1234,24 @@ print_access( Access *b )
}
#endif
/* Security Strength Factors */
if
(
b
->
a_authz
.
sai_ssf
)
{
fprintf
(
stderr
,
" ssf=%ud"
,
b
->
a_authz
.
sai_ssf
);
}
if
(
b
->
a_authz
.
sai_transport_ssf
)
{
fprintf
(
stderr
,
" transport_ssf=%ud"
,
b
->
a_authz
.
sai_transport_ssf
);
}
if
(
b
->
a_authz
.
sai_tls_ssf
)
{
fprintf
(
stderr
,
" tls_ssf=%ud"
,
b
->
a_authz
.
sai_tls_ssf
);
}
if
(
b
->
a_authz
.
sai_sasl_ssf
)
{
fprintf
(
stderr
,
" sasl_ssf=%ud"
,
b
->
a_authz
.
sai_sasl_ssf
);
}
fprintf
(
stderr
,
" %s%s"
,
b
->
a_dn_self
?
"self"
:
""
,
accessmask2str
(
b
->
a_access_mask
,
maskbuf
)
);
...
...
servers/slapd/add.c
View file @
bf3df2f7
...
...
@@ -154,8 +154,8 @@ do_add( Connection *conn, Operation *op )
goto
done
;
}
/*
make sure this backend recongizes c
riti
cal control
s */
rc
=
backend_check_
control
s
(
be
,
conn
,
op
,
&
text
)
;
/*
check rest
ri
c
ti
on
s */
rc
=
backend_check_
restriction
s
(
be
,
conn
,
op
,
NULL
,
&
text
)
;
if
(
rc
!=
LDAP_SUCCESS
)
{
send_ldap_result
(
conn
,
op
,
rc
,
NULL
,
text
,
NULL
,
NULL
);
...
...
@@ -168,14 +168,6 @@ do_add( Connection *conn, Operation *op )
goto
done
;
}
if
(
global_readonly
||
be
->
be_readonly
)
{
Debug
(
LDAP_DEBUG_ANY
,
"do_add: database is read-only
\n
"
,
0
,
0
,
0
);
send_ldap_result
(
conn
,
op
,
rc
=
LDAP_UNWILLING_TO_PERFORM
,
NULL
,
"directory is read-only"
,
NULL
,
NULL
);
goto
done
;
}
/*
* do the add if 1 && (2 || 3)
* 1) there is an add function implemented in this backend;
...
...
servers/slapd/backend.c
View file @
bf3df2f7
...
...
@@ -39,12 +39,12 @@
#ifdef SLAPD_TCL
#include
"back-tcl/external.h"
#endif
#ifdef SLAPD_NTDOMAIN
#include
"back-domain/external.h"
#endif
#ifdef SLAPD_SQL
#include
"back-sql/external.h"
#endif
#ifdef SLAPD_PRIVATE
#include
"private/external.h"
#endif
static
BackendInfo
binfo
[]
=
{
#if defined(SLAPD_DNSSRV) && !defined(SLAPD_DNSSRV_DYNAMIC)
...
...
@@ -68,11 +68,12 @@ static BackendInfo binfo[] = {
#if defined(SLAPD_TCL) && !defined(SLAPD_TCL_DYNAMIC)
{
"tcl"
,
tcl_back_initialize
},
#endif
#if defined(SLAPD_NTDOMAIN) && !defined(SLAPD_NTDOMAIN_DYNAMIC)
{
"ntdom"
,
domain_back_initialize
},
#endif
#if defined(SLAPD_SQL) && !defined(SLAPD_SQL_DYNAMIC)
{
"sql"
,
sql_back_initialize
},
#endif
/* for any private backend */
#if defined(SLAPD_PRIVATE) && !defined(SLAPD_PRIVATE_DYNAMIC)
{
"private"
,
private_back_initialize
},
#endif
{
NULL
}
};
...
...
@@ -393,6 +394,9 @@ backend_db_init(
be
->
be_timelimit
=
deftime
;
be
->
be_dfltaccess
=
global_default_access
;
be
->
be_restrictops
=
global_restrictops
;
be
->
be_requires
=
global_requires
;
/* assign a default depth limit for alias deref */
be
->
be_max_deref_depth
=
SLAPD_DEFAULT_MAXDEREFDEPTH
;
...
...
@@ -584,7 +588,7 @@ backend_connection_destroy(
return
0
;
}
int
static
int
backend_check_controls
(
Backend
*
be
,
Connection
*
conn
,
...
...
@@ -609,6 +613,183 @@ backend_check_controls(
return
LDAP_SUCCESS
;
}
int
backend_check_restrictions
(
Backend
*
be
,
Connection
*
conn
,
Operation
*
op
,
const
char
*
extoid
,
const
char
**
text
)
{
int
rc
;
slap_mask_t
restrictops
;
slap_mask_t
requires
;
slap_mask_t
opflag
;
slap_ssf_set_t
*
ssf
;
int
updateop
=
0
;
if
(
be
)
{
rc
=
backend_check_controls
(
be
,
conn
,
op
,
text
);
if
(
rc
!=
LDAP_SUCCESS
)
{
return
rc
;
}
restrictops
=
be
->
be_restrictops
;
requires
=
be
->
be_requires
;
ssf
=
&
be
->
be_ssf_set
;
}
else
{
restrictops
=
global_restrictops
;
requires
=
global_requires
;
ssf
=
&
global_ssf_set
;
}
switch
(
op
->
o_tag
)
{
case
LDAP_REQ_ADD
:
opflag
=
SLAP_RESTRICT_OP_ADD
;
updateop
++
;
break
;
case
LDAP_REQ_BIND
:
opflag
=
SLAP_RESTRICT_OP_BIND
;
break
;
case
LDAP_REQ_COMPARE
:
opflag
=
SLAP_RESTRICT_OP_COMPARE
;
break
;
case
LDAP_REQ_DELETE
:
updateop
++
;
opflag
=
SLAP_RESTRICT_OP_DELETE
;
break
;
case
LDAP_REQ_EXTENDED
:
opflag
=
SLAP_RESTRICT_OP_EXTENDED
;
break
;
case
LDAP_REQ_MODIFY
:
updateop
++
;
opflag
=
SLAP_RESTRICT_OP_MODIFY
;
break
;
case
LDAP_REQ_RENAME
:
updateop
++
;
opflag
=
SLAP_RESTRICT_OP_RENAME
;
break
;
case
LDAP_REQ_SEARCH
:
opflag
=
SLAP_RESTRICT_OP_SEARCH
;
break
;
case
LDAP_REQ_UNBIND
:
opflag
=
0
;
break
;
default:
*
text
=
"restrict operations internal error"
;
return
LDAP_OTHER
;
}
if
(
(
extoid
==
NULL
||
strcmp
(
extoid
,
LDAP_EXOP_START_TLS
)
)
&&
op
->
o_tag
!=
LDAP_REQ_BIND
)
{
/* these checks don't apply to bind nor StartTLS */
if
(
op
->
o_tag
==
LDAP_REQ_EXTENDED
)
{
/* threat other extended operations as update ops */
updateop
++
;
}
if
(
op
->
o_ssf
<
ssf
->
sss_ssf
)
{
*
text
=
"confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_transport_ssf
<
ssf
->
sss_transport
)
{
*
text
=
"transport confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_tls_ssf
<
ssf
->
sss_tls
)
{
*
text
=
"TLS confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_sasl_ssf
<
ssf
->
sss_sasl
)
{
*
text
=
"SASL confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
updateop
)
{
if
(
op
->
o_ssf
<
ssf
->
sss_update_ssf
)
{
*
text
=
"update confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_transport_ssf
<
ssf
->
sss_update_transport
)
{
*
text
=
"transport update confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_tls_ssf
<
ssf
->
sss_update_tls
)
{
*
text
=
"TLS update confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
if
(
op
->
o_sasl_ssf
<
ssf
->
sss_update_sasl
)
{
*
text
=
"SASL update confidentiality required"
;
return
LDAP_CONFIDENTIALITY_REQUIRED
;
}
}
if
(
requires
&
SLAP_REQUIRE_STRONG
)
{
/* should check mechanism */
if
(
op
->
o_authmech
==
NULL
||
op
->
o_dn
==
NULL
||
*
op
->
o_dn
==
'\0'
)
{
*
text
=
"SASL authentication required"
;
return
LDAP_STRONG_AUTH_REQUIRED
;
}
}
if
(
requires
&
SLAP_REQUIRE_SASL
)
{
if
(
op
->
o_authmech
==
NULL
||
op
->
o_dn
==
NULL
||
*
op
->
o_dn
==
'\0'
)
{
*
text
=
"SASL authentication required"
;
return
LDAP_STRONG_AUTH_REQUIRED
;
}
}
if
(
requires
&
SLAP_REQUIRE_AUTHC
)
{
if
(
op
->
o_dn
==
NULL
||
*
op
->
o_dn
==
'\0'
)
{
*
text
=
"authentication required"
;
return
LDAP_UNWILLING_TO_PERFORM
;
}
}
if
(
requires
&
SLAP_REQUIRE_BIND
)
{
int
version
;
ldap_pvt_thread_mutex_lock
(
&
conn
->
c_mutex
);
version
=
conn
->
c_protocol
;
ldap_pvt_thread_mutex_unlock
(
&
conn
->
c_mutex
);
if
(
!
version
)
{
/* no bind has occurred */
*
text
=
"BIND required"
;
return
LDAP_OPERATIONS_ERROR
;
}
}
if
(
requires
&
SLAP_REQUIRE_LDAP_V3
)
{
if
(
op
->
o_protocol
<
LDAP_VERSION3
)
{
/* no bind has occurred */
*
text
=
"operation restricted to LDAPv3 clients"
;
return
LDAP_OPERATIONS_ERROR
;
}
}
}
if
(
restrictops
&
opflag
)
{
if
(
(
restrictops
&
SLAP_RESTRICT_OP_READS
)
==
SLAP_RESTRICT_OP_READS
)
{
*
text
=
"read operations restricted"
;
}
else
{
*
text
=
"operation restricted"
;
}
return
LDAP_UNWILLING_TO_PERFORM
;
}
return
LDAP_SUCCESS
;
}
int
backend_check_referrals
(
Backend
*
be
,
Connection
*
conn
,
...
...
servers/slapd/bind.c
View file @
bf3df2f7
...
...
@@ -59,6 +59,11 @@ do_bind(
* Force to connection to "anonymous" until bind succeeds.
*/
if
(
conn
->
c_authmech
!=
NULL
)
{
free
(
conn
->
c_authmech
);
conn
->
c_authmech
=
NULL
;
}
if
(
conn
->
c_cdn
!=
NULL
)
{
free
(
conn
->
c_cdn
);
conn
->
c_cdn
=
NULL
;
...
...
@@ -175,6 +180,13 @@ do_bind(
send_ldap_result
(
conn
,
op
,
rc
=
LDAP_PROTOCOL_ERROR
,
NULL
,
"requested protocol version not supported"
,
NULL
,
NULL
);
goto
cleanup
;
}
else
if
((
global_disallows
&
SLAP_DISALLOW_BIND_V2
)
&&
version
<
LDAP_VERSION3
)
{
send_ldap_result
(
conn
,
op
,
rc
=
LDAP_PROTOCOL_ERROR
,
NULL
,
"requested protocol version not allowed"
,
NULL
,
NULL
);
goto
cleanup
;
}
/* we set connection version regardless of whether bind succeeds
...
...
@@ -269,12 +281,34 @@ do_bind(
/* accept "anonymous" binds */
if
(
cred
.
bv_len
==
0
||
ndn
==
NULL
||
*
ndn
==
'\0'
)
{
rc
=
LDAP_SUCCESS
;
text
=
NULL
;
if
(
cred
.
bv_len
&&
(
global_disallows
&
SLAP_DISALLOW_BIND_ANON_CRED
))
{
/* cred is not empty, disallow */
rc
=
LDAP_INVALID_CREDENTIALS
;
}
else
if
(
ndn
!=
NULL
&&
*
ndn
!=
'\0'
&&
(
global_disallows
&
SLAP_DISALLOW_BIND_ANON_DN
))
{
/* DN is not empty, disallow */
rc
=
LDAP_UNWILLING_TO_PERFORM
;
text
=
"unwilling to allow anonymous bind with non-empty DN"
;
}
else
if
(
global_disallows
&
SLAP_DISALLOW_BIND_ANON
)
{
/* disallow */
rc
=
LDAP_UNWILLING_TO_PERFORM
;
text
=
"anonymous bind disallowed"
;
}
/*
* we already forced connection to "anonymous",
* just need to send success
*/
send_ldap_result
(
conn
,
op
,
LDAP_SUCCESS
,
NULL
,
NULL
,
NULL
,
NULL
);
send_ldap_result
(
conn
,
op
,
rc
,
NULL
,
text
,
NULL
,
NULL
);
Debug
(
LDAP_DEBUG_TRACE
,
"do_bind: v%d anonymous bind
\n
"
,
version
,
0
,
0
);
goto
cleanup
;
...
...
@@ -302,9 +336,8 @@ do_bind(
conn
->
c_authz_backend
=
be
;
/* make sure this backend recongizes critical controls */
rc
=
backend_check_controls
(
be
,
conn
,
op
,
&
text
)
;
/* check restrictions */
rc
=
backend_check_restrictions
(
be
,
conn
,
op
,
NULL
,
&
text
)
;
if
(
rc
!=
LDAP_SUCCESS
)
{
send_ldap_result
(
conn
,
op
,
rc
,
NULL
,
text
,
NULL
,
NULL
);
...
...
servers/slapd/compare.c
View file @
bf3df2f7
...
...
@@ -105,8 +105,8 @@ do_compare(
goto
cleanup
;
}
/*
make sure this backend recongizes c
riti
cal control
s */
rc
=
backend_check_
control
s
(
be
,
conn
,
op
,
&
text
)
;
/*
check rest
ri
c
ti
on
s */
rc
=
backend_check_
restriction
s
(
be
,
conn
,
op
,
NULL
,
&
text
)
;
if
(
rc
!=
LDAP_SUCCESS
)
{
send_ldap_result
(
conn
,
op
,
rc
,
NULL
,
text
,
NULL
,
NULL
);
...
...
servers/slapd/config.c
View file @
bf3df2f7
...
...
@@ -16,7 +16,7 @@
#include
"ldap_pvt.h"
#include
"slap.h"
#define MAXARGS 1
00
#define MAXARGS 1
28
/*
* defaults for various global variables
...
...
@@ -25,7 +25,10 @@ int defsize = SLAPD_DEFAULT_SIZELIMIT;
int
deftime
=
SLAPD_DEFAULT_TIMELIMIT
;
AccessControl
*
global_acl
=
NULL
;
slap_access_t
global_default_access
=
ACL_READ
;
int
global_readonly
=
0
;
slap_mask_t
global_restrictops
=
0
;
slap_mask_t
global_disallows
=
0
;
slap_mask_t
global_requires
=
0
;
slap_ssf_set_t
global_ssf_set
;
char
*
replogfile
;
int
global_lastmod
=
ON
;
int
global_idletimeout
=
0
;
...
...
@@ -451,15 +454,181 @@ read_config( const char *fname )
return
(
1
);
}
if
(
be
==
NULL
)
{
global_readonly
=
(
strcasecmp
(
cargv
[
1
],
"on"
)
==
0
);
if
(
strcasecmp
(
cargv
[
1
],
"on"
)
==
0
)
{
global_restrictops
|=
SLAP_RESTRICT_OP_WRITES
;
}
else
{
global_restrictops
&=
~
SLAP_RESTRICT_OP_WRITES
;
}
}
else
{
if
(
strcasecmp
(
cargv
[
1
],
"on"
)
==
0
)
{
be
->
be_re
adonly
=
1
;
be
->
be_re
strictops
|=
SLAP_RESTRICT_OP_WRITES
;
}
else
{
be
->
be_readonly
=
0
;
be
->
be_restrictops
&=
~
SLAP_RESTRICT_OP_WRITES
;
}
}
/* disallow these features */
}
else
if
(
strcasecmp
(
cargv
[
0
],
"disallows"
)
==
0
||
strcasecmp
(
cargv
[
0
],
"disallow"
)
==
0
)
{
slap_mask_t
disallows
;
if
(
be
!=
NULL
)
{
Debug
(
LDAP_DEBUG_ANY
,
"%s: line %d: disallow line must appear prior to database definitions
\n
"
,
fname
,
lineno
,
0
);
}
if
(
cargc
<
2
)
{
Debug
(
LDAP_DEBUG_ANY
,
"%s: line %d: missing feature(s) in
\"
disallows <features>
\"
line
\n
"
,
fname
,
lineno
,
0
);
return
(
1
);
}
disallows
=
0
;
for
(
i
=
1
;
i
<
cargc
;
i
++
)
{
if
(
strcasecmp
(
cargv
[
i
],
"bind_v2"
)
==
0
)
{
disallows
|=
SLAP_DISALLOW_BIND_V2
;
}
else
if
(
strcasecmp
(
cargv
[
i
],
"bind_anon_cred"
)
==
0
)
{
disallows
|=
SLAP_DISALLOW_BIND_ANON_CRED
;
}
else
if
(
strcasecmp
(
cargv
[
i
],
"bind_anon_dn"
)
==
0
)
{
disallows
|=
SLAP_DISALLOW_BIND_ANON_DN
;
}
else
if
(
strcasecmp
(
cargv
[
i
],
"none"
)
!=
0
)
{
Debug
(
LDAP_DEBUG_ANY
,
"%s: line %d: unknown feature %s in
\"
disallow <features>
\"
line
\n
"
,
fname
,
lineno
,
cargv
[
i
]
);
return
(
1
);
}
}
global_disallows
=
disallows
;
/* require these features */
}
else
if
(
strcasecmp
(
cargv
[
0
],
"requires"
)
==
0
||
strcasecmp
(
cargv
[
0
],
"require"
)
==
0
)