From: Junio C Hamano Date: Wed, 26 Aug 2015 22:45:31 +0000 (-0700) Subject: Merge branch 'jv/send-email-selective-smtp-auth' X-Git-Tag: v2.6.0-rc0~40 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/629ac65f68fb78a6cbff76008326ca38965e1c9a?ds=inline;hp=-c Merge branch 'jv/send-email-selective-smtp-auth' "git send-email" learned a new option --smtp-auth to limit the SMTP AUTH mechanisms to be used to a subset of what the system library supports. * jv/send-email-selective-smtp-auth: send-email: provide whitelist of SMTP AUTH mechanisms --- 629ac65f68fb78a6cbff76008326ca38965e1c9a diff --combined Documentation/git-send-email.txt index f14705ee04,631f6c8076..b9134d234f --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@@ -49,17 -49,17 +49,17 @@@ Composin of 'sendemail.annotate'. See the CONFIGURATION section for 'sendemail.multiEdit'. ---bcc=
:: +--bcc=
,...:: Specify a "Bcc:" value for each email. Default is the value of 'sendemail.bcc'. + -The --bcc option must be repeated for each user you want on the bcc list. +This option may be specified multiple times. ---cc=
:: +--cc=
,...:: Specify a starting "Cc:" value for each email. Default is the value of 'sendemail.cc'. + -The --cc option must be repeated for each user you want on the cc list. +This option may be specified multiple times. --compose:: Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1]) @@@ -110,13 -110,13 +110,13 @@@ is not set, this will be prompted for Only necessary if --compose is also set. If --compose is not set, this will be prompted for. ---to=
:: +--to=
,...:: Specify the primary recipient of the emails generated. Generally, this will be the upstream maintainer of the project involved. Default is the value of the 'sendemail.to' configuration value; if that is unspecified, and --to-cmd is not specified, this will be prompted for. + -The --to option must be repeated for each user you want on the to list. +This option may be specified multiple times. --8bit-encoding=:: When encountering a non-ASCII message or subject that does not @@@ -171,6 -171,19 +171,19 @@@ Sendin to determine your FQDN automatically. Default is the value of 'sendemail.smtpDomain'. + --smtp-auth=:: + Whitespace-separated list of allowed SMTP-AUTH mechanisms. This setting + forces using only the listed mechanisms. Example: + + + ------ + $ git send-email --smtp-auth="PLAIN LOGIN GSSAPI" ... + ------ + + + If at least one of the specified mechanisms matches the ones advertised by the + SMTP server and if it is supported by the utilized SASL library, the mechanism + is used for authentication. If neither 'sendemail.smtpAuth' nor '--smtp-auth' + is specified, all mechanisms supported by the SASL library can be used. + --smtp-pass[=]:: Password for SMTP-AUTH. The argument is optional: If no argument is specified, then the empty string is used as diff --combined git-send-email.perl index b660cc2382,6e380a25be..c5a3f766f7 --- a/git-send-email.perl +++ b/git-send-email.perl @@@ -75,6 -75,8 +75,8 @@@ git send-email [options] * The domain name sent to HELO/EHLO handshake + --smtp-auth * Space-separated list of allowed AUTH mechanisms. + This setting forces to use one of the listed mechanisms. --smtp-debug <0|1> * Disable, enable Net::SMTP debug. Automating: @@@ -208,7 -210,7 +210,7 @@@ my ($cover_cc, $cover_to) my ($to_cmd, $cc_cmd); my ($smtp_server, $smtp_server_port, @smtp_server_options); my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); - my ($identity, $aliasfiletype, @alias_files, $smtp_domain); + my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth); my ($validate, $confirm); my (@suppress_cc); my ($auto_8bit_encoding); @@@ -239,6 -241,7 +241,7 @@@ my %config_settings = "smtppass" => \$smtp_authpass, "smtpsslcertpath" => \$smtp_ssl_cert_path, "smtpdomain" => \$smtp_domain, + "smtpauth" => \$smtp_auth, "to" => \@initial_to, "tocmd" => \$to_cmd, "cc" => \@initial_cc, @@@ -310,6 -313,7 +313,7 @@@ my $rc = GetOptions("h" => \$help "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path, "smtp-debug:i" => \$debug_net_smtp, "smtp-domain:s" => \$smtp_domain, + "smtp-auth=s" => \$smtp_auth, "identity=s" => \$identity, "annotate!" => \$annotate, "no-annotate" => sub {$annotate = 0}, @@@ -460,11 -464,25 +464,11 @@@ my ($repoauthor, $repocommitter) ($repoauthor) = Git::ident_person(@repo, 'author'); ($repocommitter) = Git::ident_person(@repo, 'committer'); -# Verify the user input - -foreach my $entry (@initial_to) { - die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/; -} - -foreach my $entry (@initial_cc) { - die "Comma in --cc entry: $entry'\n" unless $entry !~ m/,/; -} - -foreach my $entry (@bcclist) { - die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/; -} - sub parse_address_line { if ($have_mail_address) { return map { $_->format } Mail::Address->parse($_[0]); } else { - return split_addrs($_[0]); + return Git::parse_mailboxes($_[0]); } } @@@ -547,6 -565,8 +551,6 @@@ if (@alias_files and $aliasfiletype an } } -($sender) = expand_aliases($sender) if defined $sender; - # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if # $f is a revision list specification to be passed to format-patch. sub is_format_patch_arg { @@@ -791,10 -811,7 +795,10 @@@ if (!$force) } } -if (!defined $sender) { +if (defined $sender) { + $sender =~ s/^\s+|\s+$//g; + ($sender) = expand_aliases($sender); +} else { $sender = $repoauthor || $repocommitter || ''; } @@@ -826,9 -843,12 +830,9 @@@ sub expand_one_alias return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias; } -@initial_to = expand_aliases(@initial_to); -@initial_to = validate_address_list(sanitize_address_list(@initial_to)); -@initial_cc = expand_aliases(@initial_cc); -@initial_cc = validate_address_list(sanitize_address_list(@initial_cc)); -@bcclist = expand_aliases(@bcclist); -@bcclist = validate_address_list(sanitize_address_list(@bcclist)); +@initial_to = process_address_list(@initial_to); +@initial_cc = process_address_list(@initial_cc); +@bcclist = process_address_list(@bcclist); if ($thread && !defined $initial_reply_to && $prompting) { $initial_reply_to = ask( @@@ -1021,17 -1041,15 +1025,17 @@@ sub sanitize_address return $recipient; } + # remove non-escaped quotes + $recipient_name =~ s/(^|[^\\])"/$1/g; + # rfc2047 is needed if a non-ascii char is included if ($recipient_name =~ /[^[:ascii:]]/) { - $recipient_name =~ s/^"(.*)"$/$1/; $recipient_name = quote_rfc2047($recipient_name); } # double quotes are needed if specials or CTLs are included elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) { - $recipient_name =~ s/(["\\\r])/\\$1/g; + $recipient_name =~ s/([\\\r])/\\$1/g; $recipient_name = qq["$recipient_name"]; } @@@ -1043,14 -1061,6 +1047,14 @@@ sub sanitize_address_list return (map { sanitize_address($_) } @_); } +sub process_address_list { + my @addr_list = map { parse_address_line($_) } @_; + @addr_list = expand_aliases(@addr_list); + @addr_list = sanitize_address_list(@addr_list); + @addr_list = validate_address_list(@addr_list); + return @addr_list; +} + # Returns the local Fully Qualified Domain Name (FQDN) if available. # # Tightly configured MTAa require that a caller sends a real DNS @@@ -1130,6 -1140,12 +1134,12 @@@ sub smtp_auth_maybe Authen::SASL->import(qw(Perl)); }; + # Check mechanism naming as defined in: + # https://tools.ietf.org/html/rfc4422#page-8 + if ($smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) { + die "invalid smtp auth: '${smtp_auth}'"; + } + # TODO: Authentication may fail not because credentials were # invalid but due to other reasons, in which we should not # reject credentials. @@@ -1142,6 -1158,20 +1152,20 @@@ 'password' => $smtp_authpass }, sub { my $cred = shift; + + if ($smtp_auth) { + my $sasl = Authen::SASL->new( + mechanism => $smtp_auth, + callback => { + user => $cred->{'username'}, + pass => $cred->{'password'}, + authname => $cred->{'username'}, + } + ); + + return !!$smtp->auth($sasl); + } + return !!$smtp->auth($cred->{'username'}, $cred->{'password'}); }); @@@ -1560,8 -1590,8 +1584,8 @@@ foreach my $t (@files) ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1)); $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc); - @to = validate_address_list(sanitize_address_list(@to)); - @cc = validate_address_list(sanitize_address_list(@cc)); + @to = process_address_list(@to); + @cc = process_address_list(@cc); @to = (@initial_to, @to); @cc = (@initial_cc, @cc);