Allow a list of digests to be specified for a command.
This commit is contained in:
@@ -887,6 +887,9 @@ Digest_Spec ::= "sha224" ':' digest |
|
|||||||
"sha384" ':' digest |
|
"sha384" ':' digest |
|
||||||
"sha512" ':' digest
|
"sha512" ':' digest
|
||||||
|
|
||||||
|
Digest_List ::= Digest_Spec |
|
||||||
|
Digest_Spec ',' Digest_List
|
||||||
|
|
||||||
Cmnd_List ::= Cmnd |
|
Cmnd_List ::= Cmnd |
|
||||||
Cmnd ',' Cmnd_List
|
Cmnd ',' Cmnd_List
|
||||||
|
|
||||||
@@ -894,7 +897,7 @@ command name ::= file name |
|
|||||||
file name args |
|
file name args |
|
||||||
file name '""'
|
file name '""'
|
||||||
|
|
||||||
Cmnd ::= Digest_Spec? '!'* command name |
|
Cmnd ::= Digest_List? '!'* command name |
|
||||||
'!'* directory |
|
'!'* directory |
|
||||||
'!'* "sudoedit" |
|
'!'* "sudoedit" |
|
||||||
'!'* Cmnd_Alias
|
'!'* Cmnd_Alias
|
||||||
@@ -967,12 +970,17 @@ A fully-qualified path for
|
|||||||
is treated as an error by
|
is treated as an error by
|
||||||
\fBvisudo\fR.
|
\fBvisudo\fR.
|
||||||
.PP
|
.PP
|
||||||
If a
|
A
|
||||||
\fRcommand name\fR
|
\fRcommand name\fR
|
||||||
is prefixed with a
|
may be preceded by a
|
||||||
\fRDigest_Spec\fR,
|
\fRDigest_List\fR,
|
||||||
the command will only match successfully if it can be verified
|
a comma-separated list of one or more
|
||||||
using the specified SHA-2 digest.
|
\fRDigest_Spec\fR
|
||||||
|
entries.
|
||||||
|
If a
|
||||||
|
\fRDigest_List\fR
|
||||||
|
is present, the command will only match successfully if it can be verified
|
||||||
|
using one of the SHA-2 digests in the list.
|
||||||
The following digest formats are supported: sha224, sha256, sha384 and sha512.
|
The following digest formats are supported: sha224, sha256, sha384 and sha512.
|
||||||
The string may be specified in either hex or base64 format
|
The string may be specified in either hex or base64 format
|
||||||
(base64 is more compact).
|
(base64 is more compact).
|
||||||
|
@@ -852,6 +852,9 @@ Digest_Spec ::= "sha224" ':' digest |
|
|||||||
"sha384" ':' digest |
|
"sha384" ':' digest |
|
||||||
"sha512" ':' digest
|
"sha512" ':' digest
|
||||||
|
|
||||||
|
Digest_List ::= Digest_Spec |
|
||||||
|
Digest_Spec ',' Digest_List
|
||||||
|
|
||||||
Cmnd_List ::= Cmnd |
|
Cmnd_List ::= Cmnd |
|
||||||
Cmnd ',' Cmnd_List
|
Cmnd ',' Cmnd_List
|
||||||
|
|
||||||
@@ -859,7 +862,7 @@ command name ::= file name |
|
|||||||
file name args |
|
file name args |
|
||||||
file name '""'
|
file name '""'
|
||||||
|
|
||||||
Cmnd ::= Digest_Spec? '!'* command name |
|
Cmnd ::= Digest_List? '!'* command name |
|
||||||
'!'* directory |
|
'!'* directory |
|
||||||
'!'* "sudoedit" |
|
'!'* "sudoedit" |
|
||||||
'!'* Cmnd_Alias
|
'!'* Cmnd_Alias
|
||||||
@@ -931,12 +934,17 @@ A fully-qualified path for
|
|||||||
is treated as an error by
|
is treated as an error by
|
||||||
.Nm visudo .
|
.Nm visudo .
|
||||||
.Pp
|
.Pp
|
||||||
If a
|
A
|
||||||
.Li command name
|
.Li command name
|
||||||
is prefixed with a
|
may be preceded by a
|
||||||
.Li Digest_Spec ,
|
.Li Digest_List ,
|
||||||
the command will only match successfully if it can be verified
|
a comma-separated list of one or more
|
||||||
using the specified SHA-2 digest.
|
.Li Digest_Spec
|
||||||
|
entries.
|
||||||
|
If a
|
||||||
|
.Li Digest_List
|
||||||
|
is present, the command will only match successfully if it can be verified
|
||||||
|
using one of the SHA-2 digests in the list.
|
||||||
The following digest formats are supported: sha224, sha256, sha384 and sha512.
|
The following digest formats are supported: sha224, sha256, sha384 and sha512.
|
||||||
The string may be specified in either hex or base64 format
|
The string may be specified in either hex or base64 format
|
||||||
(base64 is more compact).
|
(base64 is more compact).
|
||||||
|
@@ -70,6 +70,7 @@ static void
|
|||||||
print_command_json(struct json_container *json, const char *name, bool negated)
|
print_command_json(struct json_container *json, const char *name, bool negated)
|
||||||
{
|
{
|
||||||
struct sudo_command *c = (struct sudo_command *)name;
|
struct sudo_command *c = (struct sudo_command *)name;
|
||||||
|
struct command_digest *digest;
|
||||||
struct json_value value;
|
struct json_value value;
|
||||||
char *cmnd = c->cmnd;
|
char *cmnd = c->cmnd;
|
||||||
const char *digest_name;
|
const char *digest_name;
|
||||||
@@ -85,7 +86,7 @@ print_command_json(struct json_container *json, const char *name, bool negated)
|
|||||||
value.type = JSON_STRING;
|
value.type = JSON_STRING;
|
||||||
value.u.string = cmnd;
|
value.u.string = cmnd;
|
||||||
|
|
||||||
if (!negated && c->digest == NULL) {
|
if (!negated && TAILQ_EMPTY(&c->digests)) {
|
||||||
/* Print as { "command": "command and args" } */
|
/* Print as { "command": "command and args" } */
|
||||||
sudo_json_add_value_as_object(json, "command", &value);
|
sudo_json_add_value_as_object(json, "command", &value);
|
||||||
} else {
|
} else {
|
||||||
@@ -93,11 +94,11 @@ print_command_json(struct json_container *json, const char *name, bool negated)
|
|||||||
sudo_json_open_object(json, NULL);
|
sudo_json_open_object(json, NULL);
|
||||||
sudo_json_add_value(json, "command", &value);
|
sudo_json_add_value(json, "command", &value);
|
||||||
|
|
||||||
/* Optional digest. */
|
/* Optional digest list. */
|
||||||
if (c->digest != NULL) {
|
TAILQ_FOREACH(digest, &c->digests, entries) {
|
||||||
digest_name = digest_type_to_name(c->digest->digest_type);
|
digest_name = digest_type_to_name(digest->digest_type);
|
||||||
value.type = JSON_STRING;
|
value.type = JSON_STRING;
|
||||||
value.u.string = c->digest->digest_str;
|
value.u.string = digest->digest_str;
|
||||||
sudo_json_add_value(json, digest_name, &value);
|
sudo_json_add_value(json, digest_name, &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -209,6 +209,52 @@ print_global_defaults_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree,
|
|||||||
debug_return_bool(!ferror(fp));
|
debug_return_bool(!ferror(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format a sudo_command as a string.
|
||||||
|
* Returns the formatted, dynamically allocated string or dies on error.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
format_cmnd(struct sudo_command *c, bool negated)
|
||||||
|
{
|
||||||
|
struct command_digest *digest;
|
||||||
|
char *buf, *cp;
|
||||||
|
size_t bufsiz;
|
||||||
|
int len;
|
||||||
|
debug_decl(format_cmnd, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
|
bufsiz = negated + strlen(c->cmnd) + 1;
|
||||||
|
if (c->args != NULL)
|
||||||
|
bufsiz += 1 + strlen(c->args);
|
||||||
|
TAILQ_FOREACH(digest, &c->digests, entries) {
|
||||||
|
bufsiz += strlen(digest_type_to_name(digest->digest_type)) + 1 +
|
||||||
|
strlen(digest->digest_str) + 1;
|
||||||
|
if (TAILQ_NEXT(digest, entries) != NULL)
|
||||||
|
bufsiz += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = malloc(bufsiz)) == NULL) {
|
||||||
|
sudo_fatalx(U_("%s: %s"), __func__,
|
||||||
|
U_("unable to allocate memory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = buf;
|
||||||
|
TAILQ_FOREACH(digest, &c->digests, entries) {
|
||||||
|
len = snprintf(cp, bufsiz - (cp - buf), "%s:%s%s ",
|
||||||
|
digest_type_to_name(digest->digest_type), digest->digest_str,
|
||||||
|
TAILQ_NEXT(digest, entries) ? "," : "");
|
||||||
|
if (len < 0 || len >= (int)bufsiz - (cp - buf))
|
||||||
|
sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||||
|
cp += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = snprintf(cp, bufsiz - (cp - buf), "%s%s%s%s", negated ? "!" : "",
|
||||||
|
c->cmnd, c->args ? " " : "", c->args ? c->args : "");
|
||||||
|
if (len < 0 || len >= (int)bufsiz - (cp - buf))
|
||||||
|
sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||||
|
|
||||||
|
debug_return_str(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print struct member in LDIF format as the specified attribute.
|
* Print struct member in LDIF format as the specified attribute.
|
||||||
* See print_member_int() in parse.c.
|
* See print_member_int() in parse.c.
|
||||||
@@ -219,7 +265,6 @@ print_member_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, char *name,
|
|||||||
{
|
{
|
||||||
struct alias *a;
|
struct alias *a;
|
||||||
struct member *m;
|
struct member *m;
|
||||||
struct sudo_command *c;
|
|
||||||
char *attr_val;
|
char *attr_val;
|
||||||
int len;
|
int len;
|
||||||
debug_decl(print_member_ldif, SUDOERS_DEBUG_UTIL);
|
debug_decl(print_member_ldif, SUDOERS_DEBUG_UTIL);
|
||||||
@@ -233,16 +278,7 @@ print_member_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree, char *name,
|
|||||||
print_attribute_ldif(fp, attr_name, "");
|
print_attribute_ldif(fp, attr_name, "");
|
||||||
break;
|
break;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
c = (struct sudo_command *)name;
|
attr_val = format_cmnd((struct sudo_command *)name, negated);
|
||||||
len = asprintf(&attr_val, "%s%s%s%s%s%s%s%s",
|
|
||||||
c->digest ? digest_type_to_name(c->digest->digest_type) : "",
|
|
||||||
c->digest ? ":" : "", c->digest ? c->digest->digest_str : "",
|
|
||||||
c->digest ? " " : "", negated ? "!" : "", c->cmnd,
|
|
||||||
c->args ? " " : "", c->args ? c->args : "");
|
|
||||||
if (len == -1) {
|
|
||||||
sudo_fatalx(U_("%s: %s"), __func__,
|
|
||||||
U_("unable to allocate memory"));
|
|
||||||
}
|
|
||||||
print_attribute_ldif(fp, attr_name, attr_val);
|
print_attribute_ldif(fp, attr_name, attr_val);
|
||||||
free(attr_val);
|
free(attr_val);
|
||||||
break;
|
break;
|
||||||
|
@@ -51,6 +51,7 @@ sudoers_format_member_int(struct sudo_lbuf *lbuf,
|
|||||||
struct alias *a;
|
struct alias *a;
|
||||||
struct member *m;
|
struct member *m;
|
||||||
struct sudo_command *c;
|
struct sudo_command *c;
|
||||||
|
struct command_digest *digest;
|
||||||
debug_decl(sudoers_format_member_int, SUDOERS_DEBUG_UTIL);
|
debug_decl(sudoers_format_member_int, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -63,10 +64,10 @@ sudoers_format_member_int(struct sudo_lbuf *lbuf,
|
|||||||
break;
|
break;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
c = (struct sudo_command *) name;
|
c = (struct sudo_command *) name;
|
||||||
if (c->digest != NULL) {
|
TAILQ_FOREACH(digest, &c->digests, entries) {
|
||||||
sudo_lbuf_append(lbuf, "%s:%s ",
|
sudo_lbuf_append(lbuf, "%s:%s%s ",
|
||||||
digest_type_to_name(c->digest->digest_type),
|
digest_type_to_name(digest->digest_type),
|
||||||
c->digest->digest_str);
|
digest->digest_str, TAILQ_NEXT(digest, entries) ? "," : "");
|
||||||
}
|
}
|
||||||
if (negated)
|
if (negated)
|
||||||
sudo_lbuf_append(lbuf, "!");
|
sudo_lbuf_append(lbuf, "!");
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2018
|
* Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2020
|
||||||
* Todd C. Miller <Todd.Miller@sudo.ws>
|
* Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
@@ -174,7 +174,8 @@ static struct command_digest *new_digest(int, char *);
|
|||||||
%type <string> timeoutspec
|
%type <string> timeoutspec
|
||||||
%type <string> notbeforespec
|
%type <string> notbeforespec
|
||||||
%type <string> notafterspec
|
%type <string> notafterspec
|
||||||
%type <digest> digest
|
%type <digest> digestspec
|
||||||
|
%type <digest> digestlist
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@@ -451,7 +452,7 @@ cmndspec : runasspec options cmndtag digcmnd {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
digest : SHA224_TOK ':' DIGEST {
|
digestspec : SHA224_TOK ':' DIGEST {
|
||||||
$$ = new_digest(SUDO_DIGEST_SHA224, $3);
|
$$ = new_digest(SUDO_DIGEST_SHA224, $3);
|
||||||
if ($$ == NULL) {
|
if ($$ == NULL) {
|
||||||
sudoerserror(N_("unable to allocate memory"));
|
sudoerserror(N_("unable to allocate memory"));
|
||||||
@@ -481,16 +482,25 @@ digest : SHA224_TOK ':' DIGEST {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
digestlist : digestspec
|
||||||
|
| digestlist ',' digestspec {
|
||||||
|
HLTQ_CONCAT($1, $3, entries);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
digcmnd : opcmnd {
|
digcmnd : opcmnd {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
| digest opcmnd {
|
| digestlist opcmnd {
|
||||||
|
struct sudo_command *c =
|
||||||
|
(struct sudo_command *) $2->name;
|
||||||
|
|
||||||
if ($2->type != COMMAND) {
|
if ($2->type != COMMAND) {
|
||||||
sudoerserror(N_("a digest requires a path name"));
|
sudoerserror(N_("a digest requires a path name"));
|
||||||
YYERROR;
|
YYERROR;
|
||||||
}
|
}
|
||||||
/* XXX - yuck */
|
HLTQ_TO_TAILQ(&c->digests, $1, entries);
|
||||||
((struct sudo_command *) $2->name)->digest = $1;
|
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -730,6 +740,7 @@ cmnd : ALL {
|
|||||||
}
|
}
|
||||||
c->cmnd = $1.cmnd;
|
c->cmnd = $1.cmnd;
|
||||||
c->args = $1.args;
|
c->args = $1.args;
|
||||||
|
TAILQ_INIT(&c->digests);
|
||||||
$$ = new_member((char *)c, COMMAND);
|
$$ = new_member((char *)c, COMMAND);
|
||||||
if ($$ == NULL) {
|
if ($$ == NULL) {
|
||||||
free(c);
|
free(c);
|
||||||
@@ -992,6 +1003,7 @@ new_digest(int digest_type, char *digest_str)
|
|||||||
debug_return_ptr(NULL);
|
debug_return_ptr(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HLTQ_INIT(digest, entries);
|
||||||
digest->digest_type = digest_type;
|
digest->digest_type = digest_type;
|
||||||
digest->digest_str = digest_str;
|
digest->digest_str = digest_str;
|
||||||
if (digest->digest_str == NULL) {
|
if (digest->digest_str == NULL) {
|
||||||
@@ -1080,13 +1092,15 @@ free_member(struct member *m)
|
|||||||
debug_decl(free_member, SUDOERS_DEBUG_PARSER);
|
debug_decl(free_member, SUDOERS_DEBUG_PARSER);
|
||||||
|
|
||||||
if (m->type == COMMAND) {
|
if (m->type == COMMAND) {
|
||||||
struct sudo_command *c = (struct sudo_command *)m->name;
|
struct command_digest *digest;
|
||||||
free(c->cmnd);
|
struct sudo_command *c = (struct sudo_command *)m->name;
|
||||||
free(c->args);
|
free(c->cmnd);
|
||||||
if (c->digest != NULL) {
|
free(c->args);
|
||||||
free(c->digest->digest_str);
|
while ((digest = TAILQ_FIRST(&c->digests)) != NULL) {
|
||||||
free(c->digest);
|
TAILQ_REMOVE(&c->digests, digest, entries);
|
||||||
}
|
free(digest->digest_str);
|
||||||
|
free(digest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(m->name);
|
free(m->name);
|
||||||
free(m);
|
free(m);
|
||||||
|
@@ -288,6 +288,110 @@ oom:
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a digest prefix is present, add it to struct command_digest_list
|
||||||
|
* and update cmnd to point to the command after the digest.
|
||||||
|
* Returns 1 if a digest was parsed, 0 if not and -1 on error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
sudo_ldap_extract_digest(char **cmnd, struct command_digest_list *digests)
|
||||||
|
{
|
||||||
|
char *ep, *cp = *cmnd;
|
||||||
|
struct command_digest *digest;
|
||||||
|
int digest_type = SUDO_DIGEST_INVALID;
|
||||||
|
debug_decl(sudo_ldap_extract_digest, SUDOERS_DEBUG_LDAP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for and extract a digest prefix, e.g.
|
||||||
|
* sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
|
||||||
|
*/
|
||||||
|
if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
|
||||||
|
switch (cp[3]) {
|
||||||
|
case '2':
|
||||||
|
if (cp[4] == '2' && cp[5] == '4')
|
||||||
|
digest_type = SUDO_DIGEST_SHA224;
|
||||||
|
else if (cp[4] == '5' && cp[5] == '6')
|
||||||
|
digest_type = SUDO_DIGEST_SHA256;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
if (cp[4] == '8' && cp[5] == '4')
|
||||||
|
digest_type = SUDO_DIGEST_SHA384;
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
if (cp[4] == '1' && cp[5] == '2')
|
||||||
|
digest_type = SUDO_DIGEST_SHA512;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (digest_type != SUDO_DIGEST_INVALID) {
|
||||||
|
cp += 6;
|
||||||
|
while (isblank((unsigned char)*cp))
|
||||||
|
cp++;
|
||||||
|
if (*cp == ':') {
|
||||||
|
cp++;
|
||||||
|
while (isblank((unsigned char)*cp))
|
||||||
|
cp++;
|
||||||
|
ep = cp;
|
||||||
|
while (*ep != '\0' && !isblank((unsigned char)*ep) && *ep != ',')
|
||||||
|
ep++;
|
||||||
|
if (isblank((unsigned char)*ep) || *ep == ',') {
|
||||||
|
if ((digest = malloc(sizeof(*digest))) == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__,
|
||||||
|
U_("unable to allocate memory"));
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
digest->digest_type = digest_type;
|
||||||
|
digest->digest_str = strndup(cp, (size_t)(ep - cp));
|
||||||
|
if (digest->digest_str == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__,
|
||||||
|
U_("unable to allocate memory"));
|
||||||
|
free(digest);
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
while (isblank((unsigned char)*ep))
|
||||||
|
ep++;
|
||||||
|
*cmnd = ep;
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
"%s digest %s for %s",
|
||||||
|
digest_type_to_name(digest_type),
|
||||||
|
digest->digest_str, cp);
|
||||||
|
TAILQ_INSERT_TAIL(digests, digest, entries);
|
||||||
|
debug_return_int(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a digest list is present, fill in struct command_digest_list
|
||||||
|
* and update cmnd to point to the command after the digest.
|
||||||
|
* Returns false on error, else true.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
sudo_ldap_extract_digests(char **cmnd, struct command_digest_list *digests)
|
||||||
|
{
|
||||||
|
char *cp = *cmnd;
|
||||||
|
int rc;
|
||||||
|
debug_decl(sudo_ldap_extract_digests, SUDOERS_DEBUG_LDAP);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rc = sudo_ldap_extract_digest(&cp, digests);
|
||||||
|
if (rc != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Check for additional digestspecs, separated by a comma. */
|
||||||
|
if (*cp != ',')
|
||||||
|
break;
|
||||||
|
do {
|
||||||
|
cp++;
|
||||||
|
} while (isblank((unsigned char)*cp));
|
||||||
|
}
|
||||||
|
*cmnd = cp;
|
||||||
|
|
||||||
|
debug_return_bool(rc != -1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert an LDAP sudoRole to a sudoers privilege.
|
* Convert an LDAP sudoRole to a sudoers privilege.
|
||||||
* Pass in struct berval ** for LDAP or char *** for SSSD.
|
* Pass in struct berval ** for LDAP or char *** for SSSD.
|
||||||
@@ -358,6 +462,7 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
|
|||||||
goto oom;
|
goto oom;
|
||||||
}
|
}
|
||||||
m->name = (char *)c;
|
m->name = (char *)c;
|
||||||
|
TAILQ_INIT(&c->digests);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Negated commands have precedence so insert them at the end. */
|
/* Negated commands have precedence so insert them at the end. */
|
||||||
@@ -481,17 +586,13 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
|
|||||||
if (cmndspec->tags.setenv == UNSPEC)
|
if (cmndspec->tags.setenv == UNSPEC)
|
||||||
cmndspec->tags.setenv = IMPLIED;
|
cmndspec->tags.setenv = IMPLIED;
|
||||||
} else {
|
} else {
|
||||||
struct command_digest digest;
|
|
||||||
char *args;
|
char *args;
|
||||||
|
|
||||||
m->type = COMMAND;
|
m->type = COMMAND;
|
||||||
|
|
||||||
/* Fill in command with optional digest. */
|
/* Fill in command with optional digests. */
|
||||||
if (sudo_ldap_extract_digest(&cmnd, &digest) != NULL) {
|
if (!sudo_ldap_extract_digests(&cmnd, &c->digests))
|
||||||
if ((c->digest = malloc(sizeof(*c->digest))) == NULL)
|
goto oom;
|
||||||
goto oom;
|
|
||||||
*c->digest = digest;
|
|
||||||
}
|
|
||||||
if ((args = strpbrk(cmnd, " \t")) != NULL) {
|
if ((args = strpbrk(cmnd, " \t")) != NULL) {
|
||||||
*args++ = '\0';
|
*args++ = '\0';
|
||||||
if ((c->args = strdup(args)) == NULL)
|
if ((c->args = strdup(args)) == NULL)
|
||||||
@@ -515,70 +616,3 @@ oom:
|
|||||||
}
|
}
|
||||||
debug_return_ptr(NULL);
|
debug_return_ptr(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If a digest prefix is present, fills in struct command_digest
|
|
||||||
* and returns a pointer to it, updating cmnd to point to the
|
|
||||||
* command after the digest.
|
|
||||||
*/
|
|
||||||
struct command_digest *
|
|
||||||
sudo_ldap_extract_digest(char **cmnd, struct command_digest *digest)
|
|
||||||
{
|
|
||||||
char *ep, *cp = *cmnd;
|
|
||||||
int digest_type = SUDO_DIGEST_INVALID;
|
|
||||||
debug_decl(sudo_ldap_check_command, SUDOERS_DEBUG_LDAP);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for and extract a digest prefix, e.g.
|
|
||||||
* sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
|
|
||||||
*/
|
|
||||||
if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
|
|
||||||
switch (cp[3]) {
|
|
||||||
case '2':
|
|
||||||
if (cp[4] == '2' && cp[5] == '4')
|
|
||||||
digest_type = SUDO_DIGEST_SHA224;
|
|
||||||
else if (cp[4] == '5' && cp[5] == '6')
|
|
||||||
digest_type = SUDO_DIGEST_SHA256;
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
if (cp[4] == '8' && cp[5] == '4')
|
|
||||||
digest_type = SUDO_DIGEST_SHA384;
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
if (cp[4] == '1' && cp[5] == '2')
|
|
||||||
digest_type = SUDO_DIGEST_SHA512;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (digest_type != SUDO_DIGEST_INVALID) {
|
|
||||||
cp += 6;
|
|
||||||
while (isblank((unsigned char)*cp))
|
|
||||||
cp++;
|
|
||||||
if (*cp == ':') {
|
|
||||||
cp++;
|
|
||||||
while (isblank((unsigned char)*cp))
|
|
||||||
cp++;
|
|
||||||
ep = cp;
|
|
||||||
while (*ep != '\0' && !isblank((unsigned char)*ep))
|
|
||||||
ep++;
|
|
||||||
if (*ep != '\0') {
|
|
||||||
digest->digest_type = digest_type;
|
|
||||||
digest->digest_str = strndup(cp, (size_t)(ep - cp));
|
|
||||||
if (digest->digest_str == NULL) {
|
|
||||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
|
||||||
debug_return_ptr(NULL);
|
|
||||||
}
|
|
||||||
cp = ep + 1;
|
|
||||||
while (isblank((unsigned char)*cp))
|
|
||||||
cp++;
|
|
||||||
*cmnd = cp;
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
|
||||||
"%s digest %s for %s",
|
|
||||||
digest_type_to_name(digest_type),
|
|
||||||
digest->digest_str, cp);
|
|
||||||
debug_return_ptr(digest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_return_ptr(NULL);
|
|
||||||
}
|
|
||||||
|
@@ -411,7 +411,7 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m)
|
|||||||
break;
|
break;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
c = (struct sudo_command *)m->name;
|
c = (struct sudo_command *)m->name;
|
||||||
if (command_matches(c->cmnd, c->args, c->digest))
|
if (command_matches(c->cmnd, c->args, &c->digests))
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -126,18 +126,18 @@ is_script(int fd)
|
|||||||
* Returns false on error, else true.
|
* Returns false on error, else true.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
open_cmnd(const char *path, const struct command_digest *digest, int *fdp)
|
open_cmnd(const char *path, const struct command_digest_list *digests, int *fdp)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
debug_decl(open_cmnd, SUDOERS_DEBUG_MATCH);
|
debug_decl(open_cmnd, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
/* Only open the file for fdexec or for digest matching. */
|
/* Only open the file for fdexec or for digest matching. */
|
||||||
if (def_fdexec != always && digest == NULL)
|
if (def_fdexec != always && TAILQ_EMPTY(digests))
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
|
|
||||||
fd = open(path, O_RDONLY|O_NONBLOCK);
|
fd = open(path, O_RDONLY|O_NONBLOCK);
|
||||||
# ifdef O_EXEC
|
# ifdef O_EXEC
|
||||||
if (fd == -1 && errno == EACCES && digest == NULL) {
|
if (fd == -1 && errno == EACCES && TAILQ_EMPTY(digests))
|
||||||
/* Try again with O_EXEC if no digest is specified. */
|
/* Try again with O_EXEC if no digest is specified. */
|
||||||
const int saved_errno = errno;
|
const int saved_errno = errno;
|
||||||
if ((fd = open(path, O_EXEC)) == -1)
|
if ((fd = open(path, O_EXEC)) == -1)
|
||||||
@@ -197,7 +197,7 @@ set_cmnd_fd(int fd)
|
|||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
command_matches_dir(const char *sudoers_dir, size_t dlen,
|
command_matches_dir(const char *sudoers_dir, size_t dlen,
|
||||||
const struct command_digest *digest)
|
const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
struct stat sudoers_stat;
|
struct stat sudoers_stat;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
@@ -233,7 +233,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Open the file for fdexec or for digest matching. */
|
/* Open the file for fdexec or for digest matching. */
|
||||||
if (!open_cmnd(buf, digest, &fd))
|
if (!open_cmnd(buf, digests, &fd))
|
||||||
continue;
|
continue;
|
||||||
if (!do_stat(fd, buf, &sudoers_stat))
|
if (!do_stat(fd, buf, &sudoers_stat))
|
||||||
continue;
|
continue;
|
||||||
@@ -241,7 +241,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
|
|||||||
if (user_stat == NULL ||
|
if (user_stat == NULL ||
|
||||||
(user_stat->st_dev == sudoers_stat.st_dev &&
|
(user_stat->st_dev == sudoers_stat.st_dev &&
|
||||||
user_stat->st_ino == sudoers_stat.st_ino)) {
|
user_stat->st_ino == sudoers_stat.st_ino)) {
|
||||||
if (digest != NULL && !digest_matches(fd, buf, digest))
|
if (!digest_matches(fd, buf, digests))
|
||||||
continue;
|
continue;
|
||||||
free(safe_cmnd);
|
free(safe_cmnd);
|
||||||
if ((safe_cmnd = strdup(buf)) == NULL) {
|
if ((safe_cmnd = strdup(buf)) == NULL) {
|
||||||
@@ -265,7 +265,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
|
command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
|
||||||
const struct command_digest *digest)
|
const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
struct stat sb; /* XXX - unused */
|
struct stat sb; /* XXX - unused */
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
@@ -282,12 +282,12 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
if (command_args_match(sudoers_cmnd, sudoers_args)) {
|
if (command_args_match(sudoers_cmnd, sudoers_args)) {
|
||||||
/* Open the file for fdexec or for digest matching. */
|
/* Open the file for fdexec or for digest matching. */
|
||||||
if (!open_cmnd(user_cmnd, digest, &fd))
|
if (!open_cmnd(user_cmnd, digests, &fd))
|
||||||
goto bad;
|
goto bad;
|
||||||
if (!do_stat(fd, user_cmnd, &sb))
|
if (!do_stat(fd, user_cmnd, &sb))
|
||||||
goto bad;
|
goto bad;
|
||||||
/* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
|
/* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
|
||||||
if (digest != NULL && !digest_matches(fd, user_cmnd, digest))
|
if (!digest_matches(fd, user_cmnd, digests))
|
||||||
goto bad;
|
goto bad;
|
||||||
set_cmnd_fd(fd);
|
set_cmnd_fd(fd);
|
||||||
|
|
||||||
@@ -305,7 +305,7 @@ bad:
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
||||||
const struct command_digest *digest)
|
const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
struct stat sudoers_stat;
|
struct stat sudoers_stat;
|
||||||
bool bad_digest = false;
|
bool bad_digest = false;
|
||||||
@@ -349,7 +349,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
if (strcmp(cp, user_cmnd) != 0)
|
if (strcmp(cp, user_cmnd) != 0)
|
||||||
continue;
|
continue;
|
||||||
/* Open the file for fdexec or for digest matching. */
|
/* Open the file for fdexec or for digest matching. */
|
||||||
if (!open_cmnd(cp, digest, &fd))
|
if (!open_cmnd(cp, digests, &fd))
|
||||||
continue;
|
continue;
|
||||||
if (!do_stat(fd, cp, &sudoers_stat))
|
if (!do_stat(fd, cp, &sudoers_stat))
|
||||||
continue;
|
continue;
|
||||||
@@ -357,7 +357,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
(user_stat->st_dev == sudoers_stat.st_dev &&
|
(user_stat->st_dev == sudoers_stat.st_dev &&
|
||||||
user_stat->st_ino == sudoers_stat.st_ino)) {
|
user_stat->st_ino == sudoers_stat.st_ino)) {
|
||||||
/* There could be multiple matches, check digest early. */
|
/* There could be multiple matches, check digest early. */
|
||||||
if (digest != NULL && !digest_matches(fd, cp, digest)) {
|
if (!digest_matches(fd, cp, digests)) {
|
||||||
bad_digest = true;
|
bad_digest = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -385,7 +385,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
/* If it ends in '/' it is a directory spec. */
|
/* If it ends in '/' it is a directory spec. */
|
||||||
dlen = strlen(cp);
|
dlen = strlen(cp);
|
||||||
if (cp[dlen - 1] == '/') {
|
if (cp[dlen - 1] == '/') {
|
||||||
if (command_matches_dir(cp, dlen, digest))
|
if (command_matches_dir(cp, dlen, digests))
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -399,14 +399,14 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Open the file for fdexec or for digest matching. */
|
/* Open the file for fdexec or for digest matching. */
|
||||||
if (!open_cmnd(cp, digest, &fd))
|
if (!open_cmnd(cp, digests, &fd))
|
||||||
continue;
|
continue;
|
||||||
if (!do_stat(fd, cp, &sudoers_stat))
|
if (!do_stat(fd, cp, &sudoers_stat))
|
||||||
continue;
|
continue;
|
||||||
if (user_stat == NULL ||
|
if (user_stat == NULL ||
|
||||||
(user_stat->st_dev == sudoers_stat.st_dev &&
|
(user_stat->st_dev == sudoers_stat.st_dev &&
|
||||||
user_stat->st_ino == sudoers_stat.st_ino)) {
|
user_stat->st_ino == sudoers_stat.st_ino)) {
|
||||||
if (digest != NULL && !digest_matches(fd, cp, digest))
|
if (!digest_matches(fd, cp, digests))
|
||||||
continue;
|
continue;
|
||||||
free(safe_cmnd);
|
free(safe_cmnd);
|
||||||
if ((safe_cmnd = strdup(cp)) == NULL) {
|
if ((safe_cmnd = strdup(cp)) == NULL) {
|
||||||
@@ -433,7 +433,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest *digest)
|
command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
struct stat sudoers_stat;
|
struct stat sudoers_stat;
|
||||||
const char *base;
|
const char *base;
|
||||||
@@ -444,7 +444,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
|
|||||||
/* If it ends in '/' it is a directory spec. */
|
/* If it ends in '/' it is a directory spec. */
|
||||||
dlen = strlen(sudoers_cmnd);
|
dlen = strlen(sudoers_cmnd);
|
||||||
if (sudoers_cmnd[dlen - 1] == '/')
|
if (sudoers_cmnd[dlen - 1] == '/')
|
||||||
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, digest));
|
debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, digests));
|
||||||
|
|
||||||
/* Only proceed if user_base and basename(sudoers_cmnd) match */
|
/* Only proceed if user_base and basename(sudoers_cmnd) match */
|
||||||
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
|
if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
|
||||||
@@ -455,7 +455,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
|
|
||||||
/* Open the file for fdexec or for digest matching. */
|
/* Open the file for fdexec or for digest matching. */
|
||||||
if (!open_cmnd(sudoers_cmnd, digest, &fd))
|
if (!open_cmnd(sudoers_cmnd, digests, &fd))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -476,7 +476,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
|
|||||||
}
|
}
|
||||||
if (!command_args_match(sudoers_cmnd, sudoers_args))
|
if (!command_args_match(sudoers_cmnd, sudoers_args))
|
||||||
goto bad;
|
goto bad;
|
||||||
if (digest != NULL && !digest_matches(fd, sudoers_cmnd, digest)) {
|
if (!digest_matches(fd, sudoers_cmnd, digests)) {
|
||||||
/* XXX - log functions not available but we should log very loudly */
|
/* XXX - log functions not available but we should log very loudly */
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -498,7 +498,7 @@ bad:
|
|||||||
* otherwise, return true if user_cmnd names one of the inodes in path.
|
* otherwise, return true if user_cmnd names one of the inodes in path.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest *digest)
|
command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
debug_decl(command_matches, SUDOERS_DEBUG_MATCH);
|
debug_decl(command_matches, SUDOERS_DEBUG_MATCH);
|
||||||
@@ -526,11 +526,11 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct
|
|||||||
* use glob(3) and/or fnmatch(3) to do the matching.
|
* use glob(3) and/or fnmatch(3) to do the matching.
|
||||||
*/
|
*/
|
||||||
if (def_fast_glob)
|
if (def_fast_glob)
|
||||||
rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args, digest);
|
rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args, digests);
|
||||||
else
|
else
|
||||||
rc = command_matches_glob(sudoers_cmnd, sudoers_args, digest);
|
rc = command_matches_glob(sudoers_cmnd, sudoers_args, digests);
|
||||||
} else {
|
} else {
|
||||||
rc = command_matches_normal(sudoers_cmnd, sudoers_args, digest);
|
rc = command_matches_normal(sudoers_cmnd, sudoers_args, digests);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 1996, 1998-2005, 2007-2019
|
* Copyright (c) 1996, 1998-2005, 2007-2020
|
||||||
* Todd C. Miller <Todd.Miller@sudo.ws>
|
* Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
@@ -41,61 +41,81 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "sudoers.h"
|
#include "sudoers.h"
|
||||||
|
#include "sudo_digest.h"
|
||||||
#include <gram.h>
|
#include <gram.h>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
digest_matches(int fd, const char *file, const struct command_digest *digest)
|
digest_matches(int fd, const char *file, const struct command_digest_list *digests)
|
||||||
{
|
{
|
||||||
|
unsigned int digest_type = SUDO_DIGEST_INVALID;
|
||||||
unsigned char *file_digest = NULL;
|
unsigned char *file_digest = NULL;
|
||||||
unsigned char *sudoers_digest = NULL;
|
unsigned char *sudoers_digest = NULL;
|
||||||
|
struct command_digest *digest;
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
size_t digest_len;
|
size_t digest_len;
|
||||||
debug_decl(digest_matches, SUDOERS_DEBUG_MATCH);
|
debug_decl(digest_matches, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
if (fd == -1)
|
if (TAILQ_EMPTY(digests)) {
|
||||||
goto done;
|
/* No digest, no problem. */
|
||||||
|
debug_return_bool(true);
|
||||||
file_digest = sudo_filedigest(fd, file, digest->digest_type, &digest_len);
|
|
||||||
if (lseek(fd, (off_t)0, SEEK_SET) == -1) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
|
|
||||||
"unable to rewind digest fd");
|
|
||||||
}
|
}
|
||||||
if (file_digest == NULL) {
|
|
||||||
/* Warning (if any) printed by sudo_filedigest() */
|
if (fd == -1) {
|
||||||
|
/* No file, no match. */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the command digest from ascii to binary. */
|
TAILQ_FOREACH(digest, digests, entries) {
|
||||||
if ((sudoers_digest = malloc(digest_len)) == NULL) {
|
/* Compute file digest if needed. */
|
||||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
if (digest->digest_type != digest_type) {
|
||||||
goto done;
|
free(file_digest);
|
||||||
}
|
file_digest = sudo_filedigest(fd, file, digest->digest_type,
|
||||||
if (strlen(digest->digest_str) == digest_len * 2) {
|
&digest_len);
|
||||||
/* Convert ascii hex to binary. */
|
if (lseek(fd, (off_t)0, SEEK_SET) == -1) {
|
||||||
unsigned int i;
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
|
||||||
for (i = 0; i < digest_len; i++) {
|
"unable to rewind digest fd");
|
||||||
const int h = hexchar(&digest->digest_str[i + i]);
|
}
|
||||||
if (h == -1)
|
if (file_digest == NULL) {
|
||||||
|
/* Warning (if any) printed by sudo_filedigest() */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
digest_type = digest->digest_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the command digest from ascii to binary. */
|
||||||
|
if ((sudoers_digest = malloc(digest_len)) == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (strlen(digest->digest_str) == digest_len * 2) {
|
||||||
|
/* Convert ascii hex to binary. */
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < digest_len; i++) {
|
||||||
|
const int h = hexchar(&digest->digest_str[i + i]);
|
||||||
|
if (h == -1)
|
||||||
|
goto bad_format;
|
||||||
|
sudoers_digest[i] = (unsigned char)h;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Convert base64 to binary. */
|
||||||
|
size_t len = base64_decode(digest->digest_str, sudoers_digest, digest_len);
|
||||||
|
if (len != digest_len) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"incorrect length for digest, expected %zu, got %zu",
|
||||||
|
digest_len, len);
|
||||||
goto bad_format;
|
goto bad_format;
|
||||||
sudoers_digest[i] = (unsigned char)h;
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (memcmp(file_digest, sudoers_digest, digest_len) == 0) {
|
||||||
/* Convert base64 to binary. */
|
matched = true;
|
||||||
size_t len = base64_decode(digest->digest_str, sudoers_digest, digest_len);
|
break;
|
||||||
if (len != digest_len) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
|
||||||
"incorrect length for digest, expected %zu, got %zu",
|
|
||||||
digest_len, len);
|
|
||||||
goto bad_format;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(file_digest, sudoers_digest, digest_len) == 0) {
|
|
||||||
matched = true;
|
|
||||||
} else {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO,
|
||||||
"%s digest mismatch for %s, expecting %s",
|
"%s digest mismatch for %s, expecting %s",
|
||||||
digest_type_to_name(digest->digest_type), file, digest->digest_str);
|
digest_type_to_name(digest->digest_type), file, digest->digest_str);
|
||||||
|
free(sudoers_digest);
|
||||||
|
sudoers_digest = NULL;
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 1996, 1998-2000, 2004, 2007-2018
|
* Copyright (c) 1996, 1998-2000, 2004, 2007-2020
|
||||||
* Todd C. Miller <Todd.Miller@sudo.ws>
|
* Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
@@ -105,20 +105,11 @@
|
|||||||
(cs1)->runasgrouplist != (cs2)->runasgrouplist)
|
(cs1)->runasgrouplist != (cs2)->runasgrouplist)
|
||||||
|
|
||||||
struct command_digest {
|
struct command_digest {
|
||||||
|
TAILQ_ENTRY(command_digest) entries;
|
||||||
unsigned int digest_type;
|
unsigned int digest_type;
|
||||||
char *digest_str;
|
char *digest_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* A command with option args and digest.
|
|
||||||
* XXX - merge into struct member
|
|
||||||
*/
|
|
||||||
struct sudo_command {
|
|
||||||
char *cmnd;
|
|
||||||
char *args;
|
|
||||||
struct command_digest *digest;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tags associated with a command.
|
* Tags associated with a command.
|
||||||
* Possible values: true, false, IMPLIED, UNSPEC.
|
* Possible values: true, false, IMPLIED, UNSPEC.
|
||||||
@@ -164,13 +155,14 @@ struct command_options {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tail queue list head structure.
|
* Tail queue list head structures.
|
||||||
*/
|
*/
|
||||||
TAILQ_HEAD(defaults_list, defaults);
|
TAILQ_HEAD(defaults_list, defaults);
|
||||||
TAILQ_HEAD(userspec_list, userspec);
|
TAILQ_HEAD(userspec_list, userspec);
|
||||||
TAILQ_HEAD(member_list, member);
|
TAILQ_HEAD(member_list, member);
|
||||||
TAILQ_HEAD(privilege_list, privilege);
|
TAILQ_HEAD(privilege_list, privilege);
|
||||||
TAILQ_HEAD(cmndspec_list, cmndspec);
|
TAILQ_HEAD(cmndspec_list, cmndspec);
|
||||||
|
TAILQ_HEAD(command_digest_list, command_digest);
|
||||||
STAILQ_HEAD(comment_list, sudoers_comment);
|
STAILQ_HEAD(comment_list, sudoers_comment);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -196,6 +188,16 @@ struct privilege {
|
|||||||
struct defaults_list defaults; /* list of sudoOptions */
|
struct defaults_list defaults; /* list of sudoOptions */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A command with option args and digest.
|
||||||
|
* XXX - merge into struct member
|
||||||
|
*/
|
||||||
|
struct sudo_command {
|
||||||
|
char *cmnd;
|
||||||
|
char *args;
|
||||||
|
struct command_digest_list digests;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure describing a linked list of Cmnd_Specs.
|
* Structure describing a linked list of Cmnd_Specs.
|
||||||
* XXX - include struct command_options instad of its contents inline
|
* XXX - include struct command_options instad of its contents inline
|
||||||
@@ -306,10 +308,10 @@ void reparent_parse_tree(struct sudoers_parse_tree *new_tree);
|
|||||||
bool addr_matches(char *n);
|
bool addr_matches(char *n);
|
||||||
|
|
||||||
/* match_command.c */
|
/* match_command.c */
|
||||||
bool command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest *digest);
|
bool command_matches(const char *sudoers_cmnd, const char *sudoers_args, const struct command_digest_list *digests);
|
||||||
|
|
||||||
/* match_digest.c */
|
/* match_digest.c */
|
||||||
bool digest_matches(int fd, const char *file, const struct command_digest *digest);
|
bool digest_matches(int fd, const char *file, const struct command_digest_list *digests);
|
||||||
|
|
||||||
/* match.c */
|
/* match.c */
|
||||||
struct group;
|
struct group;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
Cmnd_Alias LS = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
|
Cmnd_Alias LS = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1, sha224:d7910e1967342b4605cb73a550944044c631cd3514001900966962ac /bin/ls
|
||||||
Cmnd_Alias SH = sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM= /bin/sh
|
Cmnd_Alias SH = sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM=, sha256:1IXHRCxXgSnIEnb+xBz4PAfWaPdXIBWKFF0QCwxJ5G4= /bin/sh
|
||||||
|
|
||||||
millert ALL = LS, SH, sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
millert ALL = LS, SH, sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
||||||
|
@@ -3,13 +3,15 @@
|
|||||||
"LS": [
|
"LS": [
|
||||||
{
|
{
|
||||||
"command": "/bin/ls",
|
"command": "/bin/ls",
|
||||||
"sha224": "d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1"
|
"sha224": "d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1",
|
||||||
|
"sha224": "d7910e1967342b4605cb73a550944044c631cd3514001900966962ac"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"SH": [
|
"SH": [
|
||||||
{
|
{
|
||||||
"command": "/bin/sh",
|
"command": "/bin/sh",
|
||||||
"sha256": "hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM="
|
"sha256": "hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM=",
|
||||||
|
"sha256": "1IXHRCxXgSnIEnb+xBz4PAfWaPdXIBWKFF0QCwxJ5G4="
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@@ -4,8 +4,8 @@ objectClass: sudoRole
|
|||||||
cn: millert
|
cn: millert
|
||||||
sudoUser: millert
|
sudoUser: millert
|
||||||
sudoHost: ALL
|
sudoHost: ALL
|
||||||
sudoCommand: sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
|
sudoCommand: sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1, sha224:d7910e1967342b4605cb73a550944044c631cd3514001900966962ac /bin/ls
|
||||||
sudoCommand: sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM= /bin/sh
|
sudoCommand: sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM=, sha256:1IXHRCxXgSnIEnb+xBz4PAfWaPdXIBWKFF0QCwxJ5G4= /bin/sh
|
||||||
sudoCommand: sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
sudoCommand: sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
||||||
sudoOrder: 1
|
sudoOrder: 1
|
||||||
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
# sudoRole millert
|
# sudoRole millert
|
||||||
millert ALL = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1\
|
millert ALL = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1,\
|
||||||
/bin/ls, sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM= /bin/sh,\
|
sha224:d7910e1967342b4605cb73a550944044c631cd3514001900966962ac /bin/ls,\
|
||||||
|
sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM=,\
|
||||||
|
sha256:1IXHRCxXgSnIEnb+xBz4PAfWaPdXIBWKFF0QCwxJ5G4= /bin/sh,\
|
||||||
sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw\
|
sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw\
|
||||||
/bin/kill
|
/bin/kill
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
Parses OK.
|
Parses OK.
|
||||||
|
|
||||||
Cmnd_Alias LS = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
|
Cmnd_Alias LS = sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1, sha224:d7910e1967342b4605cb73a550944044c631cd3514001900966962ac /bin/ls
|
||||||
Cmnd_Alias SH = sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM= /bin/sh
|
Cmnd_Alias SH = sha256:hOtoe/iK6SlGg7w4BfZBBdSsXjUmTJ5+ts51yjh7vkM=, sha256:1IXHRCxXgSnIEnb+xBz4PAfWaPdXIBWKFF0QCwxJ5G4= /bin/sh
|
||||||
|
|
||||||
millert ALL = LS, SH, sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
millert ALL = LS, SH, sha512:srzYEQ2aqzm+it3f74opTMkIImZRLxBARVpb0g9RSouJYdLt7DTRMEY4Ry9NyaOiDoUIplpNjqYH0JMYPVdFnw /bin/kill
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
CMNDALIAS ALIAS = SHA224_TOK : DIGEST COMMAND
|
CMNDALIAS ALIAS = SHA224_TOK : DIGEST , SHA224_TOK : DIGEST COMMAND
|
||||||
CMNDALIAS ALIAS = SHA256_TOK : DIGEST COMMAND
|
CMNDALIAS ALIAS = SHA256_TOK : DIGEST , SHA256_TOK : DIGEST COMMAND
|
||||||
|
|
||||||
WORD(5) ALL = ALIAS , ALIAS , SHA512_TOK : DIGEST COMMAND
|
WORD(5) ALL = ALIAS , ALIAS , SHA512_TOK : DIGEST COMMAND
|
||||||
|
@@ -27,6 +27,5 @@ bool sudo_ldap_is_negated(char **valp);
|
|||||||
bool sudo_ldap_add_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
|
bool sudo_ldap_add_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
|
||||||
int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
|
int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
|
||||||
struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter);
|
struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter);
|
||||||
struct command_digest *sudo_ldap_extract_digest(char **cmnd, struct command_digest *digest);
|
|
||||||
|
|
||||||
#endif /* SUDOERS_LDAP_H */
|
#endif /* SUDOERS_LDAP_H */
|
||||||
|
Reference in New Issue
Block a user