/* * CU sudo version 1.4 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Please send bugs, changes, problems to sudo-bugs@cs.colorado.edu * ******************************************************************* * * testsudoers.c -- frontend for parser testing and developement. * * Chris Jepeway */ #ifndef lint static char rcsid[] = "$Id$"; #endif /* lint */ #include "config.h" #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_STRING_H # include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ #ifdef HAVE_FNMATCH_H # include #else # ifndef HAVE_FNMATCH # include "emul/fnmatch.h" # endif /* HAVE_FNMATCH */ #endif /* HAVE_FNMATCH_H */ #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) # include #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ #ifdef HAVE_NETGROUP_H # include #endif /* HAVE_NETGROUP_H */ #include #include #include #include #include #include #include #include #include #include "sudo.h" /* * Globals */ int parse_error = FALSE; extern int clearaliases; extern struct interface *interfaces; extern int num_interfaces; char *cmnd = NULL; char *runas_user = "root"; char host[MAXHOSTNAMELEN+1]; char *shost; char cwd[MAXPATHLEN+1]; struct passwd *user_pw_ent; char **Argv; int Argc; char **NewArgv; int NewArgc; uid_t uid; /* * return TRUE if cmnd matches, in the sudo sense, * the pathname in path; otherwise, return FALSE */ int command_matches(cmnd, user_args, path, sudoers_args) char *cmnd; char **user_args; char *path; char **sudoers_args; { int clen, plen; char *args; if (cmnd == NULL) return(FALSE); if ((args = strchr(path, ' '))) *args++ = '\0'; if (has_meta(path)) { if (fnmatch(path, cmnd, FNM_PATHNAME)) return(FALSE); if (!sudoers_args) return(TRUE); else if (user_args && sudoers_args) return(compare_args(user_args, sudoers_args)); else if (!user_args && sudoers_args && sudoers_args[0][0] == '\0' && sudoers_args[1] == NULL) return(TRUE); else return(FALSE); } else { plen = strlen(path); if (path[plen - 1] != '/') { if (strcmp(cmnd, path)) return(FALSE); if (!sudoers_args) return(TRUE); else if (user_args && sudoers_args) return(compare_args(user_args, sudoers_args)); else if (!user_args && sudoers_args && sudoers_args[0][0] == '\0' && sudoers_args[1] == NULL) return(TRUE); else return(FALSE); } clen = strlen(cmnd); if (clen < plen + 1) /* path cannot be the parent dir of cmnd */ return(FALSE); if (strchr(cmnd + plen + 1, '/') != NULL) /* path could only be an anscestor of cmnd -- */ /* ignoring, of course, things like // & /./ */ return(FALSE); /* see whether path is the prefix of cmnd */ return((strncmp(cmnd, path, plen) == 0)); } } int addr_matches(n) char *n; { int i; struct in_addr addr; addr.s_addr = inet_addr(n); for (i = 0; i < num_interfaces; i++) if (interfaces[i].addr.s_addr == addr.s_addr || (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr) == addr.s_addr) return(TRUE); return(FALSE); } int usergr_matches(group, user) char *group; char *user; { struct group *grpent; char **cur; /* make sure we have a valid usergroup, sudo style */ if (*group++ != '%') return(FALSE); if ((grpent = getgrnam(group)) == NULL) return(FALSE); /* * Check against user's real gid as well as group's user list */ if (getgid() == grpent->gr_gid) return(TRUE); for (cur=grpent->gr_mem; *cur; cur++) { if (strcmp(*cur, user) == 0) return(TRUE); } return(FALSE); } int netgr_matches(netgr, host, user) char *netgr; char *host; char *user; { #ifdef HAVE_GETDOMAINNAME static char *domain = (char *) -1; #else static char *domain = NULL; #endif /* HAVE_GETDOMAINNAME */ /* make sure we have a valid netgroup, sudo style */ if (*netgr++ != '+') return(FALSE); #ifdef HAVE_GETDOMAINNAME /* get the domain name (if any) */ if (domain == (char *) -1) { if ((domain = (char *) malloc(MAXHOSTNAMELEN + 1)) == NULL) { perror("malloc"); (void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]); exit(1); } if (getdomainname(domain, MAXHOSTNAMELEN + 1) != 0 || *domain == '\0') { (void) free(domain); domain = NULL; } } #endif /* HAVE_GETDOMAINNAME */ #ifdef HAVE_INNETGR return(innetgr(netgr, host, user, domain)); #else return(FALSE); #endif /* HAVE_INNETGR */ } void set_perms(i) int i; { return; } main(argc, argv) int argc; char **argv; { struct passwd pw_ent; char *p; #ifdef YYDEBUG extern int yydebug; yydebug = 1; #endif if (argc == 6 && strcmp(argv[1], "-u") == 0) { runas_user = argv[2]; } else if (argc != 4) { (void) fprintf(stderr, "usage: %s [-u user] \n", argv[0]); exit(1); } /* XXX - need to set NewArgv and NewArgc */ Argv = argv; Argc = argc; user_pw_ent = &pw_ent; /* need user_pw_ent->pw_name defined */ if (argc == 6) { cmnd = argv[3]; pw_ent.pw_name = argv[4]; strcpy(host, argv[5]); } else { cmnd = argv[1]; pw_ent.pw_name = argv[2]; strcpy(host, argv[3]); } if ((p = strchr(host, '.'))) { *p = '\0'; if ((shost = strdup(host)) == NULL) { perror("malloc"); (void) fprintf(stderr, "%s: cannot allocate memory!\n", Argv[0]); exit(1); } *p = '.'; } else { shost = &host[0]; } clearaliases = 0; load_interfaces(); if (yyparse() || parse_error) { (void) printf("doesn't parse.\n"); } else { (void) printf("parses OK.\n\n"); if (top == 0) (void) printf("User %s not found\n", pw_ent.pw_name); else while (top) { (void) printf("[%d]\n", top-1); (void) printf("user_match : %d\n", user_matches); (void) printf("host_match : %d\n", host_matches); (void) printf("cmnd_match : %d\n", cmnd_matches); (void) printf("no_passwd : %d\n", no_passwd); (void) printf("runas_match: %d\n", runas_matches); (void) printf("runas : %s\n", runas_user); top--; } } /* dump aliases */ (void) printf("Matching Aliases --\n"); dumpaliases(); } /* * Returns TRUE if "s" has shell meta characters in it, * else returns FALSE. */ int has_meta(s) char *s; { register char *t; for (t = s; *t; t++) { if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']') return(TRUE); } return(FALSE); } /* * Compare two arguments lists and return TRUE if they are * the same (inc. wildcard matches) or FALSE if they differ. */ int compare_args(user_args, sudoers_args) char **user_args; char **sudoers_args; { char **ua, **sa; for (ua=user_args, sa=sudoers_args; *ua && *sa; ua++, sa++) { /* only do wildcard match if there are meta chars */ /* XXX - is this really any faster than fnmatch() for all? */ if (has_meta(*sa)) { if (fnmatch(*sa, *ua, FNM_PATHNAME)) return(FALSE); } else { if (strcmp(*ua, *sa)) return(FALSE); } } /* return false unless we got to the end of each */ if (*ua || *sa) return(FALSE); else return(TRUE); }