#!/usr/bin/perl use warnings; use strict; sub processline { my $user=shift; my $setup=shift; if (! getpwnam("$user")) { print STDERR "warning: user $user does not exist\n"; return } if (! -f "$setup") { print STDERR "warning: $setup does not exist, skipping\n"; return; } print "Processing $setup as user $user ...\n"; # su is not used because it passes arguments through the shell, # which is not safe for untrusted setup file names. defined(my $pid = fork) or die "Can’t fork: $!"; if (! $pid) { my ($uuid, $ugid) = (getpwnam($user))[2, 3]; $)="$ugid $ugid"; $(=$ugid; $<=$uuid; $>=$uuid; if ($< != $uuid || $> != $uuid || $( != $ugid || $) ne "$ugid $ugid") { die "failed to drop permissions to $user"; } %ENV=( PATH => $ENV{PATH}, HOME => (getpwnam($user))[7], ); exec("ikiwiki", "-setup", $setup, @ARGV); die "failed to run ikiwiki: $!"; } waitpid($pid,0); if ($?) { print STDERR "Processing $setup as user $user failed with code $?\n"; } } sub processlist { my $file=shift; my $forceuser=shift; my $list; open ($list, "<$file") || die "$file: $!"; while (<$list>) { chomp; s/^\s+//; s/\s+$//; next if /^#/ || ! length; if (/^([^\s]+)\s+([^\s]+)$/) { my $user=$1; my $setup=$2; if (defined $forceuser && $forceuser ne $user) { print STDERR "warning: in $file line $., attempt to set user to $user, but user forced to $forceuser. Skipping\n"; } processline($user, $setup); } elsif (/^([^\s]+)$/) { my $user=$1; my $home=(getpwnam($user))[7]; if (defined $home && -d $home) { my $dotfile="$home/.ikiwiki/wikilist"; if (-e $dotfile) { processlist($dotfile, $user); } } } } close $list; } my $wikilist="/etc/ikiwiki/wikilist"; if (-e $wikilist) { processlist($wikilist); }