File Coverage

File:/home/mik/work/module/Tivoli/AccessManager/Admin/POP.pm
Coverage:99.6%

linestmtbrancondsubpodtimecode
1package Tivoli::AccessManager::Admin::POP;
2
15
15
15
163
58
234
use strict;
3
15
15
15
188
62
226
use warnings;
4
15
15
15
211
52
283
use Carp;
5
6#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7# $Id: POP.pm 333 2006-11-20 19:07:49Z mik $
8#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
9$Tivoli::AccessManager::Admin::POP::VERSION = '0.04';
10
15
225
use Inline( C => 'DATA',
11                INC => '-I/opt/PolicyDirector/include',
12                LIBS => ' -lpthread -lpdadminapi -lstdc++',
13                CCFLAGS => '-Wall',
14# VERSION => '0.04',
15                NAME => 'Tivoli::AccessManager::Admin::POP',
16
15
15
204
65
            );
17
18
15
15
15
195
52
266
use Tivoli::AccessManager::Admin::Response;
19
20my %audit = (
21            1 => 'permit',
22            2 => 'deny',
23            4 => 'error',
24            8 => 'admin',
25           15 => 'all' );
26
27my %revaudit = map { $audit{$_} => $_ } keys %audit;
28
29my %tod = (
30            1 => 'sun',
31            2 => 'mon',
32            4 => 'tue',
33            8 => 'wed',
34           16 => 'thu',
35           32 => 'fri',
36           64 => 'sat',
37     );
38
39my %revtod = map { $tod{$_} => $_ } keys %tod;
40
41sub _todtolist {
42
9
51
    my $vector = shift;
43
9
28
    my @list;
44
45
9
83
    return qw/any/ unless $vector;
46
47
7
84
80
584
    for my $mask ( sort { $a <=> $b } keys %tod ) {
48
49
198
        next unless $mask;
49
49
448
        push @list, $tod{$mask} if ( ($vector & $mask) == $mask );
50    }
51
7
154
    return @list;
52}
53
54sub _listtotod {
55
7
34
    my $list = shift;
56
7
21
    my $vector = 0;
57
58
7
7
25
30
    for my $day ( @{$list} ) {
59
17
68
        $day = lc($day);
60
17
55
        if ( $day eq 'any' ) {
61
2
9
            $vector = 0;
62
2
11
            last;
63        }
64
15
84
        $vector += $revtod{$day};
65    }
66
7
48
    return $vector;
67}
68
69sub _audtolist {
70
10
48
    my $vector = shift;
71
10
37
    my @list;
72
73
10
100
    return qw/none/ unless $vector;
74
75
7
71
    return qw/all/ if $vector == 15;
76
77
5
94
    for my $mask ( keys %audit ) {
78
25
231
        push @list, $audit{$mask} if ($vector & $mask) == $mask;
79    }
80
5
102
    return @list;
81}
82
83sub _listtoaud {
84
6
28
    my $list = shift;
85
6
11
    my $vector = 0;
86
87
6
6
27
40
    for my $level ( @{$list} ) {
88
6
25
        $level = lc $level;
89
6
62
        if ( $level eq 'all' ) {
90
1
6
            $vector = 15;
91
1
8
            last;
92        }
93        elsif ( $level eq 'none' ) {
94
1
8
            $vector = 0;
95
1
4
            last;
96        }
97
98
4
34
        unless ( defined $revaudit{$level} ) {
99
2
18
            return -1;
100        }
101
2
19
        $vector += $revaudit{$level};
102    }
103
4
30
    return $vector;
104}
105
106sub new {
107
10
1
72
    my $class = shift;
108
10
45
    my $cont = shift;
109
10
96
    my $resp = Tivoli::AccessManager::Admin::Response->new;
110
111
10
188
    unless ( defined($cont) and UNIVERSAL::isa($cont,'Tivoli::AccessManager::Admin::Context' ) ) {
112
2
88
        warn "Incorrect syntax -- did you forget the context?\n";
113
2
19
        return undef;
114    }
115
8
69
    if ( @_ % 2 ) {
116
2
43
        warn "new() invalid syntax -- you did not send a hash\n";
117
2
18
        return undef;
118    }
119
6
42
    my %opts = @_;
120
121
6
40
    my $self = bless {}, $class;
122
123
6
36
    $self->{context} = $cont;
124
6
41
    $self->{name} = $opts{name} || "";
125
6
77
    $self->_popstore();
126
6
16
    $self->{exist} = 0;
127
128
6
37
    if ( $self->{name} ) {
129
4
189684
        $self->{exist} = $self->pop_get($resp);
130    }
131
132
6
58
    return $self
133}
134
135sub create {
136
11
1
101
    my $class = shift;
137
11
96
    my $resp = Tivoli::AccessManager::Admin::Response->new;
138
11
40
    my ($rc,$self,$name);
139
140
11
55
    if ( ref $class ) {
141
7
27
        $self = $class;
142    }
143    else {
144
4
16
        my $pd = shift;
145
4
79
        unless (defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context')){
146
2
24
            $resp->set_message("Invalid Tivoli::AccessManager::Admin::Context object");
147
2
20
            $resp->set_isok(0);
148
2
16
            return $resp;
149        }
150
2
24
        $self = $class->new($pd, @_);
151
2
37
        unless ( defined $self ) {
152
1
10
            $resp->set_isok(0);
153
1
10
            $resp->set_message('Error creating object');
154
1
10
            return $resp;
155        }
156    }
157
158
8
76
    if ( @_ == 1 ) {
159
1
5
        $name = shift;
160    }
161    elsif ( @_ % 2 ) {
162
1
12
        $resp->set_message("Invalid syntax");
163
1
12
        $resp->set_isok(0);
164
1
10
        return $resp;
165    }
166    elsif ( @_ ) {
167
3
21
        my %opts = @_;
168
3
33
        $name = $opts{name} || '';
169    }
170    else {
171
3
14
        $name = '';
172    }
173
174
7
38
    unless ( $self->{name} ) {
175
3
16
        $self->{name} = $name;
176    }
177
178
7
37
    unless ( $self->{name} ) {
179
1
7
        $resp->set_message("create: syntax error -- cannot create nameless POP");
180
1
7
        $resp->set_isok(0);
181
1
6
        return $resp;
182    }
183
184
6
272841
    $rc = $self->pop_create($resp);
185
6
140
    if ( $resp->isok ) {
186
5
43
        $resp->set_value($self);
187
5
39
        $self->{exist} = 1;
188    }
189
6
111
    return $resp;
190}
191
192sub delete {
193
7
1
39
    my $self = shift;
194
7
73
    my $resp = Tivoli::AccessManager::Admin::Response->new;
195
7
15
    my $rc;
196
197
7
50
    unless ( $self->{exist} ) {
198
1
10
        $resp->set_message("Cannot delete a POP that doesn't exist");
199
1
10
        $resp->set_isok(0);
200
1
29
        return $resp;
201    }
202
203
6
279296
    $rc = $self->pop_delete($resp);
204
6
141
    if ( $resp->isok ) {
205
5
48
        $resp->set_value($rc);
206
5
46
        $self->{exist} = 0;
207    }
208
6
58
    return $resp;
209}
210
211sub attach {
212
5
1
37
    my $self = shift;
213
5
16
    my $resp;
214
215
5
39
    if ( @_ ) {
216
4
58
        $resp = $self->objects(attach => ref $_[0] ? $_[0] : [@_]);
217    }
218    else {
219
1
11
        $resp = Tivoli::AccessManager::Admin::Response->new;
220
1
14
        $resp->set_message("Where am I attaching the pop?");
221
1
14
        $resp->set_isok(0);
222    }
223
5
61
    return $resp;
224}
225
226sub detach {
227
4
1
44
    my $self = shift;
228
4
18
    my ($resp,$list);
229
230
4
21
    if ( @_ ) {
231
3
26
        $list = ref $_[0] ? $_[0] : [@_];
232    }
233    else {
234
1
10
        $resp = $self->find;
235
1
14
        return $resp unless $resp->isok;
236
1
16
        $list = [$resp->value];
237    }
238
239
4
34
    $resp = $self->objects(detach => $list);
240
4
53
    return $resp;
241}
242
243sub find {
244
3
1
42
    my $self = shift;
245
3
39
    my $resp = Tivoli::AccessManager::Admin::Response->new;
246
247
3
142103
    my @rc = $self->pop_find( $resp );
248
3
93
    $resp->isok and $resp->set_value(\@rc);
249
250
3
49
    return $resp;
251}
252
253sub objects {
254
25
1
129
    my $self = shift;
255
25
288
    my $resp = Tivoli::AccessManager::Admin::Response->new;
256
25
84
    my $rc;
257
25
281
    my %dispatch = ( detach => \&pop_detach,
258                     attach => \&pop_attach );
259
260
25
176
    if ( @_ % 2 ) {
261
1
12
        $resp->set_message("objects() invalid syntax -- you did not send a hash");
262
1
15
        $resp->set_isok(0);
263
1
10
        return $resp;
264    }
265
24
133
    my %opts = @_;
266
267
24
178
    unless ( $self->{exist} ) {
268
1
17
        $resp->set_message("$self->{name} doesn't exist yet");
269
1
10
        $resp->set_isok(0);
270
1
11
        return $resp;
271    }
272
273
23
92
    for my $key ( qw/detach attach/ ) {
274
275
46
311
        if ( defined( $opts{$key} ) ) {
276
19
65
            my $objs = $opts{$key};
277
19
127
            if ( ref($objs) eq 'ARRAY' ) {
278
14
14
42
81
                for my $obj ( @{$objs} ) {
279
14
567889
                    $rc = $dispatch{$key}->( $self,$resp, ref $obj ? $obj->name : $obj );
280
14
425
                    return $resp unless $resp->isok;
281                }
282            }
283            else {
284
5
142156
                $rc = $dispatch{$key}->( $self, $resp, ref $objs ? $objs->name : $objs );
285
5
146
                return $resp unless $resp->isok;
286            }
287        }
288    }
289
290
20
941124
    my @rc = $self->pop_find( $resp );
291
20
597
    $resp->isok and $resp->set_value(\@rc);
292
293
20
360
    return $resp;
294}
295
296sub list {
297
2
1
19
    my $self = shift;
298
2
30
    my $resp = Tivoli::AccessManager::Admin::Response->new;
299
2
10
    my (@rc,$pd);
300
301
2
18
    if ( ref $self ) {
302
1
8
        $pd = $self->{context};
303    }
304    else {
305
1
7
        $pd = shift;
306    }
307
308
2
96679
    @rc = pop_list( $pd, $resp );
309    # ARGH! I cannot figure out how to test this last freakin branch.
310
2
64
    $resp->isok and $resp->set_value( \@rc );
311
2
28
    return $resp;
312}
313
314sub anyothernw {
315
10
1
76
    my $self = shift;
316
10
127
    my $resp = Tivoli::AccessManager::Admin::Response->new;
317
10
40
    my ($level,$rc);
318
319
10
114
    if ( @_ == 1 ) {
320
3
23
        $level = shift;
321    }
322    elsif ( @_ % 2 ) {
323
1
15
        $resp->set_message("Invalid syntax");
324
1
15
        $resp->set_isok(0);
325
1
5
        return $resp;
326    }
327    elsif ( @_ ) {
328
4
54
        my %opts = @_;
329
4
66
        $level = $opts{level} || '';
330    }
331
332
9
70
    unless ( $self->{exist} ) {
333
1
10
        $resp->set_message("The POP doesn't exist");
334
1
14
        $resp->set_isok(0);
335
1
8
        return $resp;
336    }
337
338    # Since 0 is a valid value for level, I need to use the definedness
339
8
51
    if ( defined($level) ) {
340
6
50
        if ( $level eq 'forbidden' ) {
341
2
145963
            $rc = $self->pop_setanyothernw_forbidden2( $resp );
342        }
343        else {
344
4
31
            $level = 0 if $level eq 'unset';
345
4
380258
            $rc = $self->pop_setanyothernw2($resp, $level || 0 );
346        }
347
6
182
        $resp->isok and $self->pop_get($resp);
348    }
349
350
8
385484
    $rc = $self->pop_getanyothernw2($resp);
351
8
260
    if ( $rc > 100000000 or $rc == 0 ) {
352
6
48
        $rc = 'unset';
353    }
354    elsif ( $rc == 1000 ) {
355
1
14
        $rc = 'forbidden';
356    }
357
358
8
176
    $resp->isok and $resp->set_value($rc);
359
8
106
    return $resp;
360}
361
362sub description {
363
9
1
47
    my $self = shift;
364
9
91
    my $resp = Tivoli::AccessManager::Admin::Response->new;
365
9
35
    my ($rc,$desc);
366
367
9
68
    if ( @_ == 1 ) {
368
3
16
        $desc = shift;
369    }
370    elsif ( @_ % 2 ) {
371
1
18
        $resp->set_message("Invalid syntax");
372
1
17
        $resp->set_isok(0);
373
1
16
        return $resp;
374    }
375    elsif ( @_ ) {
376
2
12
        my %opts = @_;
377
2
20
        $desc = $opts{description} || '';
378    }
379    else {
380
3
14
        $desc = '';
381    }
382
383
8
45
    unless ( $self->{exist} ) {
384
1
10
        $resp->set_message("The POP doesn't exist");
385
1
9
        $resp->set_isok(0);
386
1
10
        return $resp;
387    }
388
389
7
30
    if ($desc) {
390
3
228374
        $rc = $self->pop_setdescription( $resp, $desc);
391
3
71
        if ( $resp->isok ) {
392
2
87685
            $rc = $self->pop_get($resp);
393        }
394
3
52
        return $resp unless $resp->isok;
395    }
396
6
117
    $resp->set_value($self->pop_getdescription());
397
6
32
    return $resp;
398}
399
400sub audit {
401
17
1
99
    my $self = shift;
402
17
168
    my $resp = Tivoli::AccessManager::Admin::Response->new;
403
17
79
    my ($rc,$level);
404
405
17
119
    unless ( $self->{exist} ) {
406
1
10
        $resp->set_message("The POP doesn't exist");
407
1
13
        $resp->set_isok(0);
408
1
9
        return $resp;
409    }
410
411
16
166
    if ( @_ == 1 ) {
412
6
39
        $level = shift;
413    }
414    elsif ( @_ % 2 ) {
415
1
11
        $resp->set_message("Invalid syntax");
416
1
11
        $resp->set_isok(0);
417
1
9
        return $resp;
418    }
419    elsif ( @_ ) {
420
4
38
        my %opts = @_;
421
4
46
        $level = $opts{level} || '';
422    }
423    else {
424
5
27
        $level = '';
425    }
426    # If we are setting the audit level and an array has been sent, we need to
427    # translate that into a bitmask.
428
15
86
    if ($level) {
429
9
34
        my $vec;
430        # If we have been sent an array, translate that into a bitmask
431
9
107
        if ( ref( $level ) ) {
432
3
21
            $vec = _listtoaud($level);
433
3
24
            if ( $vec == -1 ) {
434
1
1
8
19
                $resp->set_message("Invalid audit level(s): " . join(", ",@{$level}));
435
1
16
                $resp->set_isok(0);
436
1
10
                return $resp;
437            }
438        }
439        elsif ( $level =~ /^-?\d+$/ ) {
440            # Make sure the provided bitmask makes sense
441
3
59
            if ( $level > 15 or $level < 0 ) {
442
2
28
                $resp->set_message("Invalid audit level: $level");
443
2
15
                $resp->set_isok(0);
444
2
18
                return $resp;
445            }
446
1
9
            $vec = $level;
447        }
448        else {
449
3
39
            $vec = _listtoaud([$level]);
450
3
31
            if ( $vec == -1 ) {
451
1
15
                $resp->set_message("Invalid audit level: $level");
452
1
11
                $resp->set_isok(0);
453
1
9
                return $resp;
454            }
455        }
456
457
5
430396
        $rc = $self->pop_setauditlevel( $resp, $vec);
458
5
159
        $resp->isok and $self->pop_get($resp);
459    }
460
461
11
182
    if ( $resp->isok ) {
462
10
294
        $level = $self->pop_getauditlevel;
463
464
10
81
        $resp->set_value($level,[_audtolist($level)]);
465    }
466
11
112
    return $resp;
467}
468
469sub ipauth {
470
9
1
72
    my $self = shift;
471
9
98
    my $resp = Tivoli::AccessManager::Admin::Response->new;
472
9
37
    my $done = 0;
473
9
43
    my $rc;
474
9
147
    my %dispatch = ( add => \&pop_setipauth2,
475                     remove => \&pop_removeipauth2,
476                     forbidden => \&pop_setipauth_forbidden2
477                 );
478
479
9
87
    unless ( $self->{exist} ) {
480
1
14
        $resp->set_message("The POP doesn't exist");
481
1
10
        $resp->set_isok(0);
482
1
10
        return $resp;
483    }
484
485
8
75
    if ( @_ % 2 ) {
486
1
19
        $resp->set_message("ipauth invalid syntax -- you did not send a hash");
487
1
17
        $resp->set_isok(0);
488
1
19
        return $resp;
489    }
490
7
36
    my %opts = @_;
491
492
7
43
    for my $op ( qw/add remove forbidden/ ) {
493
19
132
        next unless defined $opts{$op};
494
6
6
18
53
        for my $ip ( keys %{$opts{$op}} ) {
495
7
65
            unless (defined($opts{$op}{$ip}{NETMASK}) ) {
496
1
13
                $resp->set_message("No netmask provided for $ip -- SKIPPING");
497
1
10
                $resp->set_iswarning(1);
498
1
8
                delete $opts{$op}{$ip};
499
1
10
                next;
500            }
501
6
59
            my @call = ($self, $resp, $ip, $opts{$op}{$ip}{NETMASK});
502
6
50
            if ( $op eq 'add' ) {
503
4
31
                unless (defined($opts{$op}{$ip}{AUTHLEVEL}) ) {
504
1
18
                    $resp->set_message("No auth level provided for $ip -- SKIPPING");
505
1
12
                    $resp->set_iswarning(1);
506
1
9
                    delete $opts{$op}{$ip};
507
1
11
                    next;
508                }
509
3
33
                push @call,$opts{$op}{$ip}{AUTHLEVEL};
510            }
511
512
5
432589
            $rc = $dispatch{$op}->(@call);
513
5
146
            return $resp unless $resp->isok;
514        }
515    }
516
517    # After all that, get the new ipauths and embed them
518
6
287208
    $rc = $self->pop_getipauth2($resp);
519
6
207
    $resp->set_value( $rc );
520
521
6
137
    return $resp;
522}
523
524sub qop {
525
10
1
74
    my $self = shift;
526
10
143
    my $resp = Tivoli::AccessManager::Admin::Response->new;
527
10
62
    my ($rc,$qop);
528
529
10
112
    if ( @_ == 1 ) {
530
5
36
        $qop = shift;
531    }
532    elsif ( @_ % 2 ) {
533
1
12
        $resp->set_message("Invalid syntax");
534
1
11
        $resp->set_isok(0);
535
1
8
        return $resp;
536    }
537    elsif ( @_ ) {
538
2
20
        my %opts = @_;
539
2
39
        $qop = $opts{qop} || '';
540    }
541    else {
542
2
17
        $qop = '';
543    }
544
545
9
77
    unless ( $self->{exist} ) {
546
1
19
        $resp->set_message("The POP doesn't exist");
547
1
16
        $resp->set_isok(0);
548
1
11
        return $resp;
549    }
550
551
8
56
    if ( $qop ) {
552
5
95
        unless ( $qop eq 'none' or
553                 $qop eq 'integrity' or
554                 $qop eq 'privacy' ) {
555
1
12
            $resp->set_message("qop must be one of: none, integrity or privacy");
556
1
10
            $resp->set_isok(0);
557
1
9
            return $resp;
558        }
559
4
338547
        $rc = $self->pop_setqop($resp, $qop);
560
4
133
        $resp->isok and $self->pop_get($resp);
561    }
562
7
123
    $resp->isok and $resp->set_value($self->pop_getqop());
563
7
84
    return $resp;
564}
565
566sub _miltomin {
567
16
71
    my $miltime = shift;
568
16
727012
    return ( $miltime - $miltime % 100 ) * .6 + $miltime % 100;
569}
570
571sub _mintomil {
572
18
67
    my $mins = shift;
573
574
18
311
    return sprintf( "%04d", ($mins - $mins % 60)/.6 + $mins % 60 );
575}
576
577sub tod {
578
14
1
121
    my $self = shift;
579
14
179
    my $resp = Tivoli::AccessManager::Admin::Response->new;
580
14
72
    my ($start,$end,$days, $reference, %rc, @list);
581
582
14
108
    if ( @_ % 2 ) {
583
1
16
        $resp->set_message("tod invalid syntax -- you did not send a hash");
584
1
12
        $resp->set_isok(0);
585
1
11
        return $resp;
586    }
587
13
147
    my %opts = @_;
588
589
13
130
    $reference = $opts{reference} || '';
590
591
13
91
    unless ( $self->{exist} ) {
592
1
11
        $resp->set_message("The POP doesn't exist");
593
1
11
        $resp->set_isok(0);
594
1
14
        return $resp;
595    }
596
597
12
84
    if ( defined( $opts{days} ) ) {
598
10
59
        $reference = $reference eq 'UTC';
599
600
10
75
        if ( ref($opts{days}) ) {
601
8
8
23
53
            for my $tday ( @{$opts{days}} ) {
602
18
154
                unless ( defined($revtod{$tday}) or $tday eq 'any' ) {
603
1
35
                    $resp->set_message( "Invalid day: $tday. Valid days are " . join(", ", keys %revtod ) );
604
1
12
                    $resp->set_isok(0);
605
1
17
                    return $resp;
606                }
607            }
608
7
56
            $days = _listtotod( $opts{days} )
609        }
610        else {
611
2
27
            if ( $opts{days} > 127 ) {
612
1
18
                $resp->set_message( "days bitmask > 127");
613
1
17
                $resp->set_isok(0);
614
1
20
                return $resp;
615            }
616
1
5
            $days = $opts{days};
617        }
618
619
8
62
        $start = defined($opts{start}) ? $opts{start} : 0;
620
8
41
        $end = defined($opts{end}) ? $opts{end} : 2359;
621
622
8
59
        $self->pop_settod( $resp,
623                           $days,
624                           _miltomin($start),
625                           _miltomin($end),
626                           $reference );
627
8
272
        $resp->isok and $self->pop_get($resp);
628    }
629
630
10
222
    if ( $resp->isok ) {
631
9
364
        @list = $self->pop_gettod;
632
9
142
        $rc{days} = [ _todtolist( $list[0] || 0 ) ];
633
9
121
        $rc{start} = _mintomil( $list[1] || 0);
634
9
95
        $rc{end} = _mintomil( $list[2] || 0);
635
9
84
        $rc{reference} = $list[3] ? 'UTC' : 'local';
636
637
9
113
        $resp->set_value( \%rc );
638    }
639
10
185
    return $resp;
640}
641
642sub warnmode {
643
9
1
68
    my $self = shift;
644
9
24
    my $mode;
645
9
106
    my $resp = Tivoli::AccessManager::Admin::Response->new;
646
647
9
113
    if ( @_ == 1 ) {
648
2
13
        $mode = shift;
649    }
650    elsif ( @_ % 2 ) {
651
1
11
        $resp->set_message("Invalid syntax");
652
1
11
        $resp->set_isok(0);
653
1
5
        return $resp;
654    }
655    elsif ( @_ ) {
656
3
21
        my %opts = @_;
657
3
36
        $mode = $opts{mode};
658    }
659
660
8
63
    unless ( $self->{exist} ) {
661
1
16
        $resp->set_message("Cannot set warnmode on a non-existent POP");
662
1
10
        $resp->set_isok(0);
663
1
8
        return $resp;
664    }
665
666
7
37
    if ( defined($mode) ) {
667
3
242809
        $self->pop_setwarnmode( $resp, $mode ? 1 : 0 );
668
3
87
        $resp->isok and $self->pop_get($resp);
669    }
670
671
7
125
    $resp->isok and $resp->set_value( $self->pop_getwarnmode );
672
7
70
    return $resp;
673}
674
675sub name {
676
2
1
12
    my $self = shift;
677
2
25
    my $resp = Tivoli::AccessManager::Admin::Response->new;
678
679
2
18
    unless ( $self->{exist} ) {
680
1
11
        $resp->set_message("The POP doesn't exist");
681
1
11
        $resp->set_isok(0);
682
1
8
        return $resp;
683    }
684
1
65
    $resp->set_value( $self->pop_getid() );
685
1
11
    return $resp;
686}
687
688sub _addval {
689
5
24
    my $self = shift;
690
5
24
    my $opts = shift;
691
5
13
    my @attrs;
692
693
5
51
    my $resp = Tivoli::AccessManager::Admin::Response->new();
694
5
15
    my $rc;
695
696
5
57
    for my $key ( keys %$opts ) {
697        # Loop if given an array. Don't otherwise.
698
6
56
        if ( ref($opts->{$key} ) ) {
699
3
3
13
24
            for my $val ( @{$opts->{$key}} ) {
700
5
236426
                $rc = $self->pop_attrput( $resp, $key, $val );
701
5
148
                return $resp unless $resp->isok;
702            }
703        }
704        else {
705
3
139962
            $rc = $self->pop_attrput( $resp, $key, $opts->{$key} );
706        }
707
5
132
        return $resp unless $resp->isok;
708    }
709
3
58
    return $resp;
710}
711
712sub _remvalue {
713
4
29
    my $self = shift;
714
4
18
    my $opts = shift;
715
716
4
56
    my $resp = Tivoli::AccessManager::Admin::Response->new();
717
718
4
19
    my $rc;
719
720
4
48
    for my $key ( keys %$opts ) {
721        # Loop if given an array. Don't otherwise.
722
4
52
        if ( ref($opts->{$key}) ) {
723
2
2
10
18
            for my $val ( @{$opts->{$key}} ) {
724
3
142440
                $rc = $self->pop_attrdelval( $resp, $key, $val );
725
3
102
                return $resp unless $resp->isok;
726            }
727        }
728        else {
729
2
98800
            $rc = $self->pop_attrdelval( $resp, $key, $opts->{$key} );
730        }
731
3
82
        return $resp unless $resp->isok;
732    }
733
2
40
    return $resp;
734}
735
736sub _remkey {
737
4
21
    my $self = shift;
738
4
32
    my $resp = Tivoli::AccessManager::Admin::Response->new();
739
4
31
    my $key = shift;
740
741
4
12
    my (@keys,$rc);
742
743
744
4
50
    if ( ref($key) eq 'ARRAY' ) {
745
2
17
        push @keys, @$key;
746    }
747    elsif ( ref($key) ) {
748
1
14
        $resp->set_message("remkey invalid syntax -- you must provide an array refs or scalars");
749
1
11
        $resp->set_isok(0);
750
1
9
        return $resp;
751    }
752    else {
753
1
10
        push @keys, $key;
754    }
755
756
3
19
    for ( @keys ) {
757
4
193386
        $rc = $self->pop_attrdelkey( $resp, $_ );
758
4
125
        last unless $resp->isok;
759    }
760
3
45
    return $resp;
761}
762
763sub attributes {
764
16
1
144
    my $self = shift;
765
16
244
    my $resp = Tivoli::AccessManager::Admin::Response->new;
766
16
1460
    my $rhash = {};
767
768
16
181
    if ( @_ % 2 ) {
769
1
14
        $resp->set_message("attributes invalid syntax -- you did not send a hash");
770
1
9
        $resp->set_isok(0);
771
1
8
        return $resp;
772    }
773
15
143
    my %opts = @_;
774
775
15
121
    unless ( $self->{exist} ) {
776
1
10
        $resp->set_message("Cannot modify attributes on a non-existent POP");
777
1
11
        $resp->set_isok(0);
778
1
10
        return $resp;
779    }
780
781
14
135
    if ( defined $opts{remove} ) {
782
4
54
        $resp = $self->_remvalue( $opts{remove} );
783
4
52
        return $resp unless $resp->isok;
784    }
785
786
12
95
    if ( defined $opts{removekey} ) {
787
4
39
        $resp = $self->_remkey( $opts{removekey} );
788
4
45
        return $resp unless $resp->isok;
789    }
790
791
10
88
    if ( defined $opts{add} ) {
792
5
55
        $resp = $self->_addval( $opts{add} );
793
5
62
        return $resp unless $resp->isok;
794    }
795
796    # just in case one of the above branches was actually taken, refresh the
797    # cached object
798
8
396763
    $self->pop_get($resp);
799
8
276
    if ( $resp->isok ) {
800
7
662
        for my $key ( $self->pop_attrlist ) {
801
8
492
            $rhash->{$key} = [ $self->pop_attrget($key) ];
802        }
803
7
135
        $resp->set_value( $rhash );
804    }
805
8
180
    return $resp;
806}
807
808sub DESTROY {
809
6
105
    $_[0]->_popfree;
810}
811
812
1
1
10
sub exist { $_[0]->{exist} }
813
8141;
815
816 - 1350
=head1 NAME

