# /etc/wallet/wallet.conf -- Wallet system configuration. -*- perl -*- # $Id$ # # Configuration for the wallet system as used at Stanford University. # Interesting features to note are loading the database password from an # external file and full implementations of a naming policy check and default # ACL rules. # # Written by Russ Allbery # Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University # # See LICENSE for licensing terms. use Wallet::ACL; use Wallet::Database; $DB_DRIVER = 'mysql'; $DB_NAME = 'wallet'; $DB_HOST = 'localhost'; $DB_USER = 'wallet'; # Read the MySQL password from a separate file so that we don't have to commit # it to the Puppet repository. open (PASS, '<', '/etc/wallet/mysql-password') or die "cannot open /etc/wallet/mysql-password: $!\n"; $DB_PASSWORD = ; close PASS; chomp $DB_PASSWORD; $KEYTAB_FILE = '/etc/wallet/keytab'; $KEYTAB_FLAGS = '-clearpolicy'; $KEYTAB_HOST = 'krb5-admin.stanford.edu'; $KEYTAB_PRINCIPAL = 'service/wallet@stanford.edu'; $KEYTAB_REALM = 'stanford.edu'; $KEYTAB_TMP = '/var/lib/wallet'; $KEYTAB_REMCTL_CACHE = '/var/lib/wallet/krb5cc_wallet'; $KEYTAB_REMCTL_HOST = 'kerberos1.stanford.edu'; $NETDB_REALM = 'stanford.edu'; $NETDB_REMCTL_CACHE = '/var/lib/wallet/krb5cc_wallet'; $NETDB_REMCTL_HOST = 'netdb-node-roles-rc.stanford.edu'; # Work around a bug in Net::Remctl. $NETDB_REMCTL_PRINCIPAL = 'host/netdb-node-roles-rc.stanford.edu'; # Retrieve an existing ACL and check whether it contains a netdb-root member. # This is used to check if a default ACL is already present with a netdb-root # member so that we can return a default owner that matches. We only ever # increase the ACL from netdb to netdb-root, never degrade it, so this doesn't # pose a security problem. # # On any failure, just return an empty ACL to use the default. sub acl_has_netdb_root { my ($name) = @_; my $dbh = eval { Wallet::Database->connect }; return unless ($dbh and not $@); my $acl = eval { Wallet::ACL->new ($name, $dbh) }; return unless ($acl and not $@); for my $line ($acl->list) { return 1 if $line->[0] eq 'netdb-root'; } return; } # The default owner of a host should be the host keytab and the NetDB ACL for # that host, with one twist. If the creator of a new node is using a root # instance, we want to require everyone managing that node be using root # instances by default (this will do the right thing for Unix Systems hosts). sub default_owner { my ($type, $name) = @_; my %allowed = map { $_ => 1 } qw(HTTP afpserver cifs ftp host ident imap ldap lpr nfs pop sieve smtp uniengd webauth xmpp); my $realm = 'stanford.edu'; return unless $type eq 'keytab'; return unless $name =~ m,/,; my ($service, $instance) = split ('/', $name, 2); return unless $allowed{$service}; my $acl_name = "host/$instance"; my @acl; if ($ENV{REMOTE_USER} =~ m,/root, or acl_has_netdb_root ($acl_name)) { @acl = ([ 'netdb-root', $instance ], [ 'krb5', "host/$instance\@$realm" ]); } else { @acl = ([ 'netdb', $instance ], [ 'krb5', "host/$instance\@$realm" ]); } return ($acl_name, @acl); } # Enforce a naming policy. Host-based keytabs must have fully-qualified # hostnames, limit the acceptable characters for service/* keytabs, and # enforce our naming constraints on */cgi principals. # # Also use this function to require that Unix systems staff always do implicit # object creation using a */root instance. sub verify_name { my ($type, $name, $user) = @_; my %host = map { $_ => 1 } qw(HTTP afpserver cifs ftp host ident imap ldap lpr nfs pop sieve smtp uniengd webauth xmpp); my %staff; if (open (STAFF, '<', '/etc/remctl/acl/systems')) { local $_; while () { s/^\s+//; s/\s+$//; next if m,/root\@,; $staff{$_} = 1; } close STAFF; } # Check for a staff member not using their root instance. if ($staff{$user}) { return 'use a */root instance for wallet object creation'; } # Check keytab naming conventions. if ($type eq 'keytab') { if ($name !~ m,^[a-zA-Z0-9_-]+/[a-z0-9.-]+$,) { return "invalid principal name $name"; } my ($principal, $instance) = ($name =~ m,^([a-zA-Z0-9_-]+)/([a-z0-9.-]+)$,); unless (defined ($principal) && defined ($instance)) { return "invalid principal name $name"; } if ($host{$principal}) { if ($instance !~ /^[a-z0-9-]+\.[a-z0-9.-]+$/) { return "host name $instance is not fully qualified"; } } elsif ($principal eq 'service') { if ($instance !~ /^[a-z0-9-]+$/) { return "invalid service principal name $name"; } } elsif ($instance eq 'cgi') { if ($principal !~ /^[a-z][a-z0-9]{1,7}$/ and $principal !~ /^(class|dept|group)-[a-z0-9_-]+$/) { return "invalid CGI principal name $name"; } } } # Success. return; } 1;