#!/usr/bin/perl -T # checkperms: ensure as best we can that a given file can only be # modified by the given user (or the superuser, naturally). This # means checking file ownership and permissions all the way back to # the root directory. Pass the file by its absolute path. # example invocation: # checkperms dkg /home/dkg/.monkeysphere/authorized_user_ids # return values: zero if we believe the file and path can only be # modified by the user. non-zero otherwise. # see StrictModes in sshd_config(5) (and its implementation in # OpenSSH's secure_filename() in auth.c) for the initial # inspiration/rationale for this code. # Author: # Daniel Kahn Gillmor # Started on: 2009-07-31 11:10:16-0400 # License: GPL v3 or later use strict; use Cwd qw(realpath); # found in debian in perl-base use File::stat; # found in debian in perl-modules use User::pwent; # found in debian in perl-modules use Fcntl qw(:mode); # for S_IS* functions (in perl-base) use File::Basename; # for dirname (in perl-modules) my $username = shift; my $path = shift; defined($username) or die "You must pass a username and an absolute path.\n"; defined($path) or die "You must pass a username and an absolute path.\n"; my $pw = getpwnam($username) or die "no such user $username\n"; $path =~ m#^/# or die "path was not absolute (did not start with /)\n"; sub mslog { my $level = shift; # FIXME: check and compare the log level if ($ENV{LOG_LEVEL} eq 'DEBUG') { my $format = shift; my $out = sprintf($format, @_); $out =~ s/^/$ENV{LOG_PREFIX}/ ; printf STDERR "%s", $out; } } ## return undef if permissions are OK. otherwise return an error string sub permissions_ok { my $user = shift; my $path = shift; # if we can't even stat the path, the permissions are not ok: my $stat = lstat($path) or return "cannot stat '$path'"; while (S_ISLNK($stat->mode)) { my $newpath = realpath($path) or return "cannot trace symlink '$path'"; mslog('DEBUG', "tracing link %s to %s\n", $path, $newpath); $path = $newpath; $stat = lstat($path) or return "cannot stat '$path'"; } mslog('DEBUG', "checking '%s'\n", $path); if (($stat->uid != $user->uid) && ($stat->uid != 0)) { return sprintf("improper ownership on '%s': owner ID %d is neither %s (ID %d) nor the superuser", $path, $stat->uid, $user->name, $user->uid); } if ($stat->mode & S_IWGRP) { return sprintf("improper group writability on '%s'", $path); } if ($stat->mode & S_IWOTH) { return sprintf("improper other writability on '%s'", $path); } # see the rationalization in secure_filename() in auth.c in the # OpenSSH sources for an explanation of this bailout (see also # monkeysphere #675): if ($path eq $user->dir) { mslog('DEBUG', "stopping at %s's home directory '%s'\n", $user->name, $path); return undef; } my $nextlevel = dirname($path); if ($path eq $nextlevel) { # we bottom out at the root (/ in UNIX) return undef; } return permissions_ok($user, $nextlevel); } my $err = permissions_ok($pw, $path); if (defined($err)) { printf(STDERR "%s%s\n", $ENV{LOG_PREFIX}, $err); exit(1); } else { exit(0); } ue='8'>8space:mode:
authorJonas Smedegaard <dr@jones.dk>2023-06-27 09:35:08 +0200
committerJonas Smedegaard <dr@jones.dk>2023-06-27 09:35:08 +0200
commitfd54908da2b05c526dd3bee9b6dcd093214a220d (patch)
treec69c845069c99d1d01044f6fafda7c08433329c6 /tags/27/a7/20190523172729.9D3518C@jawa.homebase.dk/hb
parentba46132213560cf3335d53560d519c0ec0190da2 (diff)
master
Diffstat (limited to 'tags/27/a7/20190523172729.9D3518C@jawa.homebase.dk/hb')