addition to a per-machine local one. For the sake of this example
the site-wide I<sudoers> will be F</etc/sudoers> and the per-machine
one will be F</etc/sudoers.local>. To include F</etc/sudoers.local>
-from F</etc/sudoers> we would use the following line in F</etc/sudoers>:
+from within F</etc/sudoers> we would use the following line in F</etc/sudoers>:
#include /etc/sudoers.local
themselves include other files. A hard limit of 128 nested include
files is enforced to prevent include file loops.
+The filename may include the C<%h> escape, signifying the short form
+of the hostname. I.e., if the machine's hostname is "xerxes", then
+
+ #include /etc/sudoers.%h
+
+will cause B<sudo> to include the file F</etc/sudoers.xerxes>.
+
=head2 Other special characters and reserved words
The pound sign ('#') is used to indicate a comment (unless it is
char *base;
{
char *cp, *ep, *path;
- int len;
+ int len = 0, subst = 0;
+ size_t shost_len = 0;
/* Pull out path from #include line. */
cp = base + sizeof("#include");
while (isblank((unsigned char) *cp))
cp++;
ep = cp;
- while (*ep != '\0' && !isspace((unsigned char) *ep))
+ while (*ep != '\0' && !isspace((unsigned char) *ep)) {
+ if (ep[0] == '%' && ep[1] == 'h') {
+ shost_len = strlen(user_shost);
+ len += shost_len - 2;
+ subst = 1;
+ }
ep++;
+ }
/* Make a copy of path and return it. */
- len = (int)(ep - cp);
+ len += (int)(ep - cp);
if ((path = malloc(len + 1)) == NULL)
yyerror("unable to allocate memory");
- memcpy(path, cp, len);
- path[len] = '\0';
+ if (subst) {
+ /* substitute for %h */
+ char *pp = path;
+ while (cp < ep) {
+ if (cp[0] == '%' && cp[1] == 'h') {
+ memcpy(pp, user_shost, shost_len);
+ pp += shost_len;
+ cp += 2;
+ }
+ *pp++ = *cp++;
+ }
+ *pp = '\0';
+ } else {
+ memcpy(path, cp, len);
+ path[len] = '\0';
+ }
/* Push any excess characters (e.g. comment, newline) back to the lexer */
if (*ep != '\0')
static RETSIGTYPE quit __P((int));
static char *get_args __P((char *));
static char *get_editor __P((char **));
+static void get_hostname __P((void));
static char whatnow __P((void));
static int check_aliases __P((int));
static int check_syntax __P((char *, int, int));
sudo_setgrent();
/* Mock up a fake sudo_user struct. */
- user_host = user_shost = user_cmnd = "";
+ user_cmnd = "";
if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL)
errorx(1, "you don't exist in the passwd database");
+ get_hostname();
/* Setup defaults data structures. */
init_defaults();
return(*args ? args : NULL);
}
+/*
+ * Look up the hostname and set user_host and user_shost.
+ */
+static void
+get_hostname()
+{
+ char *p, thost[MAXHOSTNAMELEN + 1];
+
+ if (gethostname(thost, sizeof(thost)) != 0) {
+ user_host = user_shost = "localhost";
+ return;
+ }
+ thost[sizeof(thost) - 1] = '\0';
+ user_host = estrdup(thost);
+
+ if ((p = strchr(user_host, '.'))) {
+ *p = '\0';
+ user_shost = estrdup(user_host);
+ *p = '.';
+ } else {
+ user_shost = user_host;
+ }
+}
+
/*
* Iterate through the sudoers datastructures looking for undefined
* aliases or unused aliases.