Home | History | Annotate | Download | only in libbsm
      1 #
      2 # CDDL HEADER START
      3 #
      4 # The contents of this file are subject to the terms of the
      5 # Common Development and Distribution License (the "License").
      6 # You may not use this file except in compliance with the License.
      7 #
      8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9 # or http://www.opensolaris.org/os/licensing.
     10 # See the License for the specific language governing permissions
     11 # and limitations under the License.
     12 #
     13 # When distributing Covered Code, include this CDDL HEADER in each
     14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15 # If applicable, add the following below this CDDL HEADER, with the
     16 # fields enclosed by brackets "[]" replaced with your own identifying
     17 # information: Portions Copyright [yyyy] [name of copyright owner]
     18 #
     19 # CDDL HEADER END
     20 #
     21 #
     22 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23 # Use is subject to license terms.
     24 #
     25 # ident	"%Z%%M%	%I%	%E% SMI"
     26 #
     27 
     28 use xmlHandlers;
     29 
     30 package externalEvent;
     31 
     32 1;
     33 
     34 sub new {
     35     my $pkg = shift;
     36     my $id  = shift;
     37     my $obj = shift;
     38 
     39     my @kid = $obj->getKids(); # kids of event are entry or allowed_types
     40 
     41     # separate kids into classes and create hash of entries and an 
     42     # array of includes
     43 
     44     my %entry = ();
     45     my @entry = ();
     46     my @allowed_types = ();
     47     my @include = ();
     48     my $internalName = '';
     49 
     50     my $kid;
     51     foreach $kid (@kid) {
     52 	my $class = $kid->getClass();
     53 	my $kidId = $kid->getAttr('id');
     54 
     55 	if ($class eq 'entry') {
     56 	    my $tokenId = 'undefined';
     57 	    my $format = '';
     58 	    my $internal = $kid->getKid('internal');
     59 	    if (defined $internal) {
     60 	      $tokenId = $internal->getAttr('token');
     61 	      $format = $internal->getAttr('format');
     62 	      $format = '' unless defined $format;
     63 	    }
     64 	    my $comment;
     65 	    my $commentKid = $kid->getKid('comment');
     66 	    if (defined $commentKid) {
     67 	    	$comment = $commentKid->getContent;
     68 	    }
     69 	    my $external = $kid->getKid('external');
     70 	    if (defined ($external)) {
     71 		$entry{$kidId} = [$external, $kid, $tokenId, $format, $comment];
     72 		push (@entry, $kidId);
     73 	    }
     74 	    else {
     75 		print STDERR "no external attributes defined for $id/$kidId\n";
     76 	    }
     77 	} # handle event id translation...
     78 	elsif ($class eq 'altname') {
     79 	    $internalName = $kid->getAttr('id');
     80 	    unless (defined $internalName) {
     81 		print STDERR "missing id for internal name of $id\n";
     82 		$internalName = 'error';
     83 	    }
     84 	}
     85 	elsif ($class eq 'allowed_types') {
     86 	    my $content = $kid->getContent();
     87 	    @allowed_types = (@allowed_types, split(/\s*,\s*/, $content));
     88 	}
     89     }
     90     my @entryCopy = @entry;
     91     return bless {'id'			=> $id,
     92 		  'internalName'	=> $internalName,
     93 		  'allowed_types'	=> \@allowed_types,
     94 		  'entry'		=> \%entry,
     95 		  'entryList'		=> \@entry,
     96 		  'entryListCopy'	=> \@entryCopy,
     97 		  'include'		=> \@include,
     98 		  'xmlObj'		=> $obj}, $pkg;
     99 }
    100 
    101 # return id
    102 
    103 sub getExternalName {
    104   my $pkg = shift;
    105 
    106   return $pkg->{'id'};
    107 }
    108 
    109 
    110 # return internal name if it exists, else id
    111 
    112 sub getInternalName {
    113     $pkg = shift;
    114 
    115     if ($pkg->{'internalName'}) {
    116 	return $pkg->{'internalName'};
    117     }
    118     else {
    119 	return $pkg->{'id'};
    120     }
    121 }
    122 
    123 # getNextEntry reads from 'entryList' destructively
    124 # but resets when the list after the list is emptied
    125 
    126 sub getNextEntry {
    127     my $pkg = shift;
    128 
    129     unless (@{$pkg->{'entryList'}}) {
    130 	@{$pkg->{'entryList'}} = @{$pkg->{'entryListCopy'}};
    131 	return undef;
    132     }
    133     my $id = shift @{$pkg->{'entryList'}};
    134 
    135     return ($pkg->getEntry($id));  # getEntry returns an array 
    136 }
    137 
    138 # getEntryIds returns list of all ids from entryList
    139 
    140 sub getEntryIds {
    141     my $pkg = shift;
    142     return (@{$pkg->{'entryList'}});
    143 }
    144 
    145 # getEntry returns a selected entry for the current event
    146 
    147 sub getEntry {
    148     my $pkg = shift;
    149     my $id  = shift;  #entry id
    150 
    151     my $ref = $pkg->{'entry'};
    152     my $array = $$ref{$id};
    153 
    154     return @$array;
    155 }
    156 
    157 # getNextInclude reads from 'include' destructively
    158 
    159 sub getNextInclude {
    160     my $pkg = shift;
    161 
    162     return shift @{$pkg->{'include'}};
    163 }
    164 
    165 # getIncludes returns list of 'include'
    166 
    167 sub getIncludes {
    168     my $pkg = shift;
    169     return @{$pkg->{'include'}};
    170 }
    171 
    172 # return a reference to the list of event id's allowed for
    173 # this generic event
    174 
    175 sub getAllowedTypes {
    176     my $pkg = shift;
    177 
    178     return $pkg->{'allowed_types'};
    179 }
    180 
    181 package internalEvent;
    182 
    183 1;
    184 
    185 sub new {
    186     my $pkg = shift;
    187     my $id  = shift;
    188     my $obj = shift;
    189 
    190     my @kid = $obj->getKids(); # kids of event are entry
    191 
    192     my @entry = ();
    193 
    194     my $reorder = 0;
    195     if ($reorder = $obj->getAttr('reorder')) {
    196 	$reorder = 1 if $reorder eq 'yes';
    197     }
    198     my $kid;
    199     foreach $kid (@kid) {
    200       my $class = $kid->getClass();
    201       my $id = $kid->getAttr('id');
    202       
    203       if ($class eq 'entry') {
    204 	my $internal = $kid->getKid('internal');
    205 	if (defined ($internal)) {
    206 	  push (@entry, [$internal, $kid]);
    207 	}
    208 	else {
    209 	  print STDERR "no internal attributes defined for $id\n";
    210 	}
    211       }
    212     }
    213     return bless {'id'       => $id,
    214 		  'reorder'  => $reorder,
    215 		  'entry'    => \@entry,
    216 		  'xmlObj'   => $obj}, $pkg;
    217 }
    218 
    219 # getEntries returns a list of all entry references
    220 
    221 sub getEntries {
    222     my $pkg = shift;
    223 
    224     return undef unless @{$pkg->{'entry'}};
    225 
    226     return @{$pkg->{'entry'}};
    227 }
    228 
    229 sub isReorder {
    230   my $pkg = shift;
    231 
    232   return $pkg->{'reorder'};
    233 }
    234 
    235 sub getId {
    236     my $pkg = shift;
    237 
    238     return $pkg->{'id'};
    239 }
    240 
    241 package eventDef;
    242 
    243 %uniqueId = ();
    244 
    245 1;
    246 
    247 sub new {
    248     my $pkg = shift;
    249     my $id  = shift;
    250     my $obj = shift;
    251     my $super = shift;
    252 
    253     my $omit;
    254     my $type;
    255     my $header;
    256     my $idNo;
    257     my $javaToo;
    258     my $title = '';
    259     my @program = ();
    260     my @see = ();
    261 
    262     $omit = '' unless $omit = $obj->getAttr('omit');
    263     $type = '' unless $type = $obj->getAttr('type');
    264     $header = 0 unless $header = $obj->getAttr('header');
    265     $idNo = '' unless $idNo = $obj->getAttr('idNo');
    266 
    267     if ($idNo ne '' && $uniqueId{$idNo}) {
    268         print STDERR "$uniqueId{$idNo} and $id have the same id ($idNo)\n";
    269     }
    270     else {
    271         $uniqueId{$idNo} = $id;
    272     }
    273 
    274     return bless {'id'		=> $id,
    275 		  'header'	=> $header,
    276 		  'idNo'	=> $idNo,
    277 		  'omit'	=> $omit,
    278 		  'super'	=> $super,
    279 		  'type'	=> $type,
    280 		  'title'	=> $title,
    281 		  'program'	=> \@program,
    282 		  'see'		=> \@see,
    283 		  'external'	=> 0,
    284 		  'internal'	=> 0}, $pkg;
    285 }
    286 
    287 # putDef is called at the end of an <event></event> block, so
    288 # it sees a completed object.
    289 
    290 sub putDef {
    291     my $pkg  = shift;
    292     my $obj  = shift;  # ref to xmlHandlers event object
    293     my $context = shift;
    294 
    295     my $id = $pkg->{'id'};
    296 
    297     if ($context eq 'internal') {
    298 	$pkg->{$context} = new internalEvent($id, $obj);
    299 	return undef;
    300     } elsif ($context eq 'external') {
    301 	my $ref = $pkg->{$context} = new externalEvent($id, $obj);
    302 	return $ref->{'internalName'};
    303     }
    304 }
    305 
    306 sub getId {
    307     my $pkg = shift;
    308 
    309     return $pkg->{'id'};
    310 }
    311 
    312 sub getHeader {
    313     my $pkg = shift;
    314 
    315     return $pkg->{'header'};
    316 }
    317 
    318 sub getIdNo {
    319     my $pkg = shift;
    320 
    321     return $pkg->{'idNo'};
    322 }
    323 
    324 sub getSuperClass {
    325     my $pkg = shift;
    326 
    327     return $pkg->{'super'};
    328 }
    329 
    330 sub getOmit {
    331     my $pkg = shift;
    332 
    333     return $pkg->{'omit'};
    334 }
    335 
    336 sub getType {
    337     my $pkg = shift;
    338 
    339     return $pkg->{'type'};
    340 }
    341 
    342 sub getTitle {
    343     return shift->{'title'};
    344 }
    345 
    346 sub getProgram {
    347     return shift->{'program'};
    348 }
    349 
    350 sub getSee {
    351     return shift->{'see'};
    352 }
    353 
    354 sub getInternal {
    355     my $pkg = shift;
    356 
    357     return $pkg->{'internal'};
    358 }
    359 
    360 sub getExternal {
    361     my $pkg = shift;
    362 
    363     return $pkg->{'external'};
    364 }
    365 
    366 # this isn't fully implemented; just a skeleton
    367 
    368 package tokenDef;
    369 
    370 1;
    371 
    372 sub new {
    373     my $pkg = shift;
    374     my $obj = shift;
    375     my $id  = shift;
    376 
    377     $usage	= $obj->getAttr('usage');
    378     $usage = '' unless defined $usage;
    379 
    380     return bless {'id'		=> $id,
    381 		  'usage'	=> $usage
    382 		  }, $pkg;
    383 }
    384 
    385 sub getId {
    386     my $pkg = shift;
    387 
    388     return $pkg->{'id'};
    389 }
    390 
    391 sub getUsage {
    392     my $pkg = shift;
    393 
    394     return $pkg->{'usage'};
    395 }
    396 
    397 package messageList;
    398 
    399 1;
    400 
    401 sub new {
    402     my $pkg = shift;
    403     my $obj = shift;
    404     my $id  = shift;
    405     my $header = shift;
    406     my $start = shift;
    407     my $public = shift;
    408     my $deprecated = shift;
    409 
    410     my @msg = ();
    411 
    412     my @kid = $obj->getKids(); # kids of msg_list are msg
    413     my $kid;
    414     foreach $kid (@kid) {
    415 	my $class = $kid->getClass();
    416 	if ($class eq 'msg') {
    417 	    my $text = $kid->getContent();
    418 	    $text = '' unless defined ($text);
    419 	    my $msgId = $kid->getAttr('id');
    420 	    if (defined ($msgId)) {
    421 	        push(@msg, join('::', $msgId, $text));
    422 	    }
    423 	    else {
    424 	        print STDERR "missing id for $class <msg>\n";
    425 	    }
    426 	}
    427 	else {
    428 	    print STDERR "invalid tag in <msg_list> block: $class\n";
    429 	}
    430     }
    431 
    432     return bless {'id'		=> $id,
    433 		  'header'	=> $header,
    434 		  'msg'		=> \@msg,
    435 		  'start'	=> $start,
    436 		  'public'	=> $public,
    437 		  'deprecated'	=> $deprecated
    438 		 }, $pkg;
    439 }
    440 
    441 sub getId {
    442     my $pkg = shift;
    443 
    444     return $pkg->{'id'};
    445 }
    446 
    447 sub getMsgStart {
    448     my $pkg = shift;
    449 
    450     return $pkg->{'start'};
    451 }
    452 
    453 sub getDeprecated {
    454     my $pkg = shift;
    455 
    456     return $pkg->{'deprecated'};
    457 }
    458 
    459 sub getMsgPublic {
    460     my $pkg = shift;
    461 
    462     return $pkg->{'public'};
    463 }
    464 
    465 sub getHeader {
    466     my $pkg = shift;
    467 
    468     return $pkg->{'header'};
    469 }
    470 
    471 # destructive read of @msg...
    472 
    473 sub getNextMsg {
    474     my $pkg = shift;
    475 
    476     my @msg = @{$pkg->{'msg'}};
    477 
    478     return undef unless @msg;
    479 
    480     my $text = pop(@msg);
    481     $pkg->{'msg'} = \@msg;
    482     return $text;
    483 }
    484 
    485 # returns all msgs
    486 sub getMsgs {
    487     my $pkg = shift;
    488 
    489     return @{$pkg->{'msg'}};
    490 }
    491 
    492 
    493 package auditxml;
    494 
    495 # These aren't internal state because the callback functions don't
    496 # have the object handle.
    497 
    498 @debug   = ();            # stack for nesting debug state
    499 %event   = ();            # event name => $objRef
    500 @event   = ();            # event id
    501 %token   = ();            # token name => $objRef
    502 @token   = ();            # token id
    503 %msg_list = ();           # messageList string list id to obj
    504 @msg_list = ();           # id list
    505 %service = ();            # valid service names
    506 %externalToInternal = (); # map external event name to internal event name
    507 
    508 1;
    509 
    510 sub new {
    511     my $pkg  = shift;
    512     my $file = shift;  # xml file to be parsed
    513 
    514     register('event',      \&eventStart,  \&eventEnd);
    515     register('entry',      0,             \&entry);
    516     register('external',   0,             \&external);
    517     register('internal',   0,             \&internal);
    518     register('include',    0,             \&include);
    519     register('token',      0,             \&token);
    520     register('service',    0,             \&service);
    521     register('msg_list',   0,             \&msg_list);
    522     register('msg',        0,             \&msg);
    523 
    524     # do not use register() for debug because register generates extra
    525     # debug information
    526 
    527     xmlHandlers::registerStartCallback('debug', \&debugStart);
    528     xmlHandlers::registerEndCallback('debug', \&debugEnd);
    529 
    530     $xml = new xmlHandlers(0, 'top level', $file);
    531 
    532     return bless {'xmlObj'     => $xml,
    533 	          'firstToken' => 1,
    534 	          'firstEvent' => 1}, $pkg;
    535 }
    536 
    537 # local function -- register both the auditxml function and the
    538 # xmlHandler callback
    539 
    540 sub register {
    541     my $localName     = shift;
    542     my $startFunction = shift;
    543     my $endFunction = shift;
    544     
    545     if ($startFunction) {
    546       xmlHandlers::registerStartCallback($localName, \&completed);
    547 	$startFunction{$localName} = $startFunction;
    548     }
    549     if ($endFunction) {
    550       xmlHandlers::registerEndCallback($localName, \&completed);
    551 	$endFunction{$localName} = $endFunction;
    552     }
    553 }
    554 
    555 sub completed {
    556     my $obj = shift;
    557     my $callbackSource = shift;
    558 
    559     my $id  = $obj->getAttr('id');
    560     my $class = $obj->getClass();
    561 
    562     if ($main::debug) {
    563 	print "*** $callbackSource: $class", (defined ($id)) ? "= $id\n" : "\n";
    564 
    565 	my %attributes = $obj->getAttributes();
    566 	my $attribute;
    567 	foreach $attribute (keys %attributes) {
    568 	    print "*** $attribute = $attributes{$attribute}\n";
    569 	}
    570 	my $content = $obj->getContent();
    571 	print "*** content = $content\n" if defined $content;
    572     }
    573     if ($callbackSource eq 'start') {
    574 	&{$startFunction{$class}}($obj);
    575     }
    576     elsif ($callbackSource eq 'end') {
    577 	&{$endFunction{$class}}($obj);
    578     }
    579     else {
    580 	print STDERR "no auditxml function defined for $class\n";
    581     }
    582 }
    583 
    584 # getNextEvent reads from @event destructively.  'firstEvent' could
    585 # be used to make a copy from which to read.
    586 
    587 sub getNextEvent {
    588     my $pkg = shift;
    589 
    590     return undef unless (@event);
    591     if ($pkg->{'firstEvent'}) {
    592 	@token = sort @token;
    593 	$pkg->{'firstEvent'} = 1;
    594     }
    595 
    596     my $id = shift @event;
    597 
    598     return $event{$id};
    599 }
    600 
    601 # returns all event ids
    602 sub getEventIds {
    603    my $pkg = shift;
    604 
    605    return @event;
    606 }
    607 
    608 # returns event for id
    609 sub getEvent {
    610     my $pkg = shift;
    611     my $id = shift;
    612 
    613     return $event{$id};
    614 }
    615 
    616 sub getToken {
    617     my $pkg = shift;
    618     my $id = shift;
    619 
    620     return $token{$id};
    621 }
    622 
    623 # getNextToken reads from @token destructively.  'firstToken' could
    624 # be used to make a copy from which to read.
    625 
    626 sub getNextToken {
    627     my $pkg = shift;
    628 
    629     return undef unless (@token);
    630 
    631     if ($pkg->{'firstToken'}) {
    632 	@token = sort @token;
    633 	$pkg->{'firstToken'} = 1;
    634     }
    635     my $id = shift @token;
    636 
    637     return $token{$id};
    638 }
    639 
    640 # return token Ids
    641 
    642 sub getTokenIds {
    643     my $pkg = shift;
    644 
    645     return @token;
    646 }
    647 
    648 # getNextMsgId reads from @msg_list destructively.
    649 
    650 sub getNextMsgId {
    651     my $pkg = shift;
    652 
    653     return undef unless (@msg_list);
    654 
    655     my $id = shift @msg_list;
    656 
    657     return ($id, $msg_list{$id});
    658 }
    659 
    660 sub getMsgIds {
    661     my $pkg = shift;
    662 
    663     return @msg_list;
    664 }
    665 
    666 sub getMsg {
    667     my $pkg = shift;
    668     my $id = shift;
    669 
    670     return $msg_list{$id};
    671 }
    672 
    673 sub external {
    674 }
    675 
    676 sub internal {
    677 
    678 }
    679 
    680 sub eventStart {
    681     my $obj  = shift;
    682 
    683     my $id = $obj->getAttr('id');
    684     
    685     unless ($id) {
    686 	print STDERR "eventStart can't get a valid id\n";
    687 	return;
    688     }
    689     unless (defined $event{$id}) {
    690         my $super;
    691 	if ($super = $obj->getAttr('instance_of')) {
    692 	    $super = $event{$super};
    693 	} else {
    694 	    $super = 0;
    695 	}
    696 	$event{$id} = new eventDef($id, $obj, $super);
    697         push (@event, $id);
    698     } else {
    699 	print STDERR "duplicate event id: $id\n";
    700     }
    701 }
    702 
    703 sub eventEnd {
    704     my $obj  = shift;
    705 
    706     my $id    = $obj->getAttr('id');
    707     unless (defined $id) {
    708 	print STDERR "event element is missing required id attribute\n";
    709 	return;
    710     }
    711     print "event = $id\n" if $main::debug;
    712 
    713     foreach my $kid ($obj->getKids) {
    714     	my $class = $kid->getClass;
    715     	next unless ($class =~ /title|program|see/);
    716 	my $content = $kid->getContent;
    717 	if ($class eq 'title') {
    718 	    $event{$id}->{$class} = $content;
    719 	} else {
    720 	    push @{$event{$id}->{$class}}, $content;
    721 	}
    722     }
    723     $event{$id}->putDef($obj, 'internal');
    724 
    725     my $internalName = $event{$id}->putDef($obj, 'external');
    726 
    727     $externalToInternal{$id} = $internalName if $internalName;
    728 }
    729 
    730 # class method
    731 
    732 #sub getInternalName {
    733 #    my $name = shift;
    734 #
    735 #    return $externalToInternal{$name};
    736 #}
    737 
    738 sub entry {
    739 }
    740 
    741 #sub include {
    742 #    my $obj  = shift;
    743 #
    744 #    my $id = $obj->getAttr('id');
    745 #
    746 #    if (defined $id) {
    747 #	print "include = $id\n" if $main::debug;
    748 #    }
    749 #    else {
    750 #	print STDERR "include element is missing required id attribute\n";
    751 #    }
    752 #}
    753 
    754 sub token {
    755     my $obj  = shift;
    756 
    757     my $id = $obj->getAttr('id');
    758     
    759     if (defined $id) {
    760 	print "token = $id\n" if $main::debug;
    761 	$token{$id} = new tokenDef($obj, $id);
    762 	push (@token, $id);
    763     }
    764     else {
    765 	print STDERR "token element is missing required id attribute\n";
    766     }
    767 }
    768 
    769 sub msg_list {
    770     my $obj = shift;
    771 
    772     my $id = $obj->getAttr('id');
    773     my $header = $obj->getAttr('header');
    774     my $start = $obj->getAttr('start');
    775     my $public = $obj->getAttr('public');
    776     my $deprecated = $obj->getAttr('deprecated');
    777 
    778     $header = 0 unless $header;
    779     $start = 0 unless $start;
    780     $public = ($public) ? 1 : 0;
    781     $deprecated = ($deprecated) ? 1 : 0;
    782 
    783     if (defined $id) {
    784 	print "msg_list = $id\n" if $main::debug;
    785 	$msg_list{$id} = new messageList($obj, $id, $header, $start,
    786 	    $public, $deprecated);
    787 	push (@msg_list, $id);
    788     }
    789     else {
    790 	print STDERR
    791 	    "msg_list element is missing required id attribute\n";
    792     }
    793 }
    794 
    795 sub msg {
    796 #    my $obj = shift;
    797 }
    798 
    799 # Service name was dropped during PSARC review
    800 
    801 sub service {
    802     my $obj = shift;
    803 
    804     my $name = $obj->getAttr('name');
    805     my $id   = $obj->getAttr('id');
    806 
    807     if ((defined $id) && (defined $name)) {
    808 	print "service $name = $id\n" if $main::debug;
    809 	$service{$name} = $id;
    810     }
    811     elsif (defined $name) {
    812 	print STDERR "service $name is missing an id number\n";
    813     }
    814     elsif (defined $id) {
    815 	print STDERR "service name missing for id = $id\n";
    816     }
    817     else {
    818 	print STDERR "missing both name and id for a service entry\n";
    819     }
    820 }
    821 
    822 #sub getServices {
    823 #
    824 #    return %service;
    825 #}
    826 
    827 # <debug set="on"> or <debug set="off"> or <debug>
    828 # if the set attribute is omitted, debug state is toggled
    829 
    830 # debugStart / debugEnd are used to insure debug state is
    831 # scoped to the block between <debug> and </debug>
    832 
    833 sub debugStart {
    834     my $obj = shift;
    835 
    836     push (@debug, $main::debug);
    837     my $debug = $main::debug;
    838 
    839     my $state = $obj->getAttr('set');
    840 
    841     if (defined $state) {
    842 	$main::debug = ($state eq 'on') ? 1 : 0;
    843     }
    844     else {
    845 	$main::debug = !$debug;
    846     }
    847     if ($debug != $main::debug) {
    848 	print 'debug is ', $main::debug ? 'on' : 'off', "\n";
    849     }
    850 }
    851 
    852 sub debugEnd {
    853     my $obj = shift;
    854 
    855     my $debug = $main::debug;
    856     $main::debug = pop (@debug);
    857 
    858     if ($debug != $main::debug) {
    859 	print 'debug is ', $main::debug ? 'on' : 'off', "\n";
    860     }
    861 }
    862