of stashing the struct stat. Should be safer.
332) You can now specifiy a host list instead of just a host or alias
in a privilege list. Ie: user=host1,host2,ALIAS,!host3 /bin/ls
+
+333) Stash the "safe" path to the command instead of stashing the struct
+ stat. Should be safer.
SUDOERS_MODE);
break;
- case SPOOF_ATTEMPT:
- (void) sprintf(p,
- "probable spoofing attempt; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=",
- tty, cwd, runas_user);
- break;
-
case BAD_STAMPDIR:
(void) sprintf(p,
"%s owned by non-root or not mode 0700; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=",
SUDOERS_MODE);
break;
- case SPOOF_ATTEMPT:
- (void) fprintf(stderr,
- "%s is not the same command that was validated, disallowing.\n",
- cmnd);
- break;
-
case BAD_STAMPDIR:
(void) fprintf(stderr,
"Timestamp directory has wrong permissions, ignoring.\n");
*/
case VALIDATE_ERROR:
case NO_SUDOERS_FILE:
- case SPOOF_ATTEMPT:
case BAD_STAMPDIR:
case BAD_STAMPFILE:
case BAD_ALLOCATION:
char *sudoers_args;
{
int plen;
+ static struct stat cst;
struct stat pst;
DIR *dirp;
struct dirent *dent;
char buf[MAXPATHLEN];
- static char *c;
+ static char *cmnd_base;
- /* don't bother with pseudo commands like "validate" */
+ /* Don't bother with pseudo commands like "validate" */
if (strchr(cmnd, '/') == NULL)
return(FALSE);
plen = strlen(path);
- /* only need to stat cmnd once since it never changes */
- if (cmnd_st.st_dev == 0) {
- if (stat(cmnd, &cmnd_st) < 0)
+ /* Only need to stat cmnd once since it never changes */
+ if (cst.st_dev == 0) {
+ if (stat(cmnd, &cst) == -1)
return(FALSE);
- if ((c = strrchr(cmnd, '/')) == NULL)
- c = cmnd;
+ if ((cmnd_base = strrchr(cmnd, '/')) == NULL)
+ cmnd_base = cmnd;
else
- c++;
+ cmnd_base++;
}
/*
*/
if (has_meta(path)) {
/*
- * Return true if fnmatch(3) succeeds and there are no args
- * (in sudoers or command) or if the args match;
+ * Return true if fnmatch(3) succeeds AND
+ * a) there are no args in sudoers OR
+ * b) there are no args on command line and none required by sudoers OR
+ * c) there are args in sudoers and on command line and they match
* else return false.
*/
- if (fnmatch(path, cmnd, FNM_PATHNAME))
+ if (fnmatch(path, cmnd, FNM_PATHNAME) != 0)
return(FALSE);
- if (!sudoers_args)
+ if (!sudoers_args ||
+ (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+ (sudoers_args && fnmatch(sudoers_args, user_args ? user_args : "",
+ 0) == 0)) {
+ if (cmnd_safe)
+ free(cmnd_safe);
+ cmnd_safe = estrdup(cmnd);
return(TRUE);
- else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
- return(TRUE);
- else if (sudoers_args)
- return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
- else
+ } else
return(FALSE);
} else {
+ /*
+ * No meta characters
+ * Check to make sure this is not a directory spec (doesn't end in '/')
+ */
if (path[plen - 1] != '/') {
char *p;
p = path;
else
p++;
- if (strcmp(c, p))
- return(FALSE);
-
- if (stat(path, &pst) < 0)
+ if (strcmp(cmnd_base, p) != 0 || stat(path, &pst) == -1)
return(FALSE);
/*
- * Return true if inode/device matches and there are no args
- * (in sudoers or command) or if the args match;
- * else return false.
+ * Return true if inode/device matches AND
+ * a) there are no args in sudoers OR
+ * b) there are no args on command line and none req by sudoers OR
+ * c) there are args in sudoers and on command line and they match
*/
- if (cmnd_st.st_dev != pst.st_dev || cmnd_st.st_ino != pst.st_ino)
+ if (cst.st_dev != pst.st_dev || cst.st_ino != pst.st_ino)
return(FALSE);
- if (!sudoers_args)
- return(TRUE);
- else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
+ if (!sudoers_args ||
+ (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+ (sudoers_args &&
+ fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+ if (cmnd_safe)
+ free(cmnd_safe);
+ cmnd_safe = estrdup(path);
return(TRUE);
- else if (sudoers_args)
- return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
- else
+ } else
return(FALSE);
}
strcat(buf, dent->d_name);
/* only stat if basenames are not the same */
- if (strcmp(c, dent->d_name))
+ if (strcmp(cmnd_base, dent->d_name))
continue;
- if (stat(buf, &pst) < 0)
+ if (stat(buf, &pst) == -1)
continue;
- if (cmnd_st.st_dev == pst.st_dev && cmnd_st.st_ino == pst.st_ino)
+ if (cst.st_dev == pst.st_dev && cst.st_ino == pst.st_ino) {
+ if (cmnd_safe)
+ free(cmnd_safe);
+ cmnd_safe = estrdup(buf);
break;
+ }
}
closedir(dirp);
/* get the domain name (if any) */
if (domain == (char *) -1) {
domain = (char *) emalloc(MAXHOSTNAMELEN);
- if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
+ if (getdomainname(domain, MAXHOSTNAMELEN) == -1 || *domain == '\0') {
(void) free(domain);
domain = NULL;
}
expand_match_list();
}
- cmnd_matches = TRUE;
- $$ = TRUE;
+ $$ = cmnd_matches = TRUE;
+ if (cmnd_safe)
+ free(cmnd_safe);
+ cmnd_safe = estrdup(cmnd);
}
| ALIAS {
if (printmatches == TRUE && in_alias == TRUE) {
struct passwd *user_pw_ent;
char *runas_user = RUNAS_DEFAULT;
char *cmnd = NULL;
+char *cmnd_safe = NULL;
char *cmnd_args = NULL;
char *tty = "unknown";
char *prompt;
char *shost;
char cwd[MAXPATHLEN];
FILE *sudoers_fp = NULL;
-struct stat cmnd_st;
static char *runas_homedir = NULL;
extern struct interface *interfaces;
extern int num_interfaces;
(void) sudo_setenv("HOME", runas_homedir);
#ifndef PROFILING
- if ((sudo_mode & MODE_BACKGROUND) && fork() > 0) {
+ if ((sudo_mode & MODE_BACKGROUND) && fork() > 0)
exit(0);
- } else {
- /*
- * Make sure we are not being spoofed. The stat should
- * be cheap enough to make this almost bulletproof.
- */
- if (cmnd_st.st_dev) {
- struct stat st;
-
- if (stat(cmnd, &st) < 0) {
- (void) fprintf(stderr, "%s: unable to stat %s: ",
- Argv[0], cmnd);
- perror("");
- exit(1);
- }
-
- if (st.st_dev != cmnd_st.st_dev ||
- st.st_ino != cmnd_st.st_ino) {
- /* log and send mail, then bitch */
- log_error(SPOOF_ATTEMPT);
- inform_user(SPOOF_ATTEMPT);
- exit(1);
- }
- }
- EXEC(cmnd, NewArgv); /* run the command */
- }
+ else
+ EXEC(cmnd_safe, NewArgv); /* run the command */
#else
exit(0);
#endif /* PROFILING */
#define SUDOERS_WRONG_OWNER ( 0x09 | GLOBAL_PROBLEM )
#define SUDOERS_WRONG_MODE ( 0x0A | GLOBAL_PROBLEM )
#define SUDOERS_NOT_FILE ( 0x0B | GLOBAL_PROBLEM )
-#define SPOOF_ATTEMPT 0x0C
-#define BAD_STAMPDIR 0x0D
-#define BAD_STAMPFILE 0x0E
-#define BAD_ALLOCATION 0x0F
+#define BAD_STAMPDIR 0x0C
+#define BAD_STAMPFILE 0x0D
+#define BAD_ALLOCATION 0x0E
#ifdef HAVE_KERB5
-#define GLOBAL_KRB5_INIT_ERR ( 0x10 | GLOBAL_PROBLEM )
+#define GLOBAL_KRB5_INIT_ERR ( 0x0F | GLOBAL_PROBLEM )
#endif /* HAVE_KERB5 */
/*
extern char *runas_user;
extern char *tty;
extern char *cmnd;
+extern char *cmnd_safe;
extern char *cmnd_args;
extern char *prompt;
-extern struct stat cmnd_st;
extern int Argc;
extern char **Argv;
extern int NewArgc;
short *yysslim;
YYSTYPE *yyvs;
int yystacksize;
-#line 659 "parse.yacc"
+#line 661 "parse.yacc"
typedef struct {
expand_match_list();
}
- cmnd_matches = TRUE;
- yyval.BOOLEAN = TRUE;
+ yyval.BOOLEAN = cmnd_matches = TRUE;
+ if (cmnd_safe)
+ free(cmnd_safe);
+ cmnd_safe = estrdup(cmnd);
}
break;
case 45:
-#line 481 "parse.yacc"
+#line 483 "parse.yacc"
{
if (printmatches == TRUE && in_alias == TRUE) {
append(yyvsp[0].string, &ga_list[ga_list_len-1].entries,
}
break;
case 46:
-#line 500 "parse.yacc"
+#line 502 "parse.yacc"
{
if (printmatches == TRUE && in_alias == TRUE) {
append(yyvsp[0].command.cmnd, &ga_list[ga_list_len-1].entries,
}
break;
case 49:
-#line 539 "parse.yacc"
+#line 541 "parse.yacc"
{ push; }
break;
case 50:
-#line 539 "parse.yacc"
+#line 541 "parse.yacc"
{
if (host_matches == TRUE &&
add_alias(yyvsp[-3].string, HOST_ALIAS) == FALSE)
}
break;
case 55:
-#line 555 "parse.yacc"
+#line 557 "parse.yacc"
{
push;
if (printmatches == TRUE) {
}
break;
case 56:
-#line 563 "parse.yacc"
+#line 565 "parse.yacc"
{
if (cmnd_matches == TRUE &&
add_alias(yyvsp[-3].string, CMND_ALIAS) == FALSE)
}
break;
case 57:
-#line 575 "parse.yacc"
+#line 577 "parse.yacc"
{ ; }
break;
case 61:
-#line 583 "parse.yacc"
+#line 585 "parse.yacc"
{
push;
if (printmatches == TRUE) {
}
break;
case 62:
-#line 591 "parse.yacc"
+#line 593 "parse.yacc"
{
if (runas_matches > 0 &&
add_alias(yyvsp[-3].string, RUNAS_ALIAS) == FALSE)
}
break;
case 65:
-#line 607 "parse.yacc"
+#line 609 "parse.yacc"
{ push; }
break;
case 66:
-#line 607 "parse.yacc"
+#line 609 "parse.yacc"
{
if (user_matches == TRUE &&
add_alias(yyvsp[-3].string, USER_ALIAS) == FALSE)
}
break;
case 67:
-#line 616 "parse.yacc"
+#line 618 "parse.yacc"
{ ; }
break;
case 70:
-#line 621 "parse.yacc"
+#line 623 "parse.yacc"
{
push;
}
break;
case 71:
-#line 623 "parse.yacc"
+#line 625 "parse.yacc"
{
pop;
if (user_matched == TRUE)
}
break;
case 72:
-#line 631 "parse.yacc"
+#line 633 "parse.yacc"
{
if (strcmp(yyvsp[0].string, user_name) == 0)
user_matches = TRUE;
}
break;
case 73:
-#line 636 "parse.yacc"
+#line 638 "parse.yacc"
{
if (usergr_matches(yyvsp[0].string, user_name))
user_matches = TRUE;
}
break;
case 74:
-#line 641 "parse.yacc"
+#line 643 "parse.yacc"
{
if (netgr_matches(yyvsp[0].string, NULL, user_name))
user_matches = TRUE;
}
break;
case 75:
-#line 646 "parse.yacc"
+#line 648 "parse.yacc"
{
/* could be an all-caps username */
if (find_alias(yyvsp[0].string, USER_ALIAS) == TRUE ||
}
break;
case 76:
-#line 653 "parse.yacc"
+#line 655 "parse.yacc"
{
user_matches = TRUE;
}
break;
-#line 1600 "sudo.tab.c"
+#line 1602 "sudo.tab.c"
}
yyssp -= yym;
yystate = *yyssp;
char *cmnd = NULL;
char *cmnd_args = NULL;
+char *cmnd_safe = NULL;
char *runas_user = RUNAS_DEFAULT;
char host[MAXHOSTNAMELEN];
char *shost;
char host[] = "";
char *shost = "";
char *cmnd = "";
+char *cmnd_safe = NULL;
char *cmnd_args = NULL;
struct passwd *user_pw_ent;