]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - login-utils/vipw.c
Merge branch 'hardlink' of https://github.com/rudimeier/util-linux into hardlink
[thirdparty/util-linux.git] / login-utils / vipw.c
index 6ca5f8c1078057b714a859be5a42c519cdff34c6..2502fcb4eab540814ce6c5d3dd9f8f4102d7d01c 100644 (file)
  * - fixed strerr(errno) in gettext calls
  */
 
-/*
- * This command is deprecated.  The utility is in maintenance mode,
- * meaning we keep them in source tree for backward compatibility
- * only.  Do not waste time making this command better, unless the
- * fix is about security or other very critical issue.
- *
- * See Documentation/deprecated.txt for more information.
- */
-
 #include <errno.h>
 #include <fcntl.h>
 #include <paths.h>
@@ -70,6 +61,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <getopt.h>
 
 #include "c.h"
 #include "fileutils.h"
@@ -90,11 +82,11 @@ enum {
        VIPW,
        VIGR
 };
-int program;
-char orig_file[FILENAMELEN];   /* original file /etc/passwd or /etc/group */
-char *tmp_file;                        /* tmp file */
+static int program;
+static char orig_file[FILENAMELEN];    /* original file /etc/passwd or /etc/group */
+static char *tmp_file;                 /* tmp file */
 
-void pw_error __P((char *, int, int));
+void pw_error (char *, int, int);
 
 static void copyfile(int from, int to)
 {
@@ -108,6 +100,9 @@ static void copyfile(int from, int to)
 
        if (nr < 0)
                pw_error(orig_file, 1, 1);
+#ifdef HAVE_EXPLICIT_BZERO
+       explicit_bzero(buf, sizeof(buf));
+#endif
 }
 
 static void pw_init(void)
@@ -144,9 +139,8 @@ static FILE * pw_tmpfile(int lockfd)
 {
        FILE *fd;
        char *tmpname = NULL;
-       char *dir = "/etc";
 
-       if ((fd = xfmkstemp(&tmpname, dir)) == NULL) {
+       if ((fd = xfmkstemp(&tmpname, "/etc", ".vipw")) == NULL) {
                ulckpwdf();
                err(EXIT_FAILURE, _("can't open temporary file"));
        }
@@ -191,6 +185,7 @@ static void pw_write(void)
        }
        unlink(tmp_file);
        free(tmp_file);
+       tmp_file = NULL;
 }
 
 static void pw_edit(void)
@@ -214,8 +209,7 @@ static void pw_edit(void)
 
        if (!pid) {
                execlp(editor, p, tmp_file, NULL);
-               /* Shouldn't get here */
-               _exit(EXIT_FAILURE);
+               errexec(editor);
        }
        for (;;) {
                pid = waitpid(pid, &pstat, WUNTRACED);
@@ -243,7 +237,9 @@ pw_error(char *name, int err, int eval)
                        warn(NULL);
        }
        warnx(_("%s unchanged"), orig_file);
-       unlink(tmp_file);
+
+       if (tmp_file)
+               unlink(tmp_file);
        ulckpwdf();
        exit(eval);
 }
@@ -260,7 +256,7 @@ static void edit_file(int is_shadow)
        if (lckpwdf() < 0)
                err(EXIT_FAILURE, _("cannot get lock"));
 
-       passwd_file = open(orig_file, O_RDONLY, 0);
+       passwd_file = open(orig_file, O_RDONLY | O_CLOEXEC, 0);
        if (passwd_file < 0)
                err(EXIT_FAILURE, _("cannot open %s"), orig_file);
        tmp_fd = pw_tmpfile(passwd_file);
@@ -278,8 +274,8 @@ static void edit_file(int is_shadow)
        if (end.st_nlink == 0) {
                if (close_stream(tmp_fd) != 0)
                        err(EXIT_FAILURE, _("write error"));
-               tmp_fd = fopen(tmp_file, "r");
-               if (!tmp_file)
+               tmp_fd = fopen(tmp_file, "r" UL_CLOEXECSTR);
+               if (!tmp_fd)
                        err(EXIT_FAILURE, _("cannot open %s"), tmp_file);
                if (fstat(fileno(tmp_fd), &end))
                        pw_error(tmp_file, 1, 1);
@@ -302,19 +298,30 @@ static void edit_file(int is_shadow)
        ulckpwdf();
 }
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        fputs(USAGE_HEADER, out);
        fprintf(out, " %s\n", program_invocation_short_name);
+
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Edit the password or group file.\n"), out);
+
        fputs(USAGE_OPTIONS, out);
-       fputs(USAGE_HELP, out);
-       fputs(USAGE_VERSION, out);
-       fprintf(out, USAGE_MAN_TAIL("vipw(8)"));
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+       printf(USAGE_HELP_OPTIONS(16));
+       printf(USAGE_MAN_TAIL("vipw(8)"));
+       exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char *argv[])
 {
+       int c;
+       static const struct option longopts[] = {
+               {"version", no_argument, NULL, 'V'},
+               {"help", no_argument, NULL, 'h'},
+               {NULL, 0, NULL, 0}
+       };
+
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
@@ -328,15 +335,16 @@ int main(int argc, char *argv[])
                xstrncpy(orig_file, PASSWD_FILE, sizeof(orig_file));
        }
 
-       if (1 < argc) {
-               if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
+       while ((c = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
+               switch (c) {
+               case 'V':
                        printf(UTIL_LINUX_VERSION);
-                       exit(EXIT_SUCCESS);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+               default:
+                       errtryhelp(EXIT_FAILURE);
                }
-               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
-                       usage(stdout);
-               usage(stderr);
-       }
 
        edit_file(0);
 
@@ -349,17 +357,17 @@ int main(int argc, char *argv[])
        if (access(orig_file, F_OK) == 0) {
                char response[80];
 
-               printf((program == VIGR)
+               fputs((program == VIGR)
                       ? _("You are using shadow groups on this system.\n")
-                      : _("You are using shadow passwords on this system.\n"));
+                      : _("You are using shadow passwords on this system.\n"), stdout);
+
                /* TRANSLATORS: this program uses for y and n rpmatch(3),
                 * which means they can be translated. */
                printf(_("Would you like to edit %s now [y/n]? "), orig_file);
 
-               if (fgets(response, sizeof(response), stdin)) {
-                       if (rpmatch(response) == 1)
-                               edit_file(1);
-               }
+               if (fgets(response, sizeof(response), stdin) &&
+                   rpmatch(response) == RPMATCH_YES)
+                       edit_file(1);
        }
        exit(EXIT_SUCCESS);
 }