/*
- * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
+ * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
- * This code is derived from software contributed by Chris Jepeway.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * 4. Products derived from this software may not be called "Sudo" nor
- * may "Sudo" appear in their names without specific prior written
- * permission from the author.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
-#include "config.h"
+#define _SUDO_MAIN
+
+#include <config.h>
#include <sys/param.h>
#include <sys/types.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_FNMATCH
# include <fnmatch.h>
-#endif /* HAVE_FNMATCH_H */
+#endif /* HAVE_FNMATCH */
#ifdef HAVE_NETGROUP_H
# include <netgroup.h>
#endif /* HAVE_NETGROUP_H */
+#ifdef HAVE_ERR_H
+# include <err.h>
+#else
+# include "emul/err.h"
+#endif /* HAVE_ERR_H */
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#endif /* HAVE_FNMATCH */
#ifndef lint
-static const char rcsid[] = "$Sudo: testsudoers.c,v 1.76 2002/03/16 00:44:48 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: testsudoers.c,v 1.88.2.5 2007/08/25 02:45:09 millert Exp $";
#endif /* lint */
*/
void init_parser __P((void));
void dumpaliases __P((void));
-void set_perms_dummy __P((int, int));
/*
* Globals
*/
-char **Argv, **NewArgv;
int Argc, NewArgc;
+char **Argv, **NewArgv;
int parse_error = FALSE;
int num_interfaces;
struct interface *interfaces;
struct sudo_user sudo_user;
-void (*set_perms) __P((int, int)) = set_perms_dummy;
extern int clearaliases;
extern int pedantic;
char *s;
{
char *t;
-
+
for (t = s; *t; t++) {
if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
return(TRUE);
}
/*
- * Returns TRUE if cmnd matches, in the sudo sense,
+ * Returns TRUE if user_cmnd matches, in the sudo sense,
* the pathname in path; otherwise, return FALSE
*/
int
-command_matches(cmnd, cmnd_args, path, sudoers_args)
- char *cmnd;
- char *cmnd_args;
+command_matches(path, sudoers_args)
char *path;
char *sudoers_args;
{
int clen, plen;
char *args;
- if (cmnd == NULL)
+ if (user_cmnd == NULL)
return(FALSE);
- if ((args = strchr(path, ' ')))
+ if ((args = strchr(path, ' ')))
*args++ = '\0';
if (has_meta(path)) {
- if (fnmatch(path, cmnd, FNM_PATHNAME))
+ if (fnmatch(path, user_cmnd, FNM_PATHNAME))
return(FALSE);
if (!sudoers_args)
return(TRUE);
- else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
+ else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
return(TRUE);
else if (sudoers_args)
- return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
+ return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
else
return(FALSE);
} else {
plen = strlen(path);
if (path[plen - 1] != '/') {
- if (strcmp(cmnd, path))
+ if (strcmp(user_cmnd, path))
return(FALSE);
if (!sudoers_args)
return(TRUE);
- else if (!cmnd_args && sudoers_args && !strcmp("\"\"", sudoers_args))
+ else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
return(TRUE);
else if (sudoers_args)
- return((fnmatch(sudoers_args, cmnd_args ? cmnd_args : "", 0) == 0));
+ return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
else
return(FALSE);
}
- clen = strlen(cmnd);
+ clen = strlen(user_cmnd);
if (clen < plen + 1)
- /* path cannot be the parent dir of cmnd */
+ /* path cannot be the parent dir of user_cmnd */
return(FALSE);
- if (strchr(cmnd + plen + 1, '/') != NULL)
- /* path could only be an anscestor of cmnd -- */
+ if (strchr(user_cmnd + plen + 1, '/') != NULL)
+ /* path could only be an anscestor of user_cmnd -- */
/* ignoring, of course, things like // & /./ */
return(FALSE);
- /* see whether path is the prefix of cmnd */
- return((strncmp(cmnd, path, plen) == 0));
+ /* see whether path is the prefix of user_cmnd */
+ return((strncmp(user_cmnd, path, plen) == 0));
}
}
-int
-addr_matches(n)
+static int
+addr_matches_if(n)
char *n;
{
int i;
+ struct in_addr addr;
+ struct interface *ifp;
+#ifdef AF_INET6
+ struct in6_addr addr6;
+ int j;
+#endif
+ int family;
+
+#ifdef AF_INET6
+ if (inet_pton(AF_INET6, n, &addr6) > 0) {
+ family = AF_INET6;
+ } else
+#endif
+ {
+ family = AF_INET;
+ addr.s_addr = inet_addr(n);
+ }
+
+ for (i = 0; i < num_interfaces; i++) {
+ ifp = &interfaces[i];
+ if (ifp->family != family)
+ continue;
+ switch(family) {
+ case AF_INET:
+ if (ifp->addr.ip4.s_addr == addr.s_addr ||
+ (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
+ == addr.s_addr)
+ return(TRUE);
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
+ sizeof(addr6.s6_addr)) == 0)
+ return(TRUE);
+ for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+ if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
+ break;
+ }
+ if (j == sizeof(addr6.s6_addr))
+ return(TRUE);
+#endif /* AF_INET6 */
+ }
+ }
+
+ return(FALSE);
+}
+
+static int
+addr_matches_if_netmask(n, m)
+ char *n;
char *m;
+{
+ int i;
struct in_addr addr, mask;
+ struct interface *ifp;
+#ifdef AF_INET6
+ struct in6_addr addr6, mask6;
+ int j;
+#endif
+ int family;
- /* If there's an explicit netmask, use it. */
- if ((m = strchr(n, '/'))) {
- *m++ = '\0';
+#ifdef AF_INET6
+ if (inet_pton(AF_INET6, n, &addr6) > 0)
+ family = AF_INET6;
+ else
+#endif
+ {
+ family = AF_INET;
addr.s_addr = inet_addr(n);
+ }
+
+ if (family == AF_INET) {
if (strchr(m, '.'))
mask.s_addr = inet_addr(m);
else {
mask.s_addr <<= i;
mask.s_addr = htonl(mask.s_addr);
}
- *(m - 1) = '/';
-
- for (i = 0; i < num_interfaces; i++)
- if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
- return(TRUE);
- } else {
- 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);
+ }
+#ifdef AF_INET6
+ else {
+ if (inet_pton(AF_INET6, m, &mask6) <= 0) {
+ j = atoi(m);
+ for (i = 0; i < 16; i++) {
+ if (j < i * 8)
+ mask6.s6_addr[i] = 0;
+ else if (i * 8 + 8 <= j)
+ mask6.s6_addr[i] = 0xff;
+ else
+ mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
+ }
+ }
+ }
+#endif /* AF_INET6 */
+
+ for (i = 0; i < num_interfaces; i++) {
+ ifp = &interfaces[i];
+ if (ifp->family != family)
+ continue;
+ switch(family) {
+ case AF_INET:
+ if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
+ return(TRUE);
+#ifdef AF_INET6
+ case AF_INET6:
+ for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+ if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
+ break;
+ }
+ if (j == sizeof(addr6.s6_addr))
+ return(TRUE);
+#endif /* AF_INET6 */
+ }
}
return(FALSE);
}
+/*
+ * Returns TRUE if "n" is one of our ip addresses or if
+ * "n" is a network that we are on, else returns FALSE.
+ */
+int
+addr_matches(n)
+ char *n;
+{
+ char *m;
+ int retval;
+
+ /* If there's an explicit netmask, use it. */
+ if ((m = strchr(n, '/'))) {
+ *m++ = '\0';
+ retval = addr_matches_if_netmask(n, m);
+ *(m - 1) = '/';
+ } else
+ retval = addr_matches_if(n);
+
+ return(retval);
+}
+
int
hostname_matches(shost, lhost, pattern)
char *shost;
char *lhost;
char *pattern;
{
- if (has_meta(pattern)) {
- if (strchr(pattern, '.'))
+ if (has_meta(pattern)) {
+ if (strchr(pattern, '.'))
return(fnmatch(pattern, lhost, FNM_CASEFOLD));
else
return(fnmatch(pattern, shost, FNM_CASEFOLD));
}
int
-usergr_matches(group, user)
+userpw_matches(sudoers_user, user, pw)
+ char *sudoers_user;
+ char *user;
+ struct passwd *pw;
+{
+ if (pw != NULL && *sudoers_user == '#') {
+ uid_t uid = atoi(sudoers_user + 1);
+ if (uid == pw->pw_uid)
+ return(1);
+ }
+ return(strcmp(sudoers_user, user) == 0);
+}
+
+int
+usergr_matches(group, user, pw)
char *group;
char *user;
+ struct passwd *pw;
{
struct group *grp;
char **cur;
if (*group++ != '%')
return(FALSE);
- if ((grp = getgrnam(group)) == NULL)
+ if ((grp = getgrnam(group)) == NULL)
return(FALSE);
/*
domain = (char *) emalloc(MAXHOSTNAMELEN);
if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
- free(domain);
+ efree(domain);
domain = NULL;
}
}
}
void
-set_perms_dummy(i, j)
- int i, j;
+set_perms(i)
+ int i;
{
return;
}
return;
}
+int
+set_runaspw(user)
+ char *user;
+{
+ return(TRUE);
+}
+
void
init_envtables()
{
NewArgc = Argc - 3;
} else {
(void) fprintf(stderr,
- "usage: %s [-u user] <user> <host> <command> [args]\n", Argv[0]);
+ "usage: sudo [-u user] <user> <host> <command> [args]\n");
exit(1);
}
user_shost = user_host;
}
- /* Fill in cmnd_args from NewArgv. */
+ /* Fill in user_args from NewArgv. */
if (NewArgc > 1) {
- size_t size;
char *to, **from;
+ size_t size, n;
- size = (size_t) NewArgv[NewArgc-1] + strlen(NewArgv[NewArgc-1]) -
- (size_t) NewArgv[1] + 1;
+ size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
+ strlen(NewArgv[NewArgc-1]) + 1;
user_args = (char *) emalloc(size);
- for (to = user_args, from = &NewArgv[1]; *from; from++) {
+ for (to = user_args, from = NewArgv + 1; *from; from++) {
+ n = strlcpy(to, *from, size - (to - user_args));
+ if (n >= size - (to - user_args))
+ errx(1, "internal error, init_vars() overflow");
+ to += n;
*to++ = ' ';
- (void) strcpy(to, *from);
- to += strlen(*from);
}
+ *--to = '\0';
}
/* Initialize default values. */