/*
vipw, vigr edit the password or group file
with -s will edit shadow or gshadow file
-
+
Copyright (c) 1997 , Guy Maor <maor@ece.utexas.edu>
Copyright (c) 1999 - 2000, Marek Michałkiewicz
Copyright (c) 2002 - 2006, Tomasz Kłoczko
- Copyright (c) 2007 - 2008, Nicolas François
+ Copyright (c) 2007 - 2010, Nicolas François
All rights reserved.
This program is free software; you can redistribute it and/or modify
#include <errno.h>
#include <getopt.h>
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif /* WITH_SELINUX */
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <utime.h>
#include "defines.h"
-#include "exitcodes.h"
#include "groupio.h"
#include "nscd.h"
#include "prototypes.h"
#include "pwio.h"
#include "sgroupio.h"
#include "shadowio.h"
+/*@-exitarg@*/
+#include "exitcodes.h"
+#ifdef WITH_TCB
+#include <tcb.h>
+#include "tcbfuncs.h"
+#endif /* WITH_TCB */
#define MSG_WARN_EDIT_OTHER_FILE _( \
"You have modified %s.\n"\
/*
* Global variables
*/
-static const char *progname, *filename, *fileeditname;
+const char *Prog;
+
+static const char *filename, *fileeditname;
static bool filelocked = false;
static bool createedit = false;
static int (*unlock) (void);
static bool quiet = false;
+#ifdef WITH_TCB
+static const char *user = NULL;
+static bool tcb_mode = false;
+#define SHADOWTCB_SCRATCHDIR ":tmp"
+#endif /* WITH_TCB */
/* local function prototypes */
-static void usage (void);
+static void usage (int status);
static int create_backup_file (FILE *, const char *, struct stat *);
static void vipwexit (const char *msg, int syserr, int ret);
static void vipwedit (const char *, int (*)(void), int (*)(void));
/*
* usage - display usage message and exit
*/
-static void usage (void)
+static void usage (int status)
{
- (void)
- fputs (_("Usage: vipw [options]\n"
- "\n"
- "Options:\n"
- " -g, --group edit group database\n"
- " -h, --help display this help message and exit\n"
- " -p, --passwd edit passwd database\n"
- " -q, --quiet quiet mode\n"
- " -s, --shadow edit shadow or gshadow database\n"
- "\n"), stderr);
- exit (E_USAGE);
+ FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
+ (void) fputs (_("Usage: vipw [options]\n"
+ "\n"
+ "Options:\n"), usageout);
+ (void) fputs (_(" -g, --group edit group database\n"), usageout);
+ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
+ (void) fputs (_(" -p, --passwd edit passwd database\n"), usageout);
+ (void) fputs (_(" -q, --quiet quiet mode\n"), usageout);
+ (void) fputs (_(" -s, --shadow edit shadow or gshadow database\n"), usageout);
+#ifdef WITH_TCB
+ (void) fputs (_(" -u, --user which user's tcb shadow file to edit\n"), usageout);
+#endif /* WITH_TCB */
+ (void) fputs (_("\n"), usageout);
+ exit (status);
}
/*
unlink (backup);
return -1;
}
+ if (fsync (fileno (bkfp)) != 0) {
+ (void) fclose (bkfp);
+ unlink (backup);
+ return -1;
+ }
if (fclose (bkfp) != 0) {
unlink (backup);
return -1;
if (createedit) {
if (unlink (fileeditname) != 0) {
- fprintf (stderr, _("%s: failed to remove %s\n"), progname, fileeditname);
+ fprintf (stderr, _("%s: failed to remove %s\n"), Prog, fileeditname);
/* continue */
}
}
if (filelocked) {
if ((*unlock) () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), progname, fileeditname);
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, fileeditname);
SYSLOG ((LOG_ERR, "failed to unlock %s", fileeditname));
/* continue */
}
}
if (NULL != msg) {
- fprintf (stderr, "%s: %s", progname, msg);
+ fprintf (stderr, "%s: %s", Prog, msg);
}
if (0 != syserr) {
fprintf (stderr, ": %s", strerror (err));
}
(void) fputs ("\n", stderr);
if (!quiet) {
- fprintf (stdout, _("%s: %s is unchanged\n"), progname,
+ fprintf (stdout, _("%s: %s is unchanged\n"), Prog,
filename);
}
exit (ret);
struct stat st1, st2;
int status;
FILE *f;
+ /* FIXME: the following should have variable sizes */
char filebackup[1024], fileedit[1024];
+ char *to_rename;
snprintf (filebackup, sizeof filebackup, "%s-", file);
- snprintf (fileedit, sizeof fileedit, "%s.edit", file);
+#ifdef WITH_TCB
+ if (tcb_mode) {
+ if ( (mkdir (TCB_DIR "/" SHADOWTCB_SCRATCHDIR, 0700) != 0)
+ && (errno != EEXIST)) {
+ vipwexit (_("failed to create scratch directory"), errno, 1);
+ }
+ if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
+ vipwexit (_("failed to drop privileges"), errno, 1);
+ }
+ snprintf (fileedit, sizeof fileedit,
+ TCB_DIR "/" SHADOWTCB_SCRATCHDIR "/.vipw.shadow.%s",
+ user);
+ } else {
+#endif /* WITH_TCB */
+ snprintf (fileedit, sizeof fileedit, "%s.edit", file);
+#ifdef WITH_TCB
+ }
+#endif /* WITH_TCB */
unlock = file_unlock;
filename = file;
fileeditname = fileedit;
if (access (file, F_OK) != 0) {
vipwexit (file, 1, 1);
}
+#ifdef WITH_SELINUX
+ /* if SE Linux is enabled then set the context of all new files
+ to be the context of the file we are editing */
+ if (is_selinux_enabled () != 0) {
+ security_context_t passwd_context=NULL;
+ int ret = 0;
+ if (getfilecon (file, &passwd_context) < 0) {
+ vipwexit (_("Couldn't get file context"), errno, 1);
+ }
+ ret = setfscreatecon (passwd_context);
+ freecon (passwd_context);
+ if (0 != ret) {
+ vipwexit (_("setfscreatecon () failed"), errno, 1);
+ }
+ }
+#endif /* WITH_SELINUX */
+#ifdef WITH_TCB
+ if (tcb_mode && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE)) {
+ vipwexit (_("failed to gain privileges"), errno, 1);
+ }
+#endif /* WITH_TCB */
if (file_lock () == 0) {
vipwexit (_("Couldn't lock file"), errno, 5);
}
filelocked = true;
+#ifdef WITH_TCB
+ if (tcb_mode && (shadowtcb_drop_priv () == SHADOWTCB_FAILURE)) {
+ vipwexit (_("failed to drop privileges"), errno, 1);
+ }
+#endif /* WITH_TCB */
/* edited copy has same owners, perm */
if (stat (file, &st1) != 0) {
if (NULL == f) {
vipwexit (file, 1, 1);
}
+#ifdef WITH_TCB
+ if (tcb_mode && (shadowtcb_gain_priv () == SHADOWTCB_FAILURE))
+ vipwexit (_("failed to gain privileges"), errno, 1);
+#endif /* WITH_TCB */
if (create_backup_file (f, fileedit, &st1) != 0) {
vipwexit (_("Couldn't make backup"), errno, 1);
}
+ (void) fclose (f);
createedit = true;
editor = getenv ("VISUAL");
snprintf (buf, strlen (editor) + strlen (fileedit) + 2,
"%s %s", editor, fileedit);
if (system (buf) != 0) {
- fprintf (stderr, "%s: %s: %s\n", progname, editor,
- strerror (errno));
+ fprintf (stderr, "%s: %s: %s\n", Prog, editor,
+ strerror (errno));
exit (1);
} else {
exit (0);
if ((pid != -1) && (WIFSTOPPED (status) != 0)) {
/* The child (editor) was suspended.
* Suspend vipw. */
- kill (getpid (), WSTOPSIG(status));
+ kill (getpid (), SIGSTOP);
/* wake child when resumed */
kill (pid, SIGCONT);
} else {
if (st1.st_mtime == st2.st_mtime) {
vipwexit (0, 0, 0);
}
+#ifdef WITH_SELINUX
+ /* unset the fscreatecon */
+ if (is_selinux_enabled () != 0) {
+ if (setfscreatecon (NULL) != 0) {
+ vipwexit (_("setfscreatecon () failed"), errno, 1);
+ }
+ }
+#endif /* WITH_SELINUX */
/*
* XXX - here we should check fileedit for errors; if there are any,
* without saving). Use pwck or grpck to do the check. --marekm
*/
createedit = false;
+#ifdef WITH_TCB
+ if (tcb_mode) {
+ f = fopen (fileedit, "r");
+ if (NULL == f) {
+ vipwexit (_("failed to open scratch file"), errno, 1);
+ }
+ if (unlink (fileedit) != 0) {
+ vipwexit (_("failed to unlink scratch file"), errno, 1);
+ }
+ if (shadowtcb_drop_priv () == SHADOWTCB_FAILURE) {
+ vipwexit (_("failed to drop privileges"), errno, 1);
+ }
+ if (stat (file, &st1) != 0) {
+ vipwexit (_("failed to stat edited file"), errno, 1);
+ }
+ to_rename = malloc (strlen (file) + 2);
+ if (NULL == to_rename) {
+ vipwexit (_("failed to allocate memory"), errno, 1);
+ }
+ snprintf (to_rename, strlen (file) + 2, "%s+", file);
+ if (create_backup_file (f, to_rename, &st1) != 0) {
+ free (to_rename);
+ vipwexit (_("failed to create backup file"), errno, 1);
+ }
+ (void) fclose (f);
+ } else {
+#endif /* WITH_TCB */
+ to_rename = fileedit;
+#ifdef WITH_TCB
+ }
+#endif /* WITH_TCB */
unlink (filebackup);
link (file, filebackup);
- if (rename (fileedit, file) == -1) {
+ if (rename (to_rename, file) == -1) {
fprintf (stderr,
_("%s: can't restore %s: %s (your changes are in %s)\n"),
- progname, file, strerror (errno), fileedit);
+ Prog, file, strerror (errno), to_rename);
+#ifdef WITH_TCB
+ if (tcb_mode) {
+ free (to_rename);
+ }
+#endif /* WITH_TCB */
vipwexit (0, 0, 1);
}
+#ifdef WITH_TCB
+ if (tcb_mode) {
+ free (to_rename);
+ if (shadowtcb_gain_priv () == SHADOWTCB_FAILURE) {
+ vipwexit (_("failed to gain privileges"), errno, 1);
+ }
+ }
+#endif /* WITH_TCB */
+
if ((*file_unlock) () == 0) {
- fprintf (stderr, _("%s: failed to unlock %s\n"), progname, fileeditname);
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, fileeditname);
SYSLOG ((LOG_ERR, "failed to unlock %s", fileeditname));
/* continue */
}
(void) bindtextdomain (PACKAGE, LOCALEDIR);
(void) textdomain (PACKAGE);
- progname = ((a = strrchr (*argv, '/')) ? a + 1 : *argv);
- do_vipw = (strcmp (progname, "vigr") != 0);
+ Prog = ((a = strrchr (*argv, '/')) ? a + 1 : *argv);
+ do_vipw = (strcmp (Prog, "vigr") != 0);
OPENLOG (do_vipw ? "vipw" : "vigr");
{"passwd", no_argument, NULL, 'p'},
{"quiet", no_argument, NULL, 'q'},
{"shadow", no_argument, NULL, 's'},
+#ifdef WITH_TCB
+ {"user", required_argument, NULL, 'u'},
+#endif /* WITH_TCB */
{NULL, 0, NULL, '\0'}
};
- while ((c =
- getopt_long (argc, argv, "ghpqs",
- long_options, NULL)) != -1) {
+ while ((c = getopt_long (argc, argv,
+#ifdef WITH_TCB
+ "ghpqsu:",
+#else /* !WITH_TCB */
+ "ghpqs",
+#endif /* !WITH_TCB */
+ long_options, NULL)) != -1) {
switch (c) {
case 'g':
do_vipw = false;
break;
case 'h':
- usage ();
+ usage (E_SUCCESS);
break;
case 'p':
do_vipw = true;
case 's':
editshadow = true;
break;
+#ifdef WITH_TCB
+ case 'u':
+ user = optarg;
+ break;
+#endif /* WITH_TCB */
default:
- usage ();
+ usage (E_USAGE);
}
}
}
if (do_vipw) {
if (editshadow) {
- vipwedit (SHADOW_FILE, spw_lock, spw_unlock);
+#ifdef WITH_TCB
+ if (getdef_bool ("USE_TCB") && (NULL != user)) {
+ if (shadowtcb_set_user (user) == SHADOWTCB_FAILURE) {
+ fprintf (stderr,
+ _("%s: failed to find tcb directory for %s\n"),
+ Prog, user);
+ return E_SHADOW_NOTFOUND;
+ }
+ tcb_mode = true;
+ }
+#endif /* WITH_TCB */
+ vipwedit (spw_dbname (), spw_lock, spw_unlock);
printf (MSG_WARN_EDIT_OTHER_FILE,
- SHADOW_FILE,
- PASSWD_FILE,
+ spw_dbname (),
+ pw_dbname (),
"vipw");
} else {
- vipwedit (PASSWD_FILE, pw_lock, pw_unlock);
+ vipwedit (pw_dbname (), pw_lock, pw_unlock);
if (spw_file_present ()) {
printf (MSG_WARN_EDIT_OTHER_FILE,
- PASSWD_FILE,
- SHADOW_FILE,
+ pw_dbname (),
+ spw_dbname (),
"vipw -s");
}
}
} else {
#ifdef SHADOWGRP
if (editshadow) {
- vipwedit (SGROUP_FILE, sgr_lock, sgr_unlock);
+ vipwedit (sgr_dbname (), sgr_lock, sgr_unlock);
printf (MSG_WARN_EDIT_OTHER_FILE,
- SGROUP_FILE,
- GROUP_FILE,
+ sgr_dbname (),
+ gr_dbname (),
"vigr");
} else {
-#endif
- vipwedit (GROUP_FILE, gr_lock, gr_unlock);
+#endif /* SHADOWGRP */
+ vipwedit (gr_dbname (), gr_lock, gr_unlock);
#ifdef SHADOWGRP
if (sgr_file_present ()) {
printf (MSG_WARN_EDIT_OTHER_FILE,
- GROUP_FILE,
- SGROUP_FILE,
+ gr_dbname (),
+ sgr_dbname (),
"vigr -s");
}
}
-#endif
+#endif /* SHADOWGRP */
}
nscd_flush_cache ("passwd");
nscd_flush_cache ("group");
- exit (E_SUCCESS);
+ return E_SUCCESS;
}