Tivoli::AccessManager::Admin::POP

=head1 SYNOPSIS

    use Tivoli::AccessManager::Admin;
    my ($pop,$resp,$obj);
    my $pd = Tivoli::AccessManager::Admin->new( password => $pswd);

    # Instantiate a new pop
    $pop = Tivoli::AccessManager::Admin::POP->new($pd, name => 'test');

    # Actually create the POP in the policy db
    $resp = $pop->create();

    # Set its description
    $resp = $pop->description( "POP goes the monkey" );

    # Attach it
    $resp = $pop->attach('/test/monkey');

    # See where it is now attached
    $resp = $pop->find;

    # Detach it now
    $resp = $pop->detach('/test/monkey');

    # Get a full list of POPs
    $resp = Tivoli::AccessManager::Admin::POP->list($pd);

    # Set the level for any other network
    $resp = $pop->anyothernw( 2 );
    # Forbid access from any other network
    $resp = $pop->anyothernw( 'forbidden' );

    # Set an IP auth level for a few networks
    $resp = $pop->ipauth(add => {'192.168.8.0' => {NETMASK => '255.255.255.0',
						   AUTHLEVEL => 1 }.
				 '192.168.9.0' => {NETMASK => '255.255.255.0',
						   AUTHLEVEL => 2}
				}
			);

    # Forbid the entire 10.x.x.x network
    $resp = $pop->ipauth(forbidden => {'10.0.0.0' => {NETMASK=>'255.0.0.0'}});

    # Set the audit level
    $resp = $pop->audit( [qw/all/] );

    # Set the QoP level
    $resp = $pop->qop('privacy');

    # Set Time of Day access
    $resp = $pop->tod( days => [qw/monday tuesday wednesday/],
		       start => '0800',
		       end   => '1800',
		     );

    # Set the warn mode
    $resp = $pop->warnmode(1);

    # Set an extended attribute or two
    $resp = $pop->attributes( add => { foobar => 'baz',
				       silly  => [qw/one two three/] }
			    );
    # Clean up after myself
    $pop->delete;

