Merge commit 'upstream/1.8.3'
[debian/sudo] / plugins / sudoers / visudo.c
index 43119e233c57e35517baedfe2e776a86d8dee974..e37f6d50fc14cdaf82bd2909bc84eba7e5f9a333 100644 (file)
@@ -256,6 +256,30 @@ main(int argc, char *argv[])
     exit(0);
 }
 
+/*
+ * List of editors that support the "+lineno" command line syntax.
+ * If an entry starts with '*' the tail end of the string is matched.
+ * No other wild cards are supported.
+ */
+static char *lineno_editors[] = {
+    "ex",
+    "nex",
+    "vi",
+    "nvi",
+    "vim",
+    "elvis",
+    "*macs",
+    "mg",
+    "vile",
+    "jove",
+    "pico",
+    "nano",
+    "ee",
+    "joe",
+    "zile",
+    NULL
+};
+
 /*
  * Edit each sudoers file.
  * Returns TRUE on success, else FALSE.
@@ -276,11 +300,7 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno)
     ssize_t nread;                     /* number of bytes read */
     struct stat sb;                    /* stat buffer */
 
-#ifdef HAVE_FSTAT
     if (fstat(sp->fd, &sb) == -1)
-#else
-    if (stat(sp->path, &sb) == -1)
-#endif
        error(1, _("unable to stat %s"), sp->path);
     orig_size = sb.st_size;
     mtim_get(&sb, &orig_mtim);
@@ -310,6 +330,34 @@ edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno)
     }
     (void) touch(-1, sp->tpath, &orig_mtim);
 
+    /* Does the editor support +lineno? */
+    if (lineno > 0)
+    {
+       char *editor_base = strrchr(editor, '/');
+       if (editor_base != NULL)
+           editor_base++;
+       else
+           editor_base = editor;
+       if (*editor_base == 'r')
+           editor_base++;
+
+       for (av = lineno_editors; (cp = *av) != NULL; av++) {
+           /* We only handle a leading '*' wildcard. */
+           if (*cp == '*') {
+               size_t blen = strlen(editor_base);
+               size_t clen = strlen(++cp);
+               if (blen >= clen) {
+                   if (strcmp(cp, editor_base + blen - clen) == 0)
+                       break;
+               }
+           } else if (strcmp(cp, editor_base) == 0)
+               break;
+       }
+       /* Disable +lineno if editor doesn't support it. */
+       if (cp == NULL)
+           lineno = -1;
+    }
+
     /* Find the length of the argument vector */
     ac = 3 + (lineno > 0);
     if (args) {
@@ -492,23 +540,19 @@ install_sudoers(struct sudoersfile *sp, int oldperms)
      */
     if (oldperms) {
        /* Use perms of the existing file.  */
-#ifdef HAVE_FSTAT
        if (fstat(sp->fd, &sb) == -1)
-#else
-       if (stat(sp->path, &sb) == -1)
-#endif
            error(1, _("unable to stat %s"), sp->path);
        if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) {
-           warning(_("unable to set (uid, gid) of %s to (%d, %d)"),
-               sp->tpath, sb.st_uid, sb.st_gid);
+           warning(_("unable to set (uid, gid) of %s to (%u, %u)"),
+               sp->tpath, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid);
        }
        if (chmod(sp->tpath, sb.st_mode & 0777) != 0) {
            warning(_("unable to change mode of %s to 0%o"), sp->tpath,
-               (sb.st_mode & 0777));
+               (unsigned int)(sb.st_mode & 0777));
        }
     } else {
        if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) {
-           warning(_("unable to set (uid, gid) of %s to (%d, %d)"),
+           warning(_("unable to set (uid, gid) of %s to (%u, %u)"),
                sp->tpath, SUDOERS_UID, SUDOERS_GID);
            return FALSE;
        }
@@ -724,17 +768,12 @@ check_syntax(char *sudoers_path, int quiet, int strict)
        }
     }
     /* Check mode and owner in strict mode. */
-#ifdef HAVE_FSTAT
-    if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0)
-#else
-    if (strict && yyin != stdin && stat(sudoers_path, &sb) == 0)
-#endif
-    {
+    if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0) {
        if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) {
            error = TRUE;
            if (!quiet) {
                fprintf(stderr,
-                   _("%s: wrong owner (uid, gid) should be (%d, %d)\n"),
+                   _("%s: wrong owner (uid, gid) should be (%u, %u)\n"),
                    sudoers_path, SUDOERS_UID, SUDOERS_GID);
                }
        }