Ignore:
Timestamp:
06/13/17 13:58:57 (7 years ago)
Author:
Kris Deugau
Message:

/branches/stable

Merge /trunk through r749 for 1.4.0

Location:
branches/stable
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/stable

  • branches/stable/DNSDB.pm

    r725 r756  
    33##
    44# $Id$
    5 # Copyright 2008-2013 Kris Deugau <kdeugau@deepnet.cx>
     5# Copyright 2008-2016 Kris Deugau <kdeugau@deepnet.cx>
    66#
    77#    This program is free software: you can redistribute it and/or modify
     
    3636use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
    3737
    38 $VERSION        = "1.2.5p2";    ##VERSION##
     38$VERSION        = "1.4.0";      ##VERSION##
    3939@ISA            = qw(Exporter);
    4040@EXPORT_OK      = qw(
     
    146146                domain  => 'domain_id',
    147147                revzone => 'rdns_id',
    148                 record  => 'record_id'
     148                record  => 'record_id',
    149149        );
    150150my %par_col = (
     
    456456#  group_id, log entry
    457457# and optionally one or more of:
    458 #  domain_id, rdns_id
     458#  domain_id, rdns_id, logparent
    459459# The %userdata hash provides the user ID, username, and fullname
     460# Returns the log entry ID, mainly for use in bulk operations to allow a "parent" log entry
     461# and a set of child entries (eg, domain add and the individual default-record-copy entries)
    460462sub _log {
    461463  my $self = shift;
     
    466468  $args{rdns_id} = 0 if !$args{rdns_id};
    467469  $args{domain_id} = 0 if !$args{domain_id};
     470  $args{logparent} = 0 if !$args{logparent};
    468471
    469472##fixme:  farm out the actual logging to different subs for file, syslog, internal, etc based on config
    470473#  if ($self->{log_channel} eq 'sql') {
    471   $dbh->do("INSERT INTO log (domain_id,rdns_id,group_id,entry,user_id,email,name) VALUES (?,?,?,?,?,?,?)",
     474  $dbh->do("INSERT INTO log (domain_id,rdns_id,group_id,logparent,entry,user_id,email,name) ".
     475        "VALUES (?,?,?,?,?,?,?,?)",
    472476        undef,
    473         ($args{domain_id}, $args{rdns_id}, $args{group_id}, $args{entry},
     477        ($args{domain_id}, $args{rdns_id}, $args{group_id}, $args{logparent}, $args{entry},
    474478                $self->{loguserid}, $self->{logusername}, $self->{logfullname}) );
     479
     480  my ($log_id) = $dbh->selectrow_array("SELECT currval('log_log_id_seq')");
     481  return $log_id;
     482
    475483#  } elsif ($self->{log_channel} eq 'file') {
    476484#  } elsif ($self->{log_channel} eq 'syslog') {
     
    16551663    my ($c) = ($$tmpl =~ /(\%-?c)/);  my $nld = '';  my $cld = '';
    16561664    $c = '' if !$c;
     1665    my ($cn) = ($$tmpl =~ /(\%x)/);
    16571666    my $skipgw = ($c =~ /\%-c/ ? 0 : 1);
    16581667    my $ipkill = 0;
     1668
     1669    if ($cn) {
     1670      # "natural n'th IP in the block" pattern
     1671      $$tmpl =~ s/$cn/$ipindex+1/e;
     1672    }
    16591673
    16601674##fixme: still have one edge case not handled well:
     
    23682382        undef, ($domain, $defloc));
    23692383
    2370     $self->_log(domain_id => $dom_id, group_id => $group,
     2384    my $logparent = $self->_log(domain_id => $dom_id, group_id => $group,
    23712385        entry => "Added ".($state ? 'active' : 'inactive')." domain $domain");
    23722386
     
    23842398        my @tmp1 = split /:/, $host;
    23852399        my @tmp2 = split /:/, $val;
    2386         $self->_log(domain_id => $dom_id, group_id => $group,
     2400        $self->_log(domain_id => $dom_id, group_id => $group, logparent => $logparent,
    23872401                entry => "[new $domain] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ".
    23882402                "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl");
     
    23912405        $logentry .= " [distance $dist]" if $typemap{$type} eq 'MX';
    23922406        $logentry .= " [priority $dist] [weight $weight] [port $port]" if $typemap{$type} eq 'SRV';
    2393         $self->_log(domain_id => $dom_id, group_id => $group,
     2407        $self->_log(domain_id => $dom_id, group_id => $group, logparent => $logparent,
    23942408                entry => $logentry." $val', TTL $ttl");
    23952409      }
     
    34393453        "WHERE group_id IN ($args{curgroup}".($args{childlist} ? ",$args{childlist}" : '').")".
    34403454        ($args{startwith} ? " AND username ~* ?" : '').
    3441         ($args{filter} ? " AND username ~* ?" : '');
     3455        ($args{filter} ? " AND username ~* ?" : '').
     3456        " AND NOT type = 'R' ";
    34423457  my ($count) = $dbh->selectrow_array($sql, undef, (@filterargs) );
    34433458  $errstr = $dbh->errstr if !$count;
     
    36453660  $errstr = $DBI::errstr if !$uname;
    36463661
     3662  no warnings qw (uninitialized);
    36473663  $fullformat =~ s/\%u/$uname/g;
    36483664  $fullformat =~ s/\%f/$fname/g;
     
    48104826# Get a count of log entries
    48114827# Takes a database handle and a hash containing at least:
    4812 # - Entity ID and entity type as the primary log "slice"
     4828# - Entity identifier and entity type as the primary log "slice"
    48134829sub getLogCount {
    48144830  my $self = shift;
    4815   my $dbh = $self->{dbh};
    4816 
    4817   my %args = @_;
    4818 
    4819   my @filterargs;
    4820 ##fixme:  which fields do we want to filter on?
    4821 # push @filterargs,
    4822 
    4823   $errstr = 'Missing primary parent ID and/or type';
    4824   # fail early if we don't have a "prime" ID to look for log entries for
    4825   return if !$args{id};
    4826 
    4827   # or if the prime id type is missing or invalid
    4828   return if !$args{logtype};
    4829   $args{logtype} = 'revzone' if $args{logtype} eq 'rdns';       # hack pthui
    4830   $args{logtype} = 'domain' if $args{logtype} eq 'dom';         # hack pthui
    4831   return if !grep /^$args{logtype}$/, ('group', 'domain', 'revzone', 'user');
    4832 
    4833   my $sql = "SELECT count(*) FROM log ".
    4834         "WHERE $id_col{$args{logtype}}=?".
    4835         ($args{filter} ? " AND entry ~* ?" : '');
    4836   my ($count) = $dbh->selectrow_array($sql, undef, ($args{id}, @filterargs) );
    4837   $errstr = $dbh->errstr if !$count;
    4838   return $count;
     4831  return $self->getLogEntries(@_, count => 1);
    48394832} # end getLogCount()
    48404833
     
    48434836# Get a list of log entries
    48444837# Takes arguments as with getLogCount() above, plus optional:
     4838# - "count" flag
     4839#  OR
    48454840# - sort field
    48464841# - sort order
     
    48544849  my @filterargs;
    48554850
    4856   # fail early if we don't have a "prime" ID to look for log entries for
    4857   return if !$args{id};
    4858 
    4859   # or if the prime id type is missing or invalid
     4851  # fail if the prime id type is missing or invalid
     4852  $errstr = "Missing primary log slice type";
    48604853  return if !$args{logtype};
    48614854  $args{logtype} = 'revzone' if $args{logtype} eq 'rdns';       # hack pthui
    48624855  $args{logtype} = 'domain' if $args{logtype} eq 'dom';         # hack pthui
     4856  $errstr = "Invalid primary log slice type";
    48634857  return if !grep /^$args{logtype}$/, ('group', 'domain', 'revzone', 'user');
     4858
     4859  # fail if we don't have a prime ID to look for log entries for
     4860  $errstr = "Missing ID for primary log slice";
     4861  return if !($args{id} || $args{fname});
    48644862
    48654863  # Sorting defaults
     
    48684866  $args{offset} = 0 if !$args{offset} || $args{offset} !~ /^(?:all|\d+)$/;
    48694867
    4870   my %sortmap = (fname => 'name', username => 'email', entry => 'entry', stamp => 'stamp');
     4868  my %sortmap = (fname => 'name', username => 'email', entry => 'entry', stamp => 'stamp',
     4869      revzone => 'revnet', domain => 'domain');
    48714870  $args{sortby} = $sortmap{$args{sortby}};
    48724871
    4873   my $sql = "SELECT user_id AS userid, email AS useremail, name AS userfname, entry AS logentry, ".
    4874         "date_trunc('second',stamp) AS logtime ".
    4875         "FROM log ".
    4876         "WHERE $id_col{$args{logtype}}=?".
    4877         ($args{filter} ? " AND entry ~* ?" : '').
    4878         " ORDER BY $args{sortby} $args{sortorder}, log_id $args{sortorder}".
     4872  push @filterargs, $args{filter} if $args{filter};
     4873  my $sql;
     4874  if ($args{count}) {
     4875    $sql = "SELECT count(*) FROM log l ";
     4876  } else {
     4877    $sql = "SELECT l.log_id AS logparent, l.user_id AS userid, l.name AS userfname, d.domain, l.domain_id, ".
     4878        "r.revnet AS revzone, ".
     4879        "l.rdns_id, l.entry AS logentry, date_trunc('second',l.stamp) AS logtime ".
     4880        "FROM log l ".
     4881        "LEFT JOIN domains d ON l.domain_id = d.domain_id ".
     4882        "LEFT JOIN revzones r ON l.rdns_id = r.rdns_id ";
     4883  }
     4884
     4885  # decide which ID argument to use.  Only use the "full name" if no normal ID is present
     4886  my $idarg;
     4887  if ($args{id}) {
     4888    $sql .= "WHERE l.$id_col{$args{logtype}} = ? ";
     4889    $idarg = $args{id};
     4890  } else {
     4891    $sql .= "WHERE l.name = ? ";
     4892    $idarg = $args{fname};
     4893  }
     4894
     4895  # trim log "subentries" - we'll figure out where to stash these later
     4896  $sql .= " AND logparent = 0";
     4897
     4898  # add the entry filter, if any
     4899  $sql .= ($args{filter} ? " AND entry ~* ?" : '');
     4900
     4901  # Limit scope based on group.  Mainly useful for ltype==user, so subgroup
     4902  # users can see what the deities in parent groups have done to their domains.
     4903  if ($args{group} != 1) {
     4904    my @grouplist;
     4905    $self->getChildren($args{group}, \@grouplist);
     4906    my $groupset = join(',', $args{group}, @grouplist);
     4907    $sql .= " AND l.group_id IN ($groupset)";
     4908  }
     4909
     4910  if ($args{count}) {
     4911    my ($count) = $dbh->selectrow_array($sql, undef, ($idarg, @filterargs) );
     4912    $errstr = $dbh->errstr if !$count;
     4913    return $count;
     4914  } else {
     4915    $sql .= " ORDER BY $args{sortby} $args{sortorder}, log_id $args{sortorder}".
    48794916        ($args{offset} eq 'all' ? '' : " LIMIT $self->{perpage} OFFSET ".$args{offset}*$self->{perpage});
    4880   my $loglist = $dbh->selectall_arrayref($sql, { Slice => {} }, ($args{id}, @filterargs) );
    4881   $errstr = $dbh->errstr if !$loglist;
    4882   return $loglist;
     4917    my @loglist;
     4918    my $sth = $dbh->prepare($sql);
     4919    my $logchild = $dbh->prepare("SELECT entry FROM log WHERE logparent = ? ORDER BY log_id");
     4920    $sth->execute($idarg, @filterargs);
     4921    while (my $row = $sth->fetchrow_hashref) {
     4922      $logchild->execute($row->{logparent});
     4923      my $childlist = $logchild->fetchall_arrayref({});
     4924      $row->{childentries} = $childlist;
     4925      push @loglist, $row;
     4926    }
     4927    return \@loglist;
     4928  }
     4929
     4930  # Your llama is on fire
     4931
    48834932} # end getLogEntries()
     4933
     4934
     4935# a collection of joins for the record search
     4936our $recsearchsqlbase = q(
     4937FROM records r
     4938LEFT JOIN domains d ON r.domain_id = d.domain_id
     4939  LEFT JOIN groups g1 ON d.group_id = g1.group_id
     4940LEFT JOIN revzones z ON r.rdns_id = z.rdns_id
     4941  LEFT JOIN groups g2 on z.group_id = g2.group_id
     4942JOIN rectypes t ON r.type = t.val
     4943LEFT JOIN locations l ON r.location = l.location
     4944WHERE r.type <> 6 AND (r.host ~* ? OR r.val ~* ?)
     4945);
     4946
     4947
     4948## DNSDB::recSearchCount()
     4949# Get a total count for a global record search
     4950# Takes a hash with the search string and the login group of the user
     4951sub recSearchCount {
     4952  my $self = shift;
     4953  my $dbh = $self->{dbh};
     4954  my %args = @_;
     4955
     4956  my $sql = "SELECT count(*)".$recsearchsqlbase;
     4957
     4958  # Limit scope based on group
     4959  if ($args{group} != 1) {
     4960    my @grouplist;
     4961    $self->getChildren($args{group}, \@grouplist);
     4962    my $groupset = join(',', $args{group}, @grouplist);
     4963    # oh my aching HEAD.  there has to be a better way to do conditions on joined tables...
     4964    $sql .= "AND (
     4965    (g1.group_id IN ($groupset) AND g2.group_id IN ($groupset)) OR
     4966    (g1.group_id IN ($groupset) AND g2.group_id IS NULL) OR
     4967    (g1.group_id IS NULL AND g2.group_id IN ($groupset))
     4968    )
     4969";
     4970  }
     4971
     4972  my $count = $dbh->selectrow_array($sql, undef, $args{searchfor}, $args{searchfor});
     4973  $errstr = $dbh->errstr if !$count;
     4974  return $count;
     4975
     4976} # end recSearchCount()
     4977
     4978
     4979## DNSDB::recSearch()
     4980# Find records matching the search string
     4981# Takes a hash with the search string, login group of the user, pagination offset, sort field,
     4982# and sort direction
     4983# Returns a reference to a list of hashrefs
     4984sub recSearch {
     4985  my $self = shift;
     4986  my $dbh = $self->{dbh};
     4987  my %args = @_;
     4988
     4989  my $sql = q(SELECT
     4990    r.domain_id, d.domain, g1.group_name AS domgroup,
     4991    r.rdns_id, z.revnet AS revzone, g2.group_name AS revgroup,
     4992    r.host, t.name AS rectype, r.val, l.description AS location, r.record_id).
     4993    $recsearchsqlbase;
     4994
     4995  # Limit scope based on group
     4996  if ($args{group} != 1) {
     4997    my @grouplist;
     4998    $self->getChildren($args{group}, \@grouplist);
     4999    my $groupset = join(',', $args{group}, @grouplist);
     5000    # oh my aching HEAD.  there has to be a better way to do conditions on joined tables...
     5001    $sql .= "AND (
     5002    (g1.group_id IN ($groupset) AND g2.group_id IN ($groupset)) OR
     5003    (g1.group_id IN ($groupset) AND g2.group_id IS NULL) OR
     5004    (g1.group_id IS NULL AND g2.group_id IN ($groupset))
     5005    )
     5006";
     5007  }
     5008
     5009  # mixed tables means this isn't a simple prefix like the regular record list filter.  :/
     5010  my %sortmap = (
     5011    domain => 'd.domain',
     5012    revzone => 'z.revnet',
     5013    host => 'r.host',
     5014    type => 't.name',
     5015    val => 'inetlazy(r.val)',
     5016    location => 'r.location',
     5017    );
     5018
     5019  # Sorting defaults
     5020  $args{sortorder} = 'ASC' if !$args{sortorder} || !grep /^$args{sortorder}$/, ('ASC','DESC');
     5021  $args{sortby} = 'r.host' if !$args{sortby} || $args{sortby} !~ /^[\w_.]+$/;
     5022  $args{offset} = 0 if !$args{offset} || $args{offset} !~ /^(?:all|\d+)$/;
     5023
     5024  $args{sortby} = $sortmap{$args{sortby}} if $args{sortby} !~ /\./;
     5025
     5026  # Add sort and offset to SQL
     5027  $sql .= "ORDER BY $args{sortby} $args{sortorder},record_id ASC\n";
     5028  $sql .= ($args{offset} eq 'all' ? '' : "LIMIT $self->{perpage} OFFSET ".$args{offset}*$self->{perpage});
     5029
     5030##fixme: should probably sent the warning somewhere else
     5031  my $ret = $dbh->selectall_arrayref($sql, { Slice => {} }, $args{searchfor}, $args{searchfor})
     5032    or warn $dbh->errstr;
     5033  return $ret;
     5034
     5035} # end recSearch()
    48845036
    48855037
     
    53795531  eval {
    53805532
     5533    my $logparent;
     5534
    53815535    if ($rev eq 'n') {
    53825536##fixme:  serial
     
    53865540      ($zone_id) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')");
    53875541      $domain_id = $zone_id;
    5388       $self->_log(group_id => $group, domain_id => $domain_id,
     5542      $logparent = $self->_log(group_id => $group, domain_id => $domain_id,
    53895543                entry => "[Added ".($args{status} ? 'active' : 'inactive')." domain $zone via AXFR]");
    53905544    } else {
     
    53955549      ($zone_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')");
    53965550      $rdns_id = $zone_id;
    5397       $self->_log(group_id => $group, rdns_id => $rdns_id,
     5551      $logparent = $self->_log(group_id => $group, rdns_id => $rdns_id,
    53985552                entry => "[Added ".($args{status} ? 'active' : 'inactive')." reverse zone $cidr via AXFR]");
    53995553    }
     
    56475801        $logentry .= " ".($rev eq 'y' ? $host : $val)."', TTL $ttl";
    56485802      }
    5649       $self->_log(group_id => $group, domain_id => $domain_id, rdns_id => $rdns_id, entry => $logentry);
     5803      $self->_log(group_id => $group, domain_id => $domain_id, rdns_id => $rdns_id,
     5804        logparent => $logparent, entry => $logentry);
    56505805
    56515806    } # while axfr_next
Note: See TracChangeset for help on using the changeset viewer.