=head1 DESCRIPTION

L<Tivoli::AccessManager::Admin::POP> allows manipulation of POPs via perl.

=head1 CONSTRUCTORS

=head2 new( PDADMIN[, name =E<gt> NAME] )

Creates a blessed L<Tivoli::AccessManager::Admin::POP> object.  It should be noted that creating
the object in perl is not the same thing as creating it in TAM's policy
database.  See L</"create"> to do that.

=head3 Parameters

=over 4

=item PDADMIN

An initialized L<Tivoli::AccessManager::Admin::Context> object.  This parameter is, as usual, required.

=item name =E<gt> NAME

The POP's name.  This is technically speaking optional, but it may have some
unintentional side effects if not provided.  Namely, the object will assume it
doesn't exist, which will cause problems when trying to do anything to it.

In short, if you intend on calling L</"create"> you can forget this parameter.
Otherwise, include it.

=back

=head3 Returns

A blessed L<Tivoli::AccessManager::Admin::POP> object.  If there is an error, you will get
undef.

=head2 create(PDADMIN, name =E<gt> NAME)

Creates the object in TAM's policy database and returns the blessed reference.

=head3 Parameters

=over 4

=item PDADMIN

An initialized L<Tivoli::AccessManager::Admin::Context> object.  This parameter is required.

