1# This file is part of Config::Parser::ldap -*- perl -*- 2# Copyright (C) 2019-2021 Sergey Poznyakoff <gray@gnu.org> 3# 4# Config::Parser::ldap is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 3, or (at your option) 7# any later version. 8# 9# Config::Parser::ldap is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with Config::Parser::ldap. If not, see <http://www.gnu.org/licenses/>. 16 17package Config::Parser::ldap; 18use strict; 19use warnings; 20use parent 'Config::Parser'; 21use Carp; 22 23our $VERSION = '1.02'; 24 25=head1 NAME 26 27Config::Parser::ldap - configuration file parser for ldap.conf 28 29=head1 SYNOPSIS 30 31 $cfg = new Config::Parser::ldap($filename); 32 33 $base = $cfg->get('base'); 34 35 36=head1 DESCRIPTION 37 38A parser for F<ldap.conf> and similar files. 39 40The syntax of F<ldap.conf> configuration file is very simple. Each statement 41occupies one physical line and consists of a keyword and its value separated 42by one or more space characters. Keywords are case-insensitive. A value 43starts with the first non-blank character after the keyword, and terminates 44at the end of the line, or at the last sequence of blanks before the end of 45the line. 46 47Blank lines and lines beginning with a hash mark are ignored. 48 49=head1 CONSTRUCTOR 50 51=head2 $cfg = new Config::Parser::ldap(%opts); 52 53Parses the supplied configuration file and creates a new object for 54manipulating its settings. Keyword arguments I<%opts> are: 55 56=over 4 57 58=item filename 59 60Name of the file to parse. The file must exist. 61 62=item line 63 64Optional line where the configuration starts in I<$filename>. It is used 65to keep track of statement location in the file for correct diagnostics. 66If not supplied, 1 is assumed. 67 68=item fh 69 70File handle to read from. If it is not supplied, new handle will be 71created by using open on the supplied I<$filename>. 72 73=item lexicon 74 75Dictionary of configuration statements that are allowed in the file. You 76will most probably not need this parameter. It is listed here for completeness 77sake. Refer to the L<Config::AST> constructor for details. 78 79=back 80 81=cut 82 83sub new { 84 my ($class, %args) = @_; 85 $class->SUPER::new(%args, ci => 1); 86} 87 88=head1 METHODS 89 90All methods for accessing the configuration settings are inherited from 91L<Config::AST>. 92 93If you wish to use this class as a base class, please refer to 94L<Config::Parser> for implementation details. 95 96=head1 EXAMPLE 97 98The following simplified example shows how to use this module to connect 99and bind to a LDAP server. 100 101 use Config::Parser::ldap; 102 use Net::LDAP; 103 104 # Parse configuration file 105 $cf = new Config::Parser::ldap(filename => '/etc/ldap.conf'); 106 107 # Connect to server. 108 $ldap = Net::LDAP->new($cf->uri->value); 109 110 # Start TLS if required 111 $args{capath} = $cf->get('tls_cacertdir'); 112 $args{cafile} = $cf->get('tls_cacert'); 113 $args{clientcert} = $cf->get('tls_cert'); 114 $args{clientkey} = $cf->get('tls_key'); 115 $args{ciphers} = $cf->get('tls_cipher_suite'); 116 if ($reqcert = $cf->get('tls_reqcert')) { 117 my %tab = ( 118 none => 'never', 119 allow => 'optional', 120 demand => 'require', 121 hard => 'require', 122 try => 'optional' 123 ); 124 $args{verify} = $tab{$reqcert} 125 or die "unrecognized tls_reqcert: $reqcert"; 126 } 127 $mesg = $ldap->start_tls(%args); 128 $mesg->code && die $mesg->error; 129 130 # Bind 131 @bindargs = (); 132 if (my $v = $cf->get('binddn')) { 133 push @bindargs, $v 134 } 135 if (my $v = $cf->get('bindpw')) { 136 push @bindargs, password => $v; 137 } 138 $mesg = $ldap->bind(@bindargs); 139 $mesg->code && die $mesg->error; 140 141=cut 142 143sub parse { 144 my $self = shift; 145 my $filename = shift // confess "No filename given"; 146 local %_ = @_; 147 my $fh = delete $_{fh}; 148 unless ($fh) { 149 open($fh, "<", $filename) 150 or croak "can't open $filename: $!"; 151 } 152 my $line = delete $_{line} // 0; 153 154 while (<$fh>) { 155 ++$line; 156 chomp; 157 s/^\s+//; 158 s/\s+$//; 159 s/#.*//; 160 next if $_ eq ""; 161 my ($kw, $val) = split /\s+/, $_, 2; 162 my $locus = new Text::Locus($filename, $line); 163 if (defined($kw) && defined($val)) { 164 $self->add_value([$kw], $val, $locus); 165 } else { 166 $self->error("malformed line", locus => $locus); 167 $self->{_error_count}++; 168 } 169 } 170 return $self; 171} 172 173=head1 SEE ALSO 174 175L<Config::AST>. 176 177L<Config::Parser>. 178 179=cut 180 1811; 182