fix FSF address
[opensuse:polkit-default-privs.git] / chkstat-polkit
1 #!/usr/bin/perl -w
2 # This module sets policykit permssions
3 # Copyright (C) 2008, 2009 SUSE Linux Products GmbH, Nuernberg, Germany.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 #
19 # Author: Ludwig Nussel  <lnussel@suse.de> 2008
20 #
21
22 use strict;
23 use File::Path;
24 use Digest::MD5 qw/md5_hex/;
25
26 my $polkit_public_dir = '/var/lib/PolicyKit-public';
27 my $polkit1_localauthority_dir = '/var/lib/polkit-1/localauthority/10-vendor.d';
28 my $suseconfig_dir = '/var/adm/SuSEconfig';
29 my $md5_dir = $suseconfig_dir.'/md5';
30 my $reload_file = '/var/lib/misc/PolicyKit.reload';
31
32 my $do_set;
33 # privilege => value
34 my %to_set;
35
36 if($#ARGV != -1 && $ARGV[0] eq '--help' ) {
37         print "USAGE: $0 [-set] <files...>\n";
38         exit 0;
39 }
40
41 if($#ARGV != -1 && $ARGV[0] eq '-set') {
42         $do_set = 1;
43         shift @ARGV;
44 }
45
46 if($#ARGV == -1) {
47         print STDERR "specify files\n";
48         exit 1;
49 }
50
51 my $policykit_ops = {
52         name => 'PolicyKit',
53         overridefile => sub {
54                 my $priv = shift;
55                 return $polkit_public_dir.'/'.$priv.'.defaults-override';
56         },
57         parse => sub {
58                 my $priv = shift;
59                 return shift;
60         },
61         create => sub {
62                 my $priv = shift;
63                 return shift;
64         },
65         pretty => sub {
66                 my $perms = shift;
67                 my @p = map { s/^auth/a/; s/_admin/a/; s/_self/s/; s/_keep/k/; s/_session/s/; s/_always/a/; $_ } split(/:/, $perms);
68                 return join(':', @p);
69         },
70 };
71
72 my $polkit1_ops = {
73         name => 'polkit1',
74         overridefile => sub {
75                 my $priv = shift;
76                 return $polkit1_localauthority_dir.'/'.$priv.'.pkla';
77         },
78         parse => sub {
79                 my $priv = shift;
80                 my @p;
81                 for(@_) {
82                         if(/^ResultAny=(.+)\n/) {
83                                 $p[0] = $1;
84                         } elsif(/^ResultInactive=(.+)\n/) {
85                                 $p[1] = $1;
86                         } elsif(/^ResultActive=(.+)\n/) {
87                                 $p[2] = $1;
88                         }
89                 }
90                 return join(':', @p) if ($p[0] && $p[1] && $p[2]);
91                 return undef;
92         },
93         convert => sub {
94                 my $perms = shift;
95                 my @p = map { s/^(auth_(?:admin|self)_keep).+$/$1/; s/_one_shot//; $_ } split(/:/, $perms);
96                 return join(':', @p);
97         },
98         create => sub {
99                 my $priv = shift;
100                 my $perms = shift;
101
102                 my @p = split(/:/, $perms);
103
104                 my $txt = "[$priv]\nIdentity=unix-group:*\nAction=$priv\n"
105                         . "ResultAny=$p[0]\nResultInactive=$p[1]\nResultActive=$p[2]\n";
106                 return $txt;
107         },
108         pretty => sub {
109                 my $perms = shift;
110                 my @p = map { s/^auth/a/; s/_admin/a/; s/_self/s/; s/_keep/k/; s/_session//; s/_always//; $_ } split(/:/, $perms);
111                 return join(':', @p);
112         },
113 };
114
115
116 sub override($$$)
117 {
118         my ($privilege, $perms, $ops) = @_;
119         my $overridefile = $ops->{overridefile}($privilege);
120         my $old_perms;
121         my @old_content;
122         if(-e $overridefile) {
123                 if(!open(F, '<', $overridefile)) {
124                         print STDERR "can't open $overridefile: $!, skip.\n";
125                         return;
126                 }
127                 @old_content = <F>;
128                 $old_perms = $ops->{parse}($privilege, @old_content);
129                 close F;
130         }
131
132         $perms = $ops->{convert}($perms) if $ops->{convert};
133
134         if(defined $old_perms && $perms eq $old_perms) {
135                 return;
136         }
137
138         if($do_set) {
139                 print $ops->{name}.": setting $privilege to ".$ops->{pretty}($perms).($old_perms?" (wrong setting ".$ops->{pretty}($old_perms).")\n":"\n");
140                 if(-e $overridefile) {
141                         if(!open(F, '<', $md5_dir.'/'.$overridefile)) {
142                                 print STDERR "$overridefile was created externally, skip.\n";
143                                 return;
144                         }
145                         my $should_digest = <F>;
146                         $should_digest = substr($should_digest, 0, 32);
147                         close F;
148                         my $digest = md5_hex(join('', @old_content));
149                         if($digest ne $should_digest) {
150                                 print "$should_digest $digest\n";
151                                 print STDERR "$overridefile was modifed externally, skip.\n";
152                                 return;
153                         }
154                 }
155                 if(!open(F, '>', $overridefile.'.new')) {
156                         print STDERR "can't create $overridefile.new: $!, skip.\n";
157                         return;
158                 }
159                 my $content = $ops->{create}($privilege, $perms);
160                 print F $content;
161                 close F;
162                 my $digest = md5_hex($content);
163                 if(!open(F, '>', $md5_dir.'/'.$overridefile)) {
164                         print STDERR "can't save md5 check for $privilege: $!\n";
165                         unlink($overridefile.".new");
166                         return;
167                 }
168                 print F $digest."  $overridefile\n";
169                 close F;
170                 rename($overridefile.'.new', $overridefile);
171         } else {
172                 print $ops->{name}.": $privilege should be ".$ops->{pretty}($perms).($old_perms?" (wrong setting ".$ops->{pretty}($old_perms).")\n":"\n");
173         }
174 }
175
176 if (-d $polkit_public_dir) {
177         mkpath($md5_dir.'/'.$polkit_public_dir) if $do_set;
178 } else {
179         $policykit_ops = undef;
180 }
181 mkpath($polkit1_localauthority_dir) if $do_set;
182 mkpath($md5_dir.'/'.$polkit1_localauthority_dir) if $do_set;
183
184 while(<>) {
185         chomp;
186         next unless $_;
187         next if(/^#/);
188         my ($privilege, $perms) = split(/\s+/);
189         if($perms !~ /:/) {
190                 $perms = $perms.':'.$perms.':'.$perms;
191         }
192         # backward compat with PolicyKit
193         my @p = map { s/^auth_(admin\|self)_keep$/auth_$1_keep_always/; $_ } split(/:/, $perms);
194         $perms = join(':', @p);
195         $to_set{$privilege} = $perms;
196 }
197
198 while (my ($privilege, $perms) = each %to_set) {
199         override($privilege, $perms, $policykit_ops) if defined $policykit_ops;
200         override($privilege, $perms, $polkit1_ops);
201 }
202
203 utime undef, undef, $reload_file if $do_set;