=item name =E<gt> NAME

The POP's name.  When using L</"create"> as a constructor, this parameter is
required.

=back

=head3 Returns

A L<Tivoli::AccessManager::Admin::Response> object containing the newly created object.  I refer
you to that module's documentation for digging the value out.

=head1 CLASS METHODS

Class methods behave like instance methods in that they all return a
L<Tivoli::AccessManager::Admin::Response> object.

=head2 list(PDADMIN)

List all of the POPs defined in TAM.

=head3 Parameters

=over 4

=item PDADMIN

The standard, initialized L<Tivoli::AccessManager::Admin::Context> object.

=back

=head3 Returns

The list of all defined POPs.

=head1 METHODS

All of the methods return a L<Tivoli::AccessManager::Admin::Response> object unless otherwise
explicitly stated.  See the documentation for that module on how to coax the
values out.

The methods, for the most part, follow the same pattern.  If the optional
parameters are sent, it has the effect of setting the attributes.  All
methods calls will embed the results of a 'get' in the
L<Tivoli::AccessManager::Admin::Response> object.

=head2 create([name =E<gt> NAME])

Creates a new POP in TAM's policy db.  This method can be used as both class
and instance method.

=head3 Parameters

=over 4

=item name =E<gt> NAME

The name of the new POP.  This parameter is only required when you did not use
it in the L</"new"> call.

