134 lines
4.3 KiB
C
134 lines
4.3 KiB
C
/* SPDX-License-Identifier: GPL-3.0-only */
|
|
/* SPDX-FileCopyrightText: 2026 afiw <afiw@linuxposting.xyz> */
|
|
|
|
/*
|
|
* can - query filesystem permissions
|
|
* Copyright (C) 2026 afiw <afiw@linuxposting.xyz>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, exclusively version 3 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "action.h"
|
|
#include "group.h"
|
|
#include "user.h"
|
|
|
|
enum lookup_mode: char {
|
|
LOOKUP_MODE_GID = 'G',
|
|
LOOKUP_MODE_GROUP = 'g',
|
|
LOOKUP_MODE_UID = 'U',
|
|
LOOKUP_MODE_USER = 'u' };
|
|
|
|
[[noreturn]] static void exit_with_usage(int ec) {
|
|
fprintf(ec == EXIT_SUCCESS ? stdout : stderr,
|
|
"usage: %s [-GghqU] [--gid] [--group] [--help] [--quiet] [--uid] user action path\n",
|
|
getprogname());
|
|
exit(ec); }
|
|
|
|
int main(int argc, char** argv) {
|
|
struct option const options[] = {
|
|
{ "gid", no_argument, nullptr, 'G' },
|
|
{ "group", no_argument, nullptr, 'g' },
|
|
{ "help", no_argument, nullptr, 'h' },
|
|
{ "quiet", no_argument, nullptr, 'q' },
|
|
{ "uid", no_argument, nullptr, 'U' } };
|
|
int flag;
|
|
enum lookup_mode lookup_mode = LOOKUP_MODE_USER;
|
|
char const* lookup;
|
|
enum action action;
|
|
char const* path;
|
|
struct passwd* passwd;
|
|
struct group* group;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
char const* errstr; /* for strtonum() */
|
|
bool quiet = false;
|
|
bool result;
|
|
#ifdef HAVE_PLEDGE
|
|
if (pledge("stdio rpath getpw", nullptr) == -1) {
|
|
err(EXIT_FAILURE, "pledge"); }
|
|
#endif
|
|
opterr = 0;
|
|
while ((flag = getopt_long(argc, argv, "GghqU", options, nullptr)) != -1) {
|
|
switch (flag) {
|
|
case '?':
|
|
warnx("unrecognized option: %c", optopt);
|
|
exit_with_usage(EXIT_FAILURE);
|
|
case 'G':
|
|
case 'g':
|
|
case 'U':
|
|
lookup_mode = flag;
|
|
break;
|
|
case 'h':
|
|
exit_with_usage(EXIT_SUCCESS);
|
|
case 'q':
|
|
quiet = true;
|
|
break;
|
|
default:
|
|
errx(EXIT_FAILURE, "getopt returned %c", flag); } }
|
|
if (argc != optind + 3) {
|
|
exit_with_usage(EXIT_FAILURE); }
|
|
lookup = argv[optind];
|
|
if ((action = action_of_cstring(argv[optind + 1])) == -1) {
|
|
warn("%s", argv[optind + 1]);
|
|
exit_with_usage(EXIT_FAILURE); }
|
|
path = argv[optind + 2];
|
|
switch (lookup_mode) {
|
|
case LOOKUP_MODE_GID:
|
|
gid = (gid_t)strtonum(lookup, 0, (gid_t)-1, &errstr);
|
|
if (errstr != nullptr) {
|
|
errx(EXIT_FAILURE, "%s: %s", lookup, errstr); }
|
|
errno = 0;
|
|
if ((group = getgrgid(gid)) == nullptr) {
|
|
if (errno == 0) {
|
|
errx(EXIT_FAILURE, "%d: No such group", gid); }
|
|
err(EXIT_FAILURE, "%d", gid); }
|
|
result = can_group(group, action, path);
|
|
break;
|
|
case LOOKUP_MODE_GROUP:
|
|
errno = 0;
|
|
if ((group = getgrnam(lookup)) == nullptr) {
|
|
if (errno == 0) {
|
|
errx(EXIT_FAILURE, "%s: No such group", lookup); }
|
|
err(EXIT_FAILURE, "%s", lookup); }
|
|
result = can_group(group, action, path);
|
|
break;
|
|
case LOOKUP_MODE_UID:
|
|
uid = (uid_t)strtonum(lookup, 0, (uid_t)-1, &errstr);
|
|
if (errstr != nullptr) {
|
|
errx(EXIT_FAILURE, "%s: %s", lookup, errstr); }
|
|
errno = 0;
|
|
if ((passwd = getpwuid(uid)) == nullptr) {
|
|
if (errno == 0) {
|
|
errx(EXIT_FAILURE, "%d: No such user", uid); }
|
|
err(EXIT_FAILURE, "%d", uid); }
|
|
result = can_user(passwd, action, path);
|
|
break;
|
|
case LOOKUP_MODE_USER:
|
|
errno = 0;
|
|
if ((passwd = getpwnam(lookup)) == nullptr) {
|
|
if (errno == 0) {
|
|
errx(EXIT_FAILURE, "%s: No such user", lookup); }
|
|
err(EXIT_FAILURE, "%s", lookup); }
|
|
result = can_user(passwd, action, path);
|
|
break; }
|
|
if (!quiet) {
|
|
printf(result ? "yes\n" : "no\n"); }
|
|
return result ? EXIT_SUCCESS : EXIT_FAILURE; }
|