diff --git a/usr.sbin/pw/pw.8 b/usr.sbin/pw/pw.8 --- a/usr.sbin/pw/pw.8 +++ b/usr.sbin/pw/pw.8 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 29, 2024 +.Dd August 19, 2025 .Dt PW 8 .Os .Sh NAME @@ -191,7 +191,12 @@ .Xr master.passwd 5 , .Xr group 5 and the secure and insecure -password database files, and must be run as root. +password database files, and must be run as root +.Po except when using +.Fl R +or +.Fl V +.Pc . .Pp The first one or two keywords provided to .Nm diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c --- a/usr.sbin/pw/pw.c +++ b/usr.sbin/pw/pw.c @@ -162,6 +162,7 @@ snprintf(conf.etcpath, sizeof(conf.etcpath), "%s%s", optarg, arg == 'R' ? _PATH_PWD : ""); + conf.altroot = true; } else break; } diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c --- a/usr.sbin/pw/pw_user.c +++ b/usr.sbin/pw/pw_user.c @@ -238,6 +238,13 @@ } } +static void +pw_check_root(void) +{ + if (!conf.altroot && geteuid() != 0) + errx(EX_NOPERM, "you must be root"); +} + /* * The M_LOCK and M_UNLOCK functions simply add or remove * a "*LOCKED*" prefix from in front of the password to @@ -256,8 +263,7 @@ bool locked = false; uid_t id = (uid_t)-1; - if (geteuid() != 0) - errx(EX_NOPERM, "you must be root"); + pw_check_root(); if (arg1 == NULL) errx(EX_DATAERR, "username or id required"); @@ -1324,8 +1330,8 @@ if (argc > 0) usage(); - if (geteuid() != 0 && ! dryrun) - errx(EX_NOPERM, "you must be root"); + if (!dryrun) + pw_check_root(); if (quiet) freopen(_PATH_DEVNULL, "w", stderr); @@ -1641,8 +1647,8 @@ if (argc > 0) usage(); - if (geteuid() != 0 && ! dryrun) - errx(EX_NOPERM, "you must be root"); + if (!dryrun) + pw_check_root(); if (quiet) freopen(_PATH_DEVNULL, "w", stderr); diff --git a/usr.sbin/pw/pwupd.h b/usr.sbin/pw/pwupd.h --- a/usr.sbin/pw/pwupd.h +++ b/usr.sbin/pw/pwupd.h @@ -78,6 +78,7 @@ char etcpath[MAXPATHLEN]; int fd; int rootfd; + bool altroot; bool checkduplicate; };