=back

=head3 Returns

The success or failure of the create operation.

=head2 delete

Deletes the object.

=head3 Parameters

None

=head3 Returns

The success or failure of the operation.  Please note that you really should
detach a POP before trying to delete it.

=head2 objects( [detach =E<gt> OBJECTS[, [attach =E<gt> OBJECTS]] )

Attaches or detaches a POP.  Weird little fact.  The C API for ACLs does not
contain an attach or detach method -- you have to use the methods for the
protected objects.  POPs have their own attach and detach calls.

If both parameters are used, all of the detaches will be done before
attaching.

=head3 Parameters

=over 4

=item detach =E<gt> OBJECTS

Detach the POP from the listed objects.  OBJECTS can be a list or a single
value.  It can be either a string (e.g., '/test/monkey') or a
L<Tivoli::AccessManager::Admin::ProtObject> object or a mix of them.

=item attach =E<gt> OBJECTS

Attach the POP to the listed objects.  The same combination of values can be
used as listed above.

=back

=head3 Returns

The success or failure of the operation.  You will also get a list of the
current places the POP is attached.

=head2 attach OBJECTS[,...]

A convenience method that wraps L</"objects"> with an attach message.  See
L</"objects"> for a full description of the parameters and returns.

=head2 detach OBJECTS[,...]

A convenience method that wraps L</"objects"> with a detach message.  See
L</"objects"> for a full description of the parameters and returns.

=head2 find

Finds and lists everyplace the POP is attached.

=head3 Parameters

None

=head3 Returns

A possibly empty list of everyplace the POP is attached,

=head2 list

L</"list"> can also be used as an instance method, although I personally do
not think it makes much sense.

=head3 Parameters

None, when used as an instance method.

=head3 Returns

A list of all defined POPs.

=head2 anyothernw([<NUMBER>|unset|forbidden])

Set the authentication level for any other network.

=head3 Parameters

=over 4

=item <NUMBER>|unset|forbidden

Sets the authentication level to the provided number, unset or forbidden.

=back

=head3 Returns

The success or failure of the operation, along with the current (possibly new)
level.

=head2 description([STRING])

Sets or gets the POP's description.

=head3 Parameters

=over 4

=item STRING

The new description.  This parameter is optional.

=back

=head3 Returns

The POP's description if set, an empty string otherwise.

=head2 audit( [BITMASK|[STRING[,STRING...]]] )

Sets the audit level on the POP.

=head3 Parameters

=over 4

=item BITMASK|STRING|ARRAYREF

The underlying C library uses a bit mask to set the audit level.  You can
either send this bitmask, a single word that will be translated into a bitmask
or a list of words that will be translated into a bit mask.

If the words "all" or "none" appear anywhere in the list, the bitmask will be
set as indicated below.

The name to bitmask mapping looks like this:

=over 4

=item * 
none   =E<gt> 0

=item * 
permit =E<gt> 1

=item * 
deny   =E<gt> 2

=item *
error  =E<gt> 4

=item *
admin  =E<gt> 8

=item *
all    =E<gt> 15

=back

=back

=head3 Returns

The numeric bitmask if evaluated in scalar context; the wordier list if used
in list context.

=head2 ipauth( [add =E<gt> HASHREF, remove =E<gt> HASHREF, forbidden =E<gt> HASHREF] )

Sets the IP based authentication restrictions.

=head3 Parameters

=over 4

=item add =E<gt> HASHREF

Sets the required authentication level for an IP address and/or
network.  The referant of the hash ref is a hash of hashes, keyed off the IP
address.  The contents of the subhashes look like:

=over 4

=item NETMASK =E<gt> <NETMASK>

The netmask for the ip address.  It should be requested in the quad-dot format
(e.g., 255.255.255.0).  I should likely be smart enough to handle CIDR
notation and what ever IPV6 uses, but I am not.

=item AUTHLEVEL =E<gt> <NUMBER>

Required only when adding, this specifies the authentication level for the
IP/netmask.  There is no default -- I didn't think it safe to guess.

=back

=item remove =E<gt> HASHREF

Removes the IP auth restriction from the POP.  The referant of the hash ref
should look just like it does for adding.

=item forbidden =E<gt> HASHREF

Forbids access from some subnet. The referant of the hash ref
should look just like it does for adding.

=back

=head3 Returns

An array of hashes that look mostly like the parameter hashes.  For the
record, I dislike this function.

=head2 qop( [level] )

Sets the "quality of protection" on the POP.

=head3 Parameters

=over 4

=item level

The level of protection, it must be one of these three options: none,
integrity or privacy.  You will need to refer to the WebSEAL Administration
Guide for the meaning of those three values.

=back

=head3 Returns

The current level of protection.

=head2 tod ( days =E<gt> [array], start =E<gt> N, end =E<gt> N, reference =E<gt> local | UTC )

Returns the current time of day access policy on the POP.

=head3 Parameters

=over 4

=item days 

B<days> should be a reference to an array containing some combination of:
  mon, tue, wed, thu, fri, sat, sun or any.

If the word 'any' is found anywhere in the array, it will over ride all the
others.

=item start

The beginning of the allowed access time, expressed in 24-hour format.  Since
perl will try to interpret any number starting with a 0 as an octal number (
leading to annoying problems with 09xx ), you need to either drop the
preceding 0 ( eg, 900 ) or specify it as a string ( '0900' ).

=item end

The end of the allowed access time.  See the previous item for the caveats.

=item UTC|local

Under the covers, start and end are calculated as minutes past midnight.  TAM
needs to know if you are referencing midnight UTC or midnight local time.  The
default is 'local'.

=back

=head3 Returns

A L<Tivoli::AccessManager::Admin::Response> object, the value of which is a hash with the
key/value pairs:

=over 4

=item days

An array reference to the days for which the policy is enforced.  If the TOD
policy is unset, this refers to an empty array.

=item start

The time of day when access is allowed, expressed in 24-hour format. If the TOD
policy is unset, this will be zero.


=item end

The time of day when access is denied, expressed in 24-hour format. If the TOD
policy is unset, this will be zero.

=item reference

UTC or local.  If the policy is unset, this will be local.

=head2 warnmode([0|1])

Sets the warnmode on the POP.

=head3 Parameters

=over 4

=item O | 1

Disble or enable the warn mode.

=back

=head3 Returns

The current value

=head2 attributes([add => { attribute => value },][remove => { attribute => value },][removekey => attribute])

Adds keys and attributes to the POP, removes values from an attribute and
removes a key.

=head3 Parameters

=over 4

=item add => { attribute => value[,...] }

An anonymous hash pointing to the attributes and the value(s) for that
attribute.  If you want to set more than one value on the attribute, it must
be sent as an anonymous array.

If the attribute does not already exist, it will be created.

=item remove => { attribute => value[,...] }

Removes the value(s) from the named attribute(s).  If you are removing
multiple values from an attribute, you must use an anonymous array.  Note,
this will not remove the attribute, only values from the attribute.

=item removekey => value[,...]

Removes attributes from the POP.  As always, if you want to remove multiple
attributes, you need to use an anonymous array.

=back

=head3 Returns

A hash containing the defined attributes as the keys and the values.  All of
the values are returned as anonymous arrays.

=head2 exist

Returns true if the POP exists, false otherwise.

=back 

=cut
1351