From a3684346f4d60715512c7ca30ba9fc7bb270c38e Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 3 Jun 2012 22:20:58 +0200 Subject: Merge everything into a single executable. --- fripost | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100755 fripost (limited to 'fripost') diff --git a/fripost b/fripost new file mode 100755 index 0000000..e9e27e7 --- /dev/null +++ b/fripost @@ -0,0 +1,429 @@ +#!/usr/bin/perl + +use 5.010_000; +use strict; +use warnings; +use utf8; + +our $VERSION = '0.01'; + +=head1 NAME + +fripost - Fripost.org handling utility for virtual hosting + +=head1 SYNOPSIS + +B [I] { mkpass | user-add | user-search | user-passwd +| domain-add | domain-search | alias-add | alias-search } + +B B<--man> + +=head1 COMMANDS + +=over 4 + +=item B mkpass [I] + +Create a random new password, and returns its hash. + +=item B user-add [I] [B<--password=>I] + +Add a new virtual mailbox. + +=item B user-search [I] + +List matching virtual users. + +=item B user-passwd [I] [B<--password=>I] + +Change user password. + +=item B domain-add [I [I]] + +Add a new virtual domain. + +=item B domain-search [I [I]] + +List matching virtual domains. + +=item B alias-add [B<--force>] [I [I...]] + +Add a new virtual alias. + +=item B alias-search [B<-f>|B<--from>] [B<-g>|B<--goto>] [I
] + +List matching virtual aliases. + +=back + +=head1 DESCRIPTION + +Unless one of the B<-h>, B<--help>, or B<--man> option is given, one of +the following commands is required. + +=over 4 + +=item B mkpass [I] + +C is used to generate a salted SHA-1 hash of the given +I. If no argument is given, the password is randomly +generated, respecting Fripost's password policy. + +=item B user-add [I] [B<--password=>I] + +C is used to add a new virtual mailbox to the system, unless +B<--pretend> is set. +If I or I are not given, the user is prompted for +their value. +If I is not fully qualified, the domain C is +appended. +An error is raised if I is already an existing virtual user or +alias. +If I is given, is it used RAW (not hashed). +This can be useful if the user does not want to give the clear copy but +only a hash, for example. +Using this option disables the sending of credentials. + +=item B user-search [I] + +C is used to +list virtual mailboxes whose username matches exactly I. +Wildcards I<*> can appear in I, to match zero or more characters. +If no I is given, lists all existing mailboxes. + +If I has no domain part, C lists matching users for any +domains. +Otherwise, C looks up the matching user parts for each matching +domain. +Because of these multiple searches, the use of wildcards on the domain +part of I may be inefficient. + +=item B user-passwd [I] [B<--password=>I] + +C is used to change the password of I, unless +B<--pretend> is set. +If I or I are not given, the user is prompted for +their value. +If I is not fully qualified, the domain C is appended. +An error is raised if I is not an existing virtual user. +If I is given, is it used RAW (not hashed). +This can be useful if the user does not want to give the clear copy but +only a hash, for example. +Using this option disables the sending of credentials. + +=item B domain-add [I [I]] + +C is used add a new virtual domain to the system, unless +B<--pretend> is set. +If I is not given, the user is prompted for its value. +By default, C prompts for the owner(s) of the new +domain; Use the empty string I<''> to create a "global" domain, only +managed by Fripost's administrators. +If I is an existing virtual domain, the owner(s) are simply +added to the list of managers. + +=item B domain-search [I [I]] + +C is used to list virtual domains matching exactly I, +and whose owner is I. +Wildcards I<*> can appear in I, to match zero or more characters. +If no I is given, list all domains matching I, regardless +of the owner; If I is the empty string I<''>, list only the non +self-managed domains. +If neither I nor I are given, C lists +all existing virtual domains. + +=item B alias-add [B<--force>] [I [I...]] + +C is used to add a new virtual alias to the system, unless +B<--pretend> is set. +If I or I are not given, the user is prompted for their +value. +If I is not fully qualified, the domain C is appended. +An error is raised if I is already an existing username, or if +I is an existing alias and B<--force> is not set. + +Inserted aliases conform to Postfix's B(5) alias table format; +I has to be of one of the following forms: + +=over 4 + +=item . + +I@I, to redirect emails for I@I to I, or + +=item . + +@I, to catch all emails for users in I and redirect them +to I. +This form has the lowest precedence: If there is an alias from +I@I to I, emails to I@I will be +redirected to I only. +See B(5) for details and warnings. + +=back + +If serveral entries are matching, for instance if there are an alias from +I@I to I and another for I@I to +I, emails to I@I will be redirected to BOTH I +and I. Note that C forbids the creation of such +multi-recipient aliases, unless B<--force> is set. + +=item B alias-search [B<-f>|B<--from>] [B<-g>|B<--goto>] [I
] + +C is used to list virtual aliases whose value or target +matches exactly I
. +As of the current version, wilcards are not allowed in I
; This +will be fixed soon. +To list matching aliases (resp., targets) only, use the flag B<-f> +(resp., B<-g>). +If no I
is given, C lists all existing virtual +aliases. + +=back + +=head1 OPTIONS + +=over 8 + +=item B<--pretend> + +Dry-run all operations that is, do not modify the virtual lookup tables. +But still queries the LDAP server to ensure that the modification would +be safe. (For instance, ensure that a new user is not already existing.) + +=item B<--server_host=>I + +The LDAP URI to connect to. +Overrides the value read from the configuration file (see +B) if present. + +=item B<--bind_dn=>I + +The Distinguished Name (DN) to bind to the LDAP directory. +Overrides the value read from the configuration file (see +B) if present. +If not set (the default), B binds anonymously. + +=item B<--bind_pw=>I + +The password to to bind with. +Overrides the value read from the configuration file (see +B) if present. + +=item B<--base_dn=>I + +The root DN for every communication to the LDAP server. +Overrides the value read from the configuration file (see +B) if present. + +=item B<--sign>[B<=>I] + +Use I as the key to sign all non-empty emails. If I is empty +or not given, use the first key found in the secret keyring, see +B(1). A running gpg-agent is required if the private key is +protected by a passphrase. +Overrides the value read from the configuration file (see +B) if present. + +=item B{I|I|I} + +Tells whether non-empty emails should be encrypted. +No email will be encrypted if I is chosen (the default). +I turns on opportunistic encryption that is, emails will be +encrypted as soon as the recipient is a usable user ID in the public +keyring. +I will disallow the sending of all non-empty clear emails. +Overrides the value read from the configuration file (see +B) if present. + +=item BI + +If one of the I or I encryption level is chosen, encrypt +for the user ID I. + +=item B<-v>, B<--verbose> + +Verbose mode. + +=item B<-d>, B<--debug> + +Debug mode. + +=back + +=head1 CONFIGURATION + +The configuration is read from the file C<$HOME/.fripost.yml>, and has a +lower precedence than the I above. +Valid keys include: + +=over 4 + +=item I + +The LDAP URI to connect to. Defaults to C. + +=item I + +The I e-mail address to use. Defaults to C. + +=item I + +The Distinguished Name (DN) to bind to the LDAP directory. +(If not set, B binds anonymously.) + +=item I + +The password to to bind with. + +=item I + +The root DN for every communication to the LDAP server. + +=item I + +The key used to sign all non-empty emails. If no key is given, +use the first one found in the secret keyring, see B(1). +A running gpg-agent is required if the private key is +protected by a passphrase. + +=item I + +Tells whether non-empty emails should be encrypted. +No email will be encrypted if I is chosen (the default). +I turns on opportunistic encryption that is, emails will be +encrypted as soon as the recipient is a usable user ID in the public +keyring. +I will disallow the sending of all non-empty clear emails (not +recommended). + +=back + +=cut + +use FindBin qw($Bin); +use lib "$Bin/lib"; + +use Env qw /HOME/; +use File::Spec::Functions; +use Getopt::Long qw /:config noauto_abbrev no_ignore_case + gnu_compat bundling permute nogetopt_compat + auto_version/; +use Pod::Usage; +use YAML::Syck; + +use Fripost::Schema; +use Fripost::Commands::mkpass; +use Fripost::Commands::user_add; +use Fripost::Commands::user_search; +use Fripost::Commands::user_passwd; +use Fripost::Commands::domain_add; +use Fripost::Commands::domain_search; +use Fripost::Commands::alias_add; +use Fripost::Commands::alias_search; + + +## Get global command line options +our $conf = LoadFile( catfile ($HOME, '.fripost.yml') ); + +GetOptions( + 'server_host=s' => \$conf->{server_host}, + 'base_dn=s' => \$conf->{base_dn}, + 'bind_dn=s' => \$conf->{bind_dn}, + 'bind_pw=s' => \$conf->{bind_pw}, + 'pretend' => \$conf->{pretend}, + 'sign:s' => \$conf->{sign}, + 'encrypt=s' => \$conf->{encrypt}, + 'encrypt-to=s' => \$conf->{encrypt_to}, + 'd|debug' => \$conf->{debug}, + 'v|verbose' => \$conf->{verbose}, + 'h|help' => sub { pod2usage(-exitstatus => 0, + -sections => [ qw/SYNOPSIS COMMANDS/ ], + -verbose => 99) }, + 'man' => sub { pod2usage(-exitstatus => 0, + -verbose => 2) }, + + 'password=s' => \$conf->{password}, + 'force' => \$conf->{force}, + 'f|from' => \$conf->{from}, + 'g|goto' => \$conf->{goto}, +) or pod2usage(2); + + +## Set the default values +$conf->{server_host} //= 'ldap://127.0.0.1:389'; +$conf->{bind_dn} //= ''; +$conf->{base_dn} //= ''; +$conf->{admin_email} //= 'admin@fripost.org'; +$conf->{encrypt} //= 'never'; + +die "Illegal encrypt level: `$conf->{encrypt}'.\n" + unless grep {$_ eq $conf->{encrypt}} qw /never may secure/; + + +## Get the command + +my $cmd = shift; +my $main; + +$cmd //= ''; +if ($cmd eq 'mkpass') { + &Fripost::Commands::mkpass::main (@ARGV); + exit 0; +} +elsif ($cmd eq 'user-add') { + $main = "Fripost::Commands::user_add::main"; +} +elsif ($cmd eq 'user-search') { + $main = "Fripost::Commands::user_search::main"; +} +elsif ($cmd eq 'user-passwd') { + $main = "Fripost::Commands::user_passwd::main"; +} +elsif ($cmd eq 'domain-add') { + $main = "Fripost::Commands::domain_add::main"; +} +elsif ($cmd eq 'domain-search') { + $main = "Fripost::Commands::domain_search::main"; +} +elsif ($cmd eq 'alias-add') { + $main = "Fripost::Commands::alias_add::main"; +} +elsif ($cmd eq 'alias-search') { + $main = "Fripost::Commands::alias_search::main"; +} +else { + pod2usage( -exitstatus => 1, + -verbose => 0, + -msg => "Unknown command: `$cmd'."); +} + + +## Connect to the LDAP server +my $ldap = Fripost::Schema->new( $conf ); +{ + no strict "refs"; + &$main ($ldap, $conf, @ARGV); +} +$ldap->unbind(); + + +=head1 AUTHOR + +Stefan Kangas C<< >> + +Guilhem Moulin C<< >> + +=head1 COPYRIGHT + +Copyright 2010-2012 Stefan Kangas. + +Copyright 2012 Guilhem Moulin. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it +under the same terms as perl itself. + +=cut -- cgit v1.2.3