Вы находитесь на странице: 1из 432

.

.
,
.

.

.

.
.


,
e-mail :

http://web-bookcase.ru/

Perl

. -

Canlm/iCj Lx Lx '/

. -
Perl
!.

.

.
.
.
. , .
. , .
.

. -
Perl . - . . - : -,
2001.-496 ., .
ISBN 5-93286-024-3
-
Linux . , Unix, Windows NT/2000 MacOS.
Perl ,
,
: ;
;
NIS DNS; DBI ODBC; LDAP ADSI; ; ;
SNMP.
- , ,
.
Perl.
. .
ISBN 5-93286-024-3
ISBN 0-56592-609-9()
-, 2001
""
^^- Authorized translation of the English edition 2000 O'Reilly & Associates Inc. This
translation is published and sold by permission of O'Reilly & Associates Inc., the owner of all rights to publish and sell the same.
, . , , .
-. 193148, -, . , 4,
. (812) 324-5353, edit@symbol.ru. 000054 25.12.98.
06.09.2001. 1/^- .
. 31 . . 3000 . 1533.
. . .
,
.
197110, -, ., 15.

1.

15

-
Perl
,



15
15
17
19
20
23
28

2.

29

Perl


File::Find



3.

29
30
35
41
52
60
62
62

Unix
Windows NT/2000




4.
MacOS
NT/2000
Unix

63
64
73

<.
!':'.

84
119
120
122
123
125
142
150

160
162

5. TCP/IP

163


NIS, NIS+ WINS
(DNS)

164
177
182
203
203

6.

204

?
Finger:
WHOIS
LDAP:
ADSI ( )

204
205
209
212
241
261
261

7. SQL

264

SQL- Perl
DBI
ODBC




265
268
274
277
284
286
293
293

8.





9.




294
.'V
*.;

294
301
315
339
339
341
341
342
348
351
359



10.



SNMP



388
388
389
390
399
407
417
427
432
433

A. RCS

435

B. LDAP

438

C. XML

444

D. SQL

449

E. SNMP

462

478


. - - - (Northeastern University College of Computer Science). 14 Brandies University,
(Cambridge Technology Group) MIT.
, The
Perl Journal . -
.


Perl - , . . , ,
, Perl
,
.
Perl , .
Perl, , - .

.
. :
1
, , , ,
.
, (, Unix Windows NT/2000). , , Perl.
2
,
.
. Perl ,
. , , ,
Perl.

10

3
, .
- ,
Perl. ,
, XML,
.
4
4 (, MacOS) ( WinNT/2000). . , , , Perl
.
5 TCP/IP
TCP/IP . ,
, (NIS) -
(DNS). ,
Perl.
6

,
. ,
,
. , LDAP ADSI,
, Perl.
7 SQL

. ,
SQL.
- DBI ODBC, .
8
, Perl
. Perl

11

,
.
9
. , ( ) . Unix WinNT/2000. .
10
, . , Perl . ,
, SNMP ( ) .

,
, .
, ,
-, .
(RCS), LDAP (
), SQL, XML SNMP.

, , , , (URL), , .

Perl, .

.

,
, .

12


, ,
,
( - ). ,
, ,
:
O'Reilly & Associates, Inc.
101 Morris Street
Sebastopol, CA 95472
(800) 998-9938 ( )
(707) 829-0515 (/)
(707) 829-0104 ()
, . , :
info@oreilly.com
, :
bookquestions@oreilly.com
, -, .
,
. :
http://www.oreilly.com/catalog/perlsysadmin/
O'Reilly:
http://www.oreilly.com

, .
, , - .
,
Perl, ( Perl-) . - ,

. ,
, Perl- . -

14

CCS Systems, , ,
. -
.
, , . , ,
.
, . . .
- , - , ( )
. - , ,
. .
, , , , ,
- . ,
.
-
. -,
, , . , , , , ,
- .
- .


Perl
,



-
. ,
, , . : , . .
,
.
,
, . ,
, . - ,
, , . ,
. , ,
. ,
Perl.
Perl

, .
Perl?

16

1.

. , ,
: ,
: , ,
. . , - , , .
, ,
.
- ; Perl -
. Perl
, WWW
.
Perl ,
:


Unix - , .

. . , .

,
- .



. ,
( ). .

Perl .

, Perl
. , :
- Perl
. Python .

Perl .
, Perl.

Perl . Tel
.

17

Perl ,
.

- .
Perl,
.
,
, 1966-1968 ,
- .
, : , !. :
, !, . - , ,
.
:

. , . Unix- Essential System
Administration ( )
(1 Frisch) (O'Reilly & Associates) Unix System Administration
Handbook (UNIX: ) He (Evi Nemeth), (Garth Snyder) .
(Trent R. Hein) (Prentice-Hall) - ,
. ,
: Unix, Windows NT/2000
MacOS.
, , ,
. , , ,
. , XML, , , , . , ,
, , , LDAP SNMP. , , , , - .

'

IB

1.


.
,
- .
, .
, ,
, , , . ,
(, , ).
Perl,
, Perl.
, , Perl. , , ,
.
Perl,
. , Perl - . ,
, - .
,

Perl, .
Perl: . ,
, , :
, ,
.
, . , , , , . .
, ( , ).

19


, .
15 . ,
, ,
, . , . , .

,
- .
, :
, Perl
,
Perl,
. ,
Learning Perl 1 ( Perl) (Randal
L. Schwartz) (Tom Christiansen) (O'Reilly)
Learning Perl on Win32 Systems ( Perl Win32) (Randal L. Schwartz), (Erik Olson)
(Tom Christiansen) (O'Reilly),
, .
, ()
,
(), . , , ,
.. , (, WMI Windows 2000 SNMP).

()
, . , Perl,
BHV, , 2000 .

1.
. , Unix
. , , .
:
Perl
Perl,
, . - http://
www.perl.com
, . Perl 5.005 ( - 1). Unix
Perl,
, Win32 - , ActiveState (build 522), MacOS - MacPerl (5.2.0r4).
Perl
, . , .
, .
, . , ,
.

Perl
.
:
Perl- (Comprehensive Perl Archive Network, CPAN)
CPAN - Perl, ,
,
. http://www.cpan.org.
CPAN -
, (Elaine Ashton), (Graham Barr)
1

5.6.1. - . . .


(Clifton Posey) http://search.cpan.org. CPAN Search:
.

Perl (Perl Package
Manager, PPM),
Perl Win32. ( ActiveState), .
http://www.activestate.com/Products/ActivePerl/docs/faq/ActivePerl-faq2.html.
Win32 ActiveState, . MacOS MacPerl
Module Porters http://pudge.net/mmp/.
-
CPAN .
, ,
.
, ?
, .
Perl ,
perlmodinstall.pod ( perldoc perlmodinstall,
).
,
, .
Unix
:
1. .
2. perl Makefile.? L, Makefile.
3. make, .
4. make test, ,
.
5. make install,
.
, (Andreas J. Kbnig) CPAN
( Perl).
, :
% perl -MCPAN -e shell
cpan> install modulename

22

CPAN , (. .
, PAN
). PAN, , . perldoc
CPAN,
.
Win32
Win32 Unix,
-. , Unix, , WinZip (http://www.winzip.com), ,
nmake
(ftp://ftp.microsoft.com/Softlib/MSLFILES/nmakel5.exe)
make - .

. Perl Win32 , ActiveState Perl .
CPAN. ppm.pl, Perl. ,
, perl ppm.pl bin:

C:\Perl\bin>perl ppm.pl
interactive shell (1.1.1) - type 'help' for available commands.
PPM> install module-name
, CPAN, . help ,
, .
MacOS
MacOS - . (Chris Nandor) ( CPAN, http://pudge.net/macperl),
MacOS CPAN,
.
- CPAN , Perl. , installme. (. . .tar.gz), installme, CPAN.

23

MacOS perlmodinstall.pod,
macperl modinstall.pod. http://pudge.net/
macperl.

,
. ,
, ,
. Unix Windows NT/2000
, . . root Administrator. . , , .
, ( ) , . , . ,
, Perl .

, Perl. , , . root Administrator. , , ,
.
,
.
, ,
,
.


. , . ,
,
.
Perl, Unix Linux, $< $>:

24

1.
($<,$>) = (getpwnam('nobody 1 ),getpwnam('nobody 1 ));
, nobody,
.
, $( $) .
Windows NT Windows 2000 , .
Windows 2000 , RunAs,
. Windows NT Windows 2000 Act as
part of the operating system . User Manager User Manager for Domains:
1. Policies User Rights.
2. Show Advanced User Rights.
3. Act as part of the operating system .
4. Add... , . ,
Show Users.
5. , , .
Replace a process level token ,
, Bypass traverse checking (.
W i n 3 2 : : AdminMisc). ,
Perl LogonAsllser() (David Roth) Win32: : AdminMisc,
http://www.roth.net:
use Win32: -.AdminMisc;
die " $user\n"
if ('Win32::AdminMisc::LogonAsUser('',$user,$userpw);
: , , LogonAsUser().


, , ,
. -

25

, , , (, ).
8 Perl Cookbook1 (Perl: ) (
Christiansen) (Nathan Torkington) (O'Reilly).
- . , ,
, .
: , () ():,
2049 (
, , ).
. - Poison NULL Byte, Perl
CGI. (
). - (\000) Perl . Perl
. .
,
. ,
, - , :
if ($user ne "root"){ < }
$user root\000 (. .
root ), . ,
root, .
, . ,
- :
$input =~ tr/\000//d;
, . Perl - (taint mode). perlsec, Perl,
,
, .
1

, Perl: ,
, 2000 . - ..

26

1.


, , , . Unix
, . , ,
. ,
.
, .
:
1. stat() . , , ,
. .
2. .
3. stat ().
4. , 1 3, ,

.
bigbuffy 9 , .
,
. :
open(TEMPFILE,">/tmp/temp.$$") or die " /tmp/
temp.$$:$!\n";
,
. ($$) , , , . - ,
. , , .
, ,
.
, . ,
POSIX: :tmpnam(). ,
:
use POSIX qw(tmpnam);

27

for (1..20M print POSIX: :tmpnam(), "\n"; }


, ,
:
sysopen(TEMPFILE,$tmpname,0_RDWR|0_CREAT|0_EXCL,0666);
,
( ). 10: : File->new_tmpf ile() 10:: File ( ),
.
POSIX: : t m p n a m ( ) 10:: File->new_tmpfile(), a
7
Perl Cookbook (Perl: ).
File: :Temp (Tim Jenness)
.

, ,
. , :
1. .
2. .
, 1,5, ,
.
2, , ,
1, ,
(. ., ,
). ,
.
, ., . ,
. , .

, .
, , . -

28

1.

, , .
- .
, , .

http://dwheeler.com/secure-programs/Secure-Programs-HOWTO.html HOWTO ( ) Linux, .
http:/'/www.cs.ucdavis.edu/-bishop/secprog.html
(Matt Bishop).
http://www.homeport.org/~adam/review.html - (Adam Shostack).
http://www.dnaco.net/~kragen/security-holes.html -
, ( )
(Kragen Sitaker).
http://www.shmoo.com/securecode/ , .
Perl CGI Problems, Rain Forest Puppy (Phrack Magazine, 1999). http://www.insecure.org/news/P5507.txt Phrack http://www.phrack.com/archive.html.
Perl Cookbook, Tom Christiansen, Nathan Torkington (O'Reilly, 1998)
.

Perl
,,


File::Find


Perl
. ,
, , ,
. , - . ,
. ,
. ,
, . . .
. Windows NT, . , . , , , . :
- ? ?
Linux,
, . Linux ; . NTFS, .
NTFS Linux, (Martin von Low-

30

2.
is) http://www.informatik.hu-berlin.de/~loewis/ntfs/ ( Linux 2.2), , , .
, , .
, . ,
, . , (gnutar),
. , ? , . , , ?
gnutar . Perl!
,
. , ,
,
, , Perl.


,
. , , ,
- . (
, ), Perl, .
Unix
Unix , Berkeley Fast File System. - (, Solaris (Access Control Lists) , Digital Unix advfs, , . .). , ,
Unix-.
, , Unix (/). , ,
, ,

, .
- . Unix . ASCII-, -
, .
Microsoft Windows NT/2000
Windows NT ( 4.0) : FAT
( ) NTFS ( NT). Windows 2000 FAT32 -
FAT,
.
Windows NT
FAT DOS. ,
.
(FAT ) 8.3. ,
,
, .
Unix, ,
FAT
().
FAT VFAT, FAT
. Windows NT
Windows 2000. VFAT , . . VFAT
/,

FAT.
- ,
8.3. , Downloaded Program Files , DOWNLO~1.
VFAT Unix :
1. FAT . Unix , ( MYFAVORITEFILE favorite f i l e ) , . FAT VFAT .
2. - ,
. FAT -

32

2.
. Perl
. Perl . , (. . $path=' \ d i r \ d i r \ f i l e n a m e ' ) , . ( \\server\dir\file) .
.
, . \\\\winnt\\temp\\. . ., , - , .
3. FAT , . - Read-only (
) System ().
4. , - . FAT , . , c:\home\cindy\docs\resume\current.doc.
FAT32 NTFS ,
VFAT.
.
NTFS , . . Unicode . Unicode - ,
.
NTFS , Windows NT/2000
Unix. NTFS
(ACL). ACL
.
, .
,
UNC - .
UNC - ( ) . , , : \\\_. Perl,
.
:
$path = "\\\\server\\sharename\\directory\\file"


MacOS
GUI- ,
MacOS (HFS, Hierarchical File System) , . : /_::::_. , .
, HFS , (:).
HFS, , . MacOS - ,
, . , Unix ../../../FileName
, .
MacOS (. . ^."FileName),
.
HFS 31 . MacOS
8.1 , MacOS, HFS+,
Unicode 255 .
HFS+ , MacOS.

( , Perl)
MacOS fork () . (data fork)
(resource fork). , . ( , ),
( , . .) , . , MacPerl
.
MacPerl . , -s
. , , Macintosh Toolbox.
HFS
: creator () type (),

2.

34

,
. , , FAT ( .doc .).
, / .

, ,
(. 2.1).
2.1.
OS - -

Unix (- /


Berkeley
Fast File Sys-

tem )

MacOS (HFS)


-
/dir/file
dir/file

31

/
,

volume:
dir:file

:dir:file

255 - Drive:\

dir\file

dir\file

ACL, , Unicode

8.3

Drive:\
dir\file

dir\file

( 255
-

HFS+)

WinNT/2000
(NTFS)

DOS (BASIC

FAT)

Perl
Perl , .
File: :Spec,
. , catf ile :
use File::Spec;
$path = File::Spec->catfile("home","cindy","docs","resume.doc");

35

Windows NT/ 2000 $path home\cindy\docs\resume. doc, Unix me/cindy/docs/resume.doc . . File: :Spec ,
c u r d i r updir,
( . . , ).

. - , File: :Spec: '.Functions File:: Spec.

- , Perl. - , . .
. Unix
find, Windows NT/2000 - Find Files or Folders Search For Files or
Folders, MacOS - Find File Sherlock.
, ,
, . ,
Perl ,
.
,
, .
Unix . ( Unix,
.)
,
, . -
, . Unix - core-,
. , , , .
.
. , , core-
- .

2.

36

, ,
, . ,
($! ), opendir():
opendir(DIR,".") or die "He : $!\";
, D I R , readdir(), . r e a d d i r ( ) , ( ,
) :
# / @names
names = readdir(OIR) or die " :$!\";
:
closedir(DIR);
:
foreach $name (@names) {
next if ($name eq ".");
next if ($name eq "..");

?
if (-d $name){
print " : $name\n";

next;
for
if ($name eq "core") {
print "!\n";

core?

, . ,
. ,
, , . , .
,

, (
). (. .
), .

37

:
, , . .
(.. , ), . - .
, ,
, . . .
:
1. , .
? , .
2. 1 ,
.
3. . ,
3 .
. ,
, ,
. ,
.
, . . , , - .
,
, . , ,
, ,
.
. ,
ScanDirectoryO. ScanDirectoryO - , . , .
,
. :
#!/usr/bin/perl -s
-s
. NT/2000
-s (.. perl -s script),
# perl.

38

2.

-s ,
8
# ( 1:1: : :) () .
use Cwd;
8
8 , ,
8 "core"
sub ScanDirectory{
my ($workdir) = shift;
my (Sstartdir) = &cwd; 8 ,
chdir($workdir) or die " $workdir:$!\n";
opendir(DIR, ".") or die " $workdir:$!\n";
my names = readdir(DIR) or die " $workdir:$!\n";
closedir(DIR);
foreach my $name (@names){
next if ($name eq ". ");
next if ($name eq ". . ");
if (-1 $name){
8
next;
}
if (-d $name){
8 ?
&ScanDi rectory ($name);
next;
}
if ($name eq "core") {
8 "core"?
8 -,
8
if (defined $r){
unlink($name) or die " $name:$!\n";
}
else {
print " $workdir!\n";

chdir($startdir) or
die " Sstartdir; $!\n";
&ScanDirectory(". ");
'
,
. , ,

39

, , ,
. (. .
ScanDi recto () )
.
core-, .
, : ,
- ( remove - ) .
Perl -s (#! / u s r / b i n /
perl -s) .
, . , -
Getopt. ( -),
( $). Perl -, -
, core-.
,
, . : Perl,
, .
, NT/2000 ,
, , . :
if (Sname eq "core") {
:

if (Sname eq "MSCREATE.DIR") {
,
,
Microsoft.
, , . , , , , , ,
.

40

2.
:
use Cwd;
$1=1;
/
sub ScanDirectory {
my ($workdir) = shift;
my($startdir) = &cwd; ,
chdir($workdir) or die " $workdir:$!\n";
opendir(DIR, ".") or die " $workdir:$!\n";
my @names = readdir(DIR);
closedir(DIR);
foreach my $name (@names){
next if ($name eq ".");
next if ($name eq "..");
if (-d $name){
# ?
&ScanDirectory($name);
next;
>
unless (&CheckFile($name)){
print &cwd. "/".$name. "\n"; tt

}

}
chdir($startdir) or die " $startdir:$!\n";
}
sub CheckFile{
my($name) = shift;
print STDERR " ". &cwd."/"-$name."\n";
#
my @stat = stat($name);
if (!$stat[4] && !$stat[5] 8A !$stat[6] && !$stat[7] && !$stat[8]){
return 0;
}
tt
unless (open(T,"$name")){
return 0;
>
tt
for (my $1=0;$i< $stat[7];$!++){
my $r=sysread(T, $i, 1);
if ($r != 1) {
close(T);
return 0;

File::Find

41

close(T);
return 1;
&ScanDirectory(".");


. stat,
, (, ). , , . , . . ,
( ),
, .
, ,
sysread( ), , read ,
Perl. , sysread( ) , .
X, , +1 , +2, +3 . . ,
. , . , , . . , .
, , , .
( ), 95 16000. , , ; . Perl .

File::Find
, , .
Perl File : : Find, find
Unix. - find2perl -
Perl.

42

2.

find2perl Perl
Unix-. MacOS,
, Macintosh Programmer's Workshop (MPW) ,
@ARGV . ,
(Chris Nandor), MacPerl: Power and Ease (MacPerl: ):
@ARGV = @ARGV ? @ARGV :
split "\s", MacPerl::Ask("Arguments?");
File: :Find, find2perl find.pl,
. , .
, beesknees
/home. , Unix
find:
% find /home -name beesknees -print
find2perl:
% find2perl /home -name beesknees -print
:
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_sheH;
require "find.pl";
#
&find('/home');
exit;
sub wanted {
/~beesknees$/ && print("$name\n");

}
, find2perl, .
find.pl
r e q u i r e , &f i n d ( ) . & w a n t e d ( ) , ,
.

File::Find

43

, , :
, File: .Find,
.
File:: Find ,
Unix, MacOS, NT, VMS . .
, find2perl,
Perl 4 (, require
.pi), find.pl PerlS. ,
.
, ,
, perl -7 , :
% perl-e 'print join("\n",@INC,"")'
&wanted(),
. &wanted()
&f ind() ( &File:: Find: : f ind(), )
. &wanted()
. , ,
beesknees. , && Perl print,
.
&wanted() . &wanted()
,
.
&wanted(), f i n d
.
,
.
& f i n d ( ) - &wanted() ( , ). , , , File:: Find.
F i l e : : F i n d
, core-,
. :
% find2perl -name core -print

44

2.
require "find.pl";

&find('.');
exit;
sub wanted {
/~core$/ && print("$name\n");
}
-s Perl
&wanted():
sub wanted {
/~core$/ && print("$name\n") && defined $r && unlink($name);
}
-
( core-). , :
sub wanted {
/~core$/ && -s $name && print("$name\n") &&
defined $r && unlink($name);
}
, , , core . /dev/null core , core- .
-s , , . , :
1. ,
core-. Perl,
Unix file. , core-, ,
core-.
2. . -
, core, , - .
Unix .
MacOS Windows NT/2000.
, MacOS - '
, ,

) File::Find

45

. . , , SimpleText,
ttxt ( ) TEXT ( ). Perl (
MacPerl) MacPerl: :GetFileInfo(). :
$type = MacPerl:-.GetFilelnfo(filename);

:
($creator,$type) = MacPerl::GetFileInfo(filename);
MacOS, :
use File::Find;
&File::Find::find(\&wanted,"Macintosh HD:");
sub wanted!
-f $_ && MacPerl::GetFileInfo($_) eq "TEXT" &&
print "$Find::File::name\n";
}
, , , , . .
File: :Find , find.pl.
, $name, File:: Find, ,
. , File: :Find (. 2.2).
2.2. File::Find


SFile::Find: :dir
$File::Find::name (. . SFile:: Find:: dir/$_)

, NT/2000:
use File::Find;
use W i n 3 2 : : F i l e ;
&File::Find::find(\&wanted, "\\");
sub wanted!
-f $ &&

46

2.
S attr
Win32::File::GetAttributes
(Win32::File::GetAttributes($_,Sattr)) &&
(Sattr & HIDDEN) &&
print "$File::Find::name\n";
}


(. . , HIDDEN).
NTFS .
NTFS, ,
Everyone,
:
use File::Find;
use Win32::FileSecurity;
# DACL
Sfullmask = Win32::FileSecurity::MakeMask(FULL);
&find(\&wanted,"\\");
sub wanted {
# Win32::FileSecurity::Get
pagefile.sys,
next if ($_ eq "pagefile.sys");
/ f \ 00
(,-T
_) &&

Win32::FileSecurity::Get($_, \%users) &&


(defined $users{"Everyone"}) &&
($users{"Everyone"} == $fullmask) &&
print "$File::Find::name\n";
}

ACL ( Windows NT).


, Everyone.
, Everyone
( MakeMask()) ,
.
, , .
( ) NT
, Metadata C o r r u p t i o n E r r o r ( ).
- , ,
, Windows NT. ,

File::Find

47

. ,
, .
, ,
. ,
:
require "find.pl";

&find(\&wanted, '. ')1;
print "max:$max\n";
exit;
sub wanted {
return unless -f $_;
if (length($_) > $maxlength){
$max = $name;
$maxlength = length($_);
}
if (length($name) > 200) { print $name,"\n";}
}
200 , . ,
Perl.
Unix,
. ,
, - . , , .
, .
- , , - , .

, - . needspace, , . needspace,
,
\&wanted . - . ..

2.

48


File::Find
File: : Find ? :
1. , ,
, .
, NTFS Linux, , - .
, , . File: : F i n d .
2.
, File: :Find
.
3.
( Unix), File:: Find .
4. ,
(, Unix, NFS Windows), File: . F i n d , .
, , ,
.
. :
, . :
use File: :Find;
use File: :Basename;
# ,
#
% derivations = (".dvi" => ".tex",
".aux" => ". tex",
".toe" => ",tex",
".o" => ",c",
, :
File: : F i n d File: :Basename.
. -
; , ,
LaTeX happy.tex, happy.dvi,

File::Find

49

happy-0 , , happy.c
. ,
,
. ,
. - , .
, ,
($<), getpwuidQ. g e t p w u i d ( ) ( );
([7]) , . (,
$), .
, , & f i n d ( ) , :
$homedir=(getpwuid($<))[7];

cridir($homedir) or
die " $homedir:$!\n";
$|=1; 8 STDOUT
print "";
find(\&wanted, "."); , &wanted
#
&wanted().
core-,
, emacs. ,
, (, ).
, , , .

. &BaseFileExists(),
,
.
,
:
sub wanted {
# ,
# , -
print "." if (-d $_);
#
return unless (-f $_);

50

2.

# core-, %
$_ eq "core" && ($core{$File: : Find: : name} = (stat(_))[7])
&& return;
# ,
# emacs
(/"#.*$/ || /-$/) &&
($emacs{$File: :Find: :name}=(stat(_))[7]) &&
return;
tex-
(/\.dvi$/ || /\.aux$/ | /\.toc$/) &&
&BaseFileExists($File: :Find: :name) &&
($tex{$File: :Find: :name} = (stat(_))[7]) &&
return;
# .
/\.$/ &&
&BaseFileExists($File: : Find: :name) &&
($doto{$File::Find::name} = (stat(_))[7]) &&
return;
, ,
(,
happy. , happy.c):
sub BaseFileExists {
my($name, $path, Ssuffix) =
&File: :Basename: :fileparse($_[0], '\. , *' );
,
return 0 unless (defined $derivations{$suffix});
# ,
return 1 if (defined
$baseseen{$path.$name.$derivations{$suffix}});
( )
#
return 1 if (-s $name. $derivations{$suffix} &&
++$baseseen { Spat h.$name.$deri vat ions {$suf fix}});
print ".\n";
:
1. & F i l e : :Basename; : f i l e p a r s e ( )
, ( resume.dvi
/home/cindy/docs/, .dvi).

File::Find

51

2. , ,
. , 0 (. . ).
3. , , (base file)
, , . ( , TeX/LaTeX),
. , . .
.
4. ( ,
), ,
. , 1 (. . ).
, :
foreach my $path (keys %core){
print " core-, ".&BytesToMeg($core{$path}).
"MB ".SFile: :Basename: :dirname($path). ".\n";
if (keys %emacs){
print " , , ,
emacs:\n";
foreach my $path (keys %emacs){
Stempsize += $emacs{$path};
$path =" s/"$horoedir/~/;
# ,
ft
print "Spath ($emacs{$path} )\";
}
print "\ ",&BytesToMeg($tempsize). "MB . \";
$tempsize=0;
if (keys %tex){
print " , , ,
1_/:\";
foreach my $path (keys %tex){
Stempsize += $tex{$path};
Spath =" s/~$homedir/~/;
tt ,
#
print "$path ($tex{$path} )\";
>
print "\ ".&BytesToMeg($tempsize). "MB . \n";
$tempsize=0;
if (keys %doto){

52

2.
print " , , ,
:\";
foreach my Spath (keys %doto){
Stempsize += $doto{$path};
Spath =" s/"$homedir/"/;
n ,

print "$path ($doto{$path} )\";
}
print "\ ".&BytesToMeg($tempsize)."MB .\n";
$tempsize=0;

}
sub BytesToMegf # .
return sprintf("%.2f",($_[0]/1024000));
>
, ,
. . :

.
,
,
Perl.
, .
,
( %tex) .

, - (

).

. u n l i n k ( ) rmpath
File: :Path.

, .


Perl-, , , , .
,
, . .
, .
, : . , , -

53

,
. Windows 2000 Unix. NT4 , MacOS S.O.L. (Simply or Sore Out of Luck - ).1
, ,
, ,
, , core-. .
.
Unix
Perl. ,
,
. , Unix ( /etc/fstab
/etc/vfstab) , ( quotaon).
/etc/vfstab Solaris:
device
device
mount FS
fsck mount
#to mount
to fsck
point type pass at boot
/dev/dsk/cOtOdOs? /dev/dsk/cOdOtOdOs7 /home ufs 2
yes

mount
options
rq

rq . .
, ,
quota:
$ quota -v sabrams
, :
Disk quotas for sabrams (uid 670):
Filesystem usage quota
limit timeleft files quota limit timeleft
/home/users 228731 250000 253000
0
0
0

. -
sabrams
, /home/users. - . - ,
1

, MacOS . - . . .

54

2.
, . - , . . , .
,
, d i s k quota exceeded.
edquota,
,
EDITOR . , . ,
/exprt/server2, . .
:
fs /exprt/serverl
fs /exprt/server2
hard = 0)
fs /exprt/server3
fs /exprt/server4

blocks (soft = 0, hard = 0) inodes (soft = 0, hard = 0)


blocks (soft = 250000, hard = 253000) inodes (soft = 0,
blocks (soft = 0, hard = 0) inodes (soft = 0, hard = 0)
blocks (soft = 0, hard = 0) inodes (soft = 0, hard = 0)

edquota , , . Unix -
. Unix
, . ,
Perl, (There's More Than One Way To Do It, TMTOWTDI, -, tim-toady),
Perl.
edquota
. : edquota
,
, . , , . , , . , edquota, - ,

. ( EDITOR) .

55

edquota Perl?
.
: -, , EDITOR edquota. , edquota , . (. 2.1).
, .
, edquota, , . edquota :
ui(l), EDITOR
. EDITOR , , edquota. , Perl. , :

AppleEvents ( MacOS)

(mutex)
( NT/2000)

. , , .
, :
(- ?)

(
?)

( 10- 20 ?)

( , ?)
, ,
.
, .
( ),

2.

56

Unix.1 , , edquota, .

.,?"

,""

'""'',}__

1 '=^1
: autoedquota

autoedquota

edquota

EDITOR.

!
edquota

; EDITOR - autoedquota

/
j ^J7
autoeciqijota
v

=
== NW"x^^^
^^^^
edquota ^ i

/
^J^J2
autoedquota

edquota


.

Amp/file

i
^^

yk
44
autoedquota
edquota
* I [\ autoedquota

autoedquota

Amp/file
U^

autoedquota

edquolaVN.
+

|
filesystem quota

rr

=^2
autoedquota

edquota


.

W
/Imp/file
J

. 2.1.
1

, edquota,
Perl-.

57

. ,
, - , .

(, ), , edquota, ( ). , ,
. , :
$edquota = "/usr/etc/edquota";
it edquota
$autoedq = "/usr/adm/autoedquota"; tt
?
# -
if ($ARGV > 0) {
SParseArgs;
&CallEdquota;
}
ft ,
ft
else {
&EdQuota();
}
,
edquota :
sub ParseArgs{
use Getopt: :Std; tt
ft $opt_u
# , $opt_f - ,
ft $opt_s - $opt_h
getopt("u:f :s:h: "); ft ,
ft
die ": $0 -u uid -f <fsystem> -s <softq> -h <hardq>\n"
if (!$opt_u || !$opt_f || !$opt_s || !$opt_h);
sub CallEdquotai
$ENV{ "EDITOR"} = Sautoedq; ft
ft EDITOR
ft
open(EPROCESS, "|$edquota $opt_u") or
die " edquota :$!\n";

58

2.

print EPROCESS "$opt_f |$opt_s|$opt_h\n";
close(EPROCESS);
}

:
sub EdQuota {
$tfile = $ARGV[0]; # edquota
open(TEMPFILE, $tfile) or
die " $tfile:$!\n";
# -,
10:: File > new_tmpfile()
open(NEWTEMP, ">$tfile.$$") or
die " - $tfile.$$:$!\n"
ft \
chomp($change = <STDIN>);
my($fs,$soft,$hard) = split(/\|/,$change); ft
ft .
ft ,
ft , .
ft (, ) .
while (<TEMPFILE>){
if (/"fs $fs\s+/){
s/(soft\s*=\s*)\d+(, hard\s*=\s*)\d+/$1$soft$2$hard/;
}
print NEWTEMP;
>

close(TEMPFILE);
close(NEWTEMP);
ft ,
ft edquota
rename("$tfile.$$",$tfile)
or die " $tfile.$$ $tfile:$!\n";
- ,
. -
, . > ,
,
, . , , .

59

Quota
- (, ,
)
, , , , Perl. , Perl Perl,
Quota Perl .
(Tom Zoerner)
Perl , Unix. , .
, ,
:
use Getopt::Std;
use Quota:;
getopt("u:f:s:h:");
die "USAGE: $0 -u uid -f <filesystem> -s <softquota> -h <tiard quota>\n"
if (!$opt_u | !$opt_f || !$opt_s || !$opt_h);
$dev = Quota::getcarg($opt_f) or die "
$opt_f:$!\n";
(Scurblock, Ssoft,Shard,Sbtimeout,Scurinode,Sisoft,$ihard,$itimeout)=
Quota::query($dev,$uid) or die "
$uid:$!\n";
Quota::setqlim($dev,$opt_u,$opt_s,$opt_h,Sisoft,Sihard,1) or
die " :$!\";
: -,
Quota: : g e t c a r g ( ) , .
Quota : : q u e ry (), .
, , (, ). , .
, Perl.
, Perl TMTOWTDI ,
.

60

2.



, , , . ,
.
MacOS - ,
. MacOS PBHGetVInf Macintosh Toolbox
,
MacPerl, .
Finder . , - MacOS
.
pa (Chris Nandor) http://pudge.net CPAN.
, :
1. -. - CPAN. pm, (Andreas J. Kb'nig),
, 1. MacOS,
. , README.
2. Mac: :AppleEvents: :Simple, installme.
3. Mac::Glue. installme !
Mac: : G l u e . gluedialect
gluescriptadds scripts , .
4. Finder. System Folder
Finder gluemac,
(, , ).
'
:
use Mac::Glue qw(:all);
$fobj = new Mac::Glue 'Finder';
Svolumename = "Macintosh HD"; #

_. -

61

Stotal = $fobj->get($fobj->prop('capacity',
disk => Svolumename),
as => 'doub');
$free = $fobj->get($fobj->prop('free_space',
disk => $volumename),
as => 'doub');
print " $free $total\n";
. Win32,
Win32: : AdminMisc, (Dave Roth):
use Win32::AdminMisc;
(Stotal,$f) = Win32::AdminMisc::GetDriveSpace("c:\\");
print " $free $total\n";
, , Unix. Unix, Filesys: :DiskSpace (Fabien Tassin), Filesys: :Df (Ian Guthrie) Filesys: :DiskFree (Alan R. Barclay).
statvf s(), Unix- df
. - , . Filesys: : D f , ( ,
1) . :
use Filesys::Df;
Sfobj = df("/");
print $fobj->{su_bavail}*1024." ".
$fobj->{su_blocks}*1024." \";
( : *1024), Filesys: : Df , 1024 . d f ( )
, , .
. su_bavail s u _ b l o c k s -
. Unix df , 10% , .
-

62

2.
user_blocks user_bavail.
, , .

.

-
CPAN

File:: Find ( Perl)


File:: Spec ( Perl)
Cwd ( Perl)
W i n 3 2 : : F i l e : : Get Attributes ( ActiveState Perl)
W i n 3 2 : : FileSecurity ( ActiveState Perl)
File:: Basename ( Perl)
Getopt:: Std ( Perl)
Quota
- ()
Mac::AppleEvents::Simple
Mac::Glue

TOMZO
CNANDOR
CNANDOR
CNANDOR

1.2.3
0.40
0.81
0.58


perlport - Perl- . (Chris Nandor) (Gurasamy Sarathy) Perl Conference 2.0;
http:/l
pudge.net/macperl/tpc/98.


Unix

Windows NT/2000


.
, :
a) .
b) .
, , ) - .
1, ,
,
.
? ,
, , : .
, .
. ,
, - . , :
. . . .
.
?
, ? -

64

3.
, . ,
, ,
. .
, , . Unix, Windows NT/2000. MacOS , MacOS . ,
.

Unix

J^ , . , ,
, , , .
.
,
.
,
(
). , . , .
Unix
, . , Unix. , Unix, SunOS, Digital Unix Linux.
/etc/passwd, '
ASCII-, "
.
, '
. , '
.
/etc/passwd:
dnb:fMP.olmno4jGA6:6700:520:David N. Blank-Edelman:/home/dnb:/bin/zsh

66

3.
, 2397,
danielr drinehart, drinehart. - . , .
, ; , .
, . :
Spasswd = "/etc/passwd";
open(PW,$passwd) or die " $passwd:$!\n";
while (<PW>){
@fields = split(/:/);
$highestuid = ($highestuid < $fields[2]) ? $fields[2] : Shlghestuid;
}
close(PW);
print " : " . ++$highestuid . "\n";
,
(. 3.1).
3.1. ,

/

getpwnam($name) , ;
getpwuid($uid) , ;

$>
Perl

$<
Perl
(GID)

. Unix
,
. ,

1

^ Unix

67

(primary group). GID


.
, /etc/group. ,
.
, ( , ). 8. /etc/'group:
bin::2:root,bin,daemon
sys::3:root,bin,sys,adm
, - ( ),
- - .
, ( ,
) . ,
(,
. .), ( , . .) ( .).
Perl
passwd .
. , (. 3.2).
3.2. ,

/

getgrent()

;
: $name, Spasswd, $gid, $members
getgrnam($name) ;
,
getgrent()
9etgrgid($gid) ;
, g e t g r e n t ( )
$)

$(

68

3.

, Unix.
, , , . , ,
mguerre,
. ,
(, ), Unix.
(*). ,
.
- .
10 .
GCOS
GCOS1 ( ). (
. ), / .
, ( ),
.
.
Unix- /etc/passwd,
, ,
. ,
finger-
- .
(, '
, '
), .
: 6
, "
GCOS 6
( , '
). ^

, #
.
'
http://www.jargon.org.

^ Unix

69


.
, .
, .
, . ,
,
. , , , , . , (
-
) , ,
.
Perl, ,
:
use User::pwent;
use File::stat;
# : ,
#
while($pwent = getpwent()){
fl , ,
#
$dirinfo = stat($pwent->dir."/.");
unless (defined $dirinfo){
warn " ".$pwent->dir.": $!\n";
next;
}
warn ".$pwent->name."
uid (". $dirinfo->uid." ".$pwent>uid.")!\n"
if ($dirinfo->uid != $pwentuid);
,
# -" (. . 01000),
# chmod
warn $pwent->name. '"s homedir is world-writable! \n"
if ($dirinfo->mode & 022 and (!$stat->mode & 01000));

}
endpwentO;
, (Tom Christiansen): User: :pwent File: :stat.
getpwent() stat(), , . User: : pwent

70

3.
File: : stat,
. ,
, .
:
$gid = ( s t a t ( " f i l e n a m e " ) ) [ 5 ] ;
:

use F i l e : : s t a t ;
$stat = stat("filename");
$gid = $stat->gid;

:
use F i l e : : s t a t ;
$gid = stat("filename")->gid;


- , .
(sh, csh, tcsh, ksh, zsh),
.
, ( ) Perl. ,
(zsh) Perl,
. ,
Perl shell (http://www.focusresearch.com/gregor/psh/), Perl Emacs, (http://
john-edwin-tobey.org/perlmacs/).
, . , , ,
.
,
, ,
, . - , .
.
/etc/shells, , '
FTP. FTP- '
, '
, /etc/passwd ( ), '

1/| Unix

71

/etc/'shells. Perl,
:
use User::pwent;
$shells = "/etc/shells";
open (SHELLS,$shells) or die " $shells:$!\n";
while(<SHELLS>){
chomp;
$okshell{$_}++;
}
close(SHELLS);
while($pwent = getpwent()){
warn $pwent->name." has a b.ad shell (".$pwent->shell. ")!\n"
unless (exists $okshell{$pwent->shell});

endpwentO;
BSD 4.4
BSD (Berkeley Software Distribution) 4.3 4.4
: , .
BSD 4.4 GID GCOS . class.
(, , ). , change
expire,
.
Unix.
, , Perl , getpwent(). ,
getpwent(), s p l i t ( ) .
BSD 4.4
BSD - , . BSD DB -
DBM (Database Management). .

72

3.
pwd_mkdb
, , /etc /master.passwd.
- ,
. .
Perl DB- ( 9 ),
, . : ,
,
. , chpasswd, .1 , EDITOR, 2
, chpasswd.


,
GCOS, . . . , , -
. , ,
, , .
(, ), .
,
. .
.
- , .
, . . , .
: , .
, '
, , BSD *.
pwd_mkdb , ( BSD), .

Windows NT/2000

73

, ( ), ,
.
, , , .
. ,
BSD-, .
Perl-, g e t p w e n t ( ) ,
. , , ,
, Perl . ,
, , Perl
( ),
. .
,
. Perl . (Eric Estabrooks) Passwd: :Solaris,
Solaris.
, ,
(
getpwent()), shadow
.

Windows NT/2000
, ,
Unix-, , NT/2000.
, .

0

Windows NT/2000
NT/2000 SAM (Security Accounts Manager,
). SAM - NT/2000, %SYSTEMROOT%/system32/config. ,
, , , -

74

3.
Perl . ,
NT/2000 ,
(pack() unpack()) SAM,
.
, Perl.
- ,
.
NT/2000 net, , , net , ,
.
, , net :
C:\>net users
User accounts for \\HOTDIGGITYDOG
Administrator
Guest
The command completed successfully.
,
Perl. net ,
, .
- Win32: : NetAdmin ( ActiveState Perl) ,
W i n 3 2 : : Net Admin. !
W i n 3 2 : : AdminMisc (David Roth,
http://www.roth.net) Win32: :UserAdmin (
(Ashley Meggitt) (Timothy Ritchey)
Windows NT User Administration (Windows NT: ), ftp://ftp.oreilly.com/pubi
examples/'windows /winuser/).
'
W i n 3 2 : : A d m i n M i s c , "
, , '
.
, '
Win32 Perl Programming: The Standard E#'
tensions ( Perl Win32: #
) (Macmillan Technical Publishing).
, Perl '
Win32.

Windows NT/2000

75

, , .
/etc/passwd Unix:
use Win32: :AdminMisc;
#
Win32: :AdminMisc: :GetUsers( " , " ,\@users) or
die " : $!\";

foreach $user (@users){
Win32: :AdminMisc: :UserGetMiscAttributes( ' ' , $user,\%attribs)
or warn " : $!\";
print join(" :", Suser,
$attribs{USER_USER_ID},
$attribs{USER_PRIMARY_GROUP_ID},
$attribs<USER_COMMENT},
$attribs{USER_FULL_NAME},
$attribs{USER_HOME_DIR_DRIVE}."\\".
$attribs{USER_HOME_DIR},

, Win32 : : OLE (ADSI, Active Directory Service


Interfaces). Windows 2000 Windows NT 4.0. 6 .
Perl
NT/2000 ,
Unix Windows NT/2000.
NT/2000
NT/2000
. Unix,
,
Windows NT/2000
. (
NT/2000 RID, Relative ID) ,
-
(SID, Security ID),
(UID). , RID 500, SID, :

76

3.
S-1-5-21-2046255566-1111630368-2110791508-500
RID - ,
UserGetMiscAttributes() .
RID :
use Win32::AdminMisc;
Win32: -.AdminMisc: :UserGetMiscAttributes('' ,$user,\%attribs);
print $attribs{USER_USER_ID},"\n";
( )
, .
,
(SID) .
.
NT , .
,
, SID, , .
,
. , .

. Unix : , . NT, , , . ,
, Unix. Perl :

, :
- chown Microsoft NT Resource ( , ),
Cygwin http://www.cygnus.com ().
- setowner, NTSEC, Pedestal Software http://www.pedestalsoftware.com.
, . .
.

W i n 3 2 : : rms, (David Roth), http://www.roth.net/perl/perms.


, , :

Windows NT/2000

77

use Win32::Perms;
$acl = new Win32::Perms();
$acl->Owner($NewAccountName);
$result = $acl->SetRecurse($dir);
$acl->Close();
NT/2000
, , NT/2000 Unix, . , . ,
/ .
- ,
Unix-NT/2000.
, - , .
, , Perl, -
,
.
( .),
.
NT
- , NIS.
, , ,
, .
NT/2000
Perl, , , .
Windows NT 4.0. Windows 2000 ,
Windows 2000 Windows 2000,
.
NT
: SAM SAM .
, , ,
.

78

3.
NT : . ,
. ,
, . ,
,
, ,
Unix. , , .
, , , . :

.
, .

, ,
-
,
.
, . ,
, , .

(
).

. :
.
, /'
.
, . , >'
NT ,
- , .
Omphalos'
kepsis, '
Global-Omph People. '
, . '
, , , '
.
.
v4eTHbie

Windows NT/2000

79

(
). (, Perl),
, :
1. Local-Authorized
Omphies.
2. .
3. Global-Omph People .
4. (
) Log on Locally ( )
Local-Authorized Omphies.
5. Log on Locally
.
. Global-Omph People , - .
/ ,
.1
, Perl. . ,
Win32: :NetAdmin :
GroupCreateO
GroupOeleteO
GroupGetAttributesO
GroupSetAttributesO
GroupAddUsersO
GroupDeleteUsersO
GroupIsMemberQ
GroupGetMembersO

LocalGroupCreateO
LocalGroupDeleteO
LocalGroupGetAttributesO
LocalGroupSetAttributesO
LocalGroupAddUsersO
LocalGroupDeleteUsersO
LocalGroupIsMember()
LocalGroupGetMembers()

, Unix, , , , NIS /etc/passwd NIS.


netgroup.

80

3.

Windows 2000
,
NT, Windows 2000,
,
:
1. Windows 2000 (Active Directory,
6) . ,
, SAM.
2. .
3. , (scope) . Windows 2000
. ,
, .
, .
, .
Perl

. - , NT4 SAM ,
. ,
Windows 2000.
(Active Directory Service Interfaces, ADSI), 6.
, , . , , , - , . .
.
:
,
,
.

Windows NT/2000

81

NT/2000
Unix
NT/2000, , -
. Unix , , , . NT/2000
. ( )
,
. ,
Change the System Time ( ),
.
,
, User Rights Policy (
) NT 4.0 User Manager (
) User Manager for Domains ( ).
, , .

, . (. 3.1) .
,
, . ,
, Perl.
- ntrights.exe Microsoft NT Resource Kit. , .
User Rights Policy
Computer: OMPHALOSKEPSIS
Right: ' 4ct as oaft o( the ooeiatina system
Giant To:

F Show Advanced Us Bights


.1. User Rights Policy NT 4.0

82

3.
ntrights.exe ; Perl, (. .,
system( )). ntrights.exe. :
C:\>ntrights.exe +r <right > +u <user or group > [-m \\machinename]
( machinename, ). ,
:
C:\xitrights.exe - <right > +u <user or group > [-m \\machinename]
Unix + - (
chmod), -, . (, SetSystemtimePrivilege )
Microsoft NT Resource Kit no ntrights
, Perl,
W i n 3 2 : :(_anman, (Jens Helberg),
ftp://ftp.roth.net/pub/ntperl/Others/
Lanman/, http://jenda.krynicky.cz. , .
, , .
:
use Win32: : Lanman;

(SID) ,
. SID
Guest:
unless( Win32: : Lanman: :LsaLookupNames($server, [ 'Guest'],\@info){
die " SID:
".Win32: :Lanman: :GetLastError(). "\n";
@inf , (
- Guest). : domain, domainsid, relativeid, sid use. sid.
:
unless (Win32: : Lanman: : LsaEnumerateAccountRights($server,
${$info[0]}{sid}, \@rights)){
die " :
".Win32: : Lanman: :GetLastError(). "\n";

> Windows NT/2000

83

Microsoft Windows NT/ Windows 2000 Resource Kits


NT 4.0 Server / Workstation
Resource Kit - , , NT, . Microsoft Press ,
NT/2000.
, -,
. -
NT/2000. ,
NT/2000 Server, , - NT Workstation/Windows 2000 Professional. , , NT/2000 Server.
NT/2000, ,
. ,
, , ,
,
. .
(as is), , .
, - Microsoft .
,
, , . , , -
Microsoft.
@rights ,
Guest.
, API- ( Application Program Interface,
)
, . , , - SDK (Software Developement Kit, ), http://msdn.microsoft.com. ,

84

3.
SDK Perl.
, MSDN (Microsoft's Developer Network)
LsaEnumerateAccountRights, .
.
, Guest
() , :
use Win32::Lanman;
unless (Win32::Lanman::LsaLookupNames($server, ['Guest'],
\@info)) {
die " SID: ".Win32::lanman::GetlastError()."\n";

unless (Win32: :l_anman: :LsaAddAccountRights($server,


${$info[0]}{sid}, [&SE_SHUTDOWN_NAME])) {
die " : ".Win32::lanman::GetlastError()."\n"
}
SE_SHUTDOWN_NAME SDK
&SE_SHUTDOWN_NAME ( Win32:: Lanman), SDK.
W i n 3 2 : : L a n m a n : : LsaRemoveAccountRights() - . , ,
.
, ,
Win32::Lanman , , . , . W i n 3 2 : : L a n m a n : :LsaEnumerateAccountsWithUserRight(), (SID),
. .


, ,
.
Perl, ,
,
. , NT, Unix.

85

:
, , ( Microsoft -) .
(. 3.2).

. 3.2.

. .
,

. .
.
.
, .
,
- . , , .
, ( ,
) . -

86

3.
- ,
.
,
:
sub Collectlnformation{
it .
#
it
my fields = qwjlogin fullname id type password};
my %record;
foreach my $field (@fields){
print "Please enter $field: ";
chomp($record{$field} = <STDIN>);

$record{status}="to_be_created";
return \%record;

}
, . , .


.
, .
.
. - .
,
, .

- . /etc/ passwd SAM , .
, ,
: ,
, , . ,
. , LDAP .

/16



: .

. , . - , , , , , . ,
.
, . , ,
. , .

. , ,
. , ,
, .
,
.
,
. , . .
,
.
, , , . , .
?
, , .
,
, . , ,

87

88

3.

.
:

, .

, , ,
. ,
LDAP (Lightweight Directory Access
Protocol) .

(.. ).

,
.

,
.


. : , ,
, .
, , - , ( , Postgres
MySQL). 7
SQL,
Perl.
, . 1
. Windows Access ( database.mdb).
. , XML.
XML, ,

XML.
XML? XML , '

:

89

XML - , ,
Perl-,
.

XML .
, , /etc/
passwd, ,
. XML ,
.

, XML
. ,
, , . .

(DTD). , , , ,
.
- X M L : :Checker, libxml-enno (Enno Derksen). , , -
, .

XML
. , ,
.
XML- , , /.
, TMTOWTDI -
. XML, ,
, ,
. , ,
, ,
, XML Perl.
XML- Perl
, NT/2000. ,
,
C o l l e c t l n f o r m a t i o n O , .
, . ,
XML.
XML-
p r i n t , . X M L : :Generator
(Benjamin Holzman) X M L : : W r i t e r (David

90

3.
Megginson) . , / , (<, >, & . .). ,
XML XML: -.Writer:
sub AppendAccountXML {

my $filename = shift;
tt
Srecord = shift;
# XML;'.Writer 10; '.File
ft
use 10;;File;
#
$fh = new 10: ;File("$filename") or
die "Unable to append to file;$!\n";
# XML: .'Writer
# $fh
use XML;;Writer;
my $w = new XML;;Writer(OUTPUT => $fh);
(t <account>
$w->startTag("account");
/
<account>
foreach my $field (keys %{$record}){
print $fh "\n\t";
$w->startTag($field);
$w->characters($$record{$field});
$w->endTag;
}
print $fh "\n";
tt <account>
$w->endTag;
$w->end;
$fh->close();

>
, !"
:
&AppendAccountXML($addqueue,SCollectInformation);

91

:1
<account>
<login>bobf</login>
<fullname>Bob Fate</fullname>
<id>24-9057</id>
<type>staff</type>
<password>password</password>
<status>to_be_created</status>
</account>
, . ,
, . , , .
AppendAccountXMLO , .
XML: :Writer AppendAccountXMLO
:
, , ,
startTagO, charactersO endTagO.
, c h a r a c t e r s ( )
- , (>).
, . X M L : :Writer endTag(), , . ,
,
,
.
XML XML::Parser
XML Perl,
,
. ,
: XML
XML (. ., <?xml v e r sion="1. 0"?>). , ,
X M L : : W r i t e r xmlDecl , .

92

3.
,
.
XML.
, XML-
.1 X M L : : P a r s e r , (Larry
Wall) ( (Clark Cooper)).
XML: : Parser - , . , .
, ,
(, ,
3V4,
. .). , , (events),
, , - (event handlers). - , . (callback routines), . .
, , . X M L : : P a r s e r , - ,
, . - : .2
,
XML: : Parse . ,
(style) . XML: : Parser
,
. ,
( ).
,
, , ^
, ,
. -,
,
. , ,
(Eric Prud'hommeaux) http://www.w3.org/1999/02/26-modules/W3C-SAX'
XmlParser-*
, XML: :Node 1
'
, .

93

, - -. , ,
Handlers (, Handlers => {Start =>
\ & s t a r t _ h a n d l e r } ) .
stream, . , . stream,
, : StartTag, EndTag Text. , Text, . Text X M L : :Parser $_. , .
:
use XML::Parser;
use Data::Dumper; #
(f XML
$ = new XML::Parser(ErrorContext =>
Style
=>
Pkg
=>

,
3,
'Stream',
'Account::Parse');

. , E r r o r C o n t e x t , . . , Pkg, , .
, , &Account::Parse: :StartTag(), &Account:-.Parse: :EndTag0
. ., &StartTag(), &EndTag() . .
, ,
StartTag(). Pkg,
package
Account;:Parse;.
, . :
package Account::Parse;
sub StartTag {
undef %record if ($_["!] eq "account");

94

3.
&StartTag() ,
. :
.
,
StartTagO, (, <account>). . ,
:
sub Text {
my $ce = $_[0]->current_element();
$record{$ce}=$_ unless ($ce eq "account");
}
&Text() %record.
, :
,

. , , current_element().
X M L : : Parse : : Expat ,
. ,
account, , <account>, :
sub EndTag {
print Data::Dumper->Dump([\%record], ["account"])
if ($_[1] eq "account");
-
,
}
, &EndTag (), &Sta rtTag ()
, ,
. , .
:
Saccount = {

>;
Saccount = {

'login' => 'bobf,


'type' => 'staff,
'password' => 'password',
'fullname' => 'Bob Fate',
'id' => '24-9057'
'login' => 'wendyf,
'type' => 'faculty',
'password' => 'password',

95

'fullname' => 'Wendy Fate',


'id' => '50-9057'
,
, , , ateAccount(\%record), Data: : Dumper.
, XML: : Parser, , :
#
# XML-
open(FILE, Saddqueue) or die "Unable to open $addqueue:$!\n";
tt
read(FILE, Squeuecontents, -s FILE);
$p->parse( "<queue>" . Squeuecontents. "</queue>" ) ;
, , ,
.
Squeuecontents. , , parse ( ).
XML ,
?
, . - .
<account>
.
XML- (root element). ; . XML , , . XML- ,
, (well-formed).
XML .
, , ,
<account>. ,
</account> .
, , , .
(<queue>)
, (</queue>)?
( ), , ,
.

96

3. ^
^
( )
seek(), (
seek()) ,
. , . .
(, ?) . ,
, ,
, XML . , , , % .
, , , , . , .
XML XML'.Simple

, XML- X M L : : Parse .
TMTOWTDI, , . ,
X M L : '.Parser, XML- / , XML::DOM (Enno Derksen), XML::Grove, ToOb]ects
( libxml-perl) (Ken MacLeod), X M L : : DT Xoce Xoa (Jose Joao Dias de Almeida), X M L ; : Simple (Grant McLean). , , XML::Simple. XML,
.
XML::Simple . ( ):
use XML::Simple;
use Data::Dumper; ft
#
Squeuefile = "addqueue.xml";
open(FILE,Squeuefile) or die "Unable to open $queuefile:$!\n";
read(FILE, Squeuecontents, -s FILE);
Squeue = XMLin("<queue>".$queuecontents."</queue>");
Squeue :
print Data::Dumper->Dump([$queue],["queue"]);

97

, , , <id>.
, (. 3.3).
Squeue = {
'account' => {
24-9057' => {
1
login' => 'bobf',
'type1 => ' staff ,
'password' => 'password1,
'fullname' => 'Bob Fate',
1
status' =>'to_be_created'

50-9057' => {
'login' => 'wendyf,
'type' => 'faculty1,
'password' => 'password',
'fullname1 => 'Wendy Fate'
'status' =>'to_be_created'

}
}

.. , ()

, X M L : : Simple
,
. :
Squeue = XMLin("<queue>".$queuecontents."</queue>",keyattr=>[]);
, .
(. 3.4).
. :
Squeue = XMLin("<queue>".$queuecontents."</queue>",keyattr => ["login"]);
( ,
),
. 3.5 - , .
? , :
, Slogin = "bobf";
delete $queue->{account}{Slogin};
,
(, ),
:

3.

98

, $login="wendyf"; $field="status";
$queue->{ account} {$loginH$field}="created";
$queue =

account' =>
'login' => ' b o b f ' ,
'type' => ' s t a f f ,
'password 1 => 'password',
'status' => 'to_be_created'
'fullname' => 'Bob F a t e ' ,
'id' => '24-9057'
'login' => ' w e n d y f ' ,
1
type' => ' f a c u l t y ' ,
'password' => 'password',
' s t a t u s ' => 'to_be_created'
'fullname' => 'Wendy Fate 1 ,
' i d ' => '50-9057'

Puc. 3.4. , XMLinf) keyattr


$queue =

account' => {
'bobf =>
'type' => ' s t a f f ,
'password' => 'password',
'fullname' => 'Bob F a t e ' ,
' s t a t u s ' => 'to_be_created'
' i d 1 => ' 2 4 - 9 0 5 7 '
'wendyf' =>

{
'type' => ' f a c u l t y ' ,
'password' => 'password 1 ,
'fullname' => 'Wendy Fate',
' s t a t u s ' => 'to_be_created'
id1 => ' 5 0 - 9 0 5 7 '

Puc. 3.5. , keyattr


XML- XML::Simple

XML-, . "
XML: :Simple *
XML-:

99

# rootname ,
tt XMLdecl, XML
print XMLout($queue, rootname =>"queue");
( ):
<queue>
occount name="bobf" type="staff"
password="password" status="to_be_created"
fullname="Bob Fate" id="24-9057" />
Occount name="wendyf" type="faculty"
password="password" status="to_be_created"
fullname="Wendy Fate" id="50-9057" />
</queue>
XML-,
.
<account> </ account>, a
. X M L : '.Simple ,
, .
( ): XML-,
XML.
XML- (
, ),
(. 3.6).
$queue = {

'account 1 => {
1

login 1 => [ 'bobf ' ] ,


'type' => [ ' s t a f f ' ] ,
'password 1 => [ ' p a s s w o r d ' ] ,
'status' => [ ' to_be_created' ] ,
'fullname' => ['Bob F a t e 1 ] ,
' i d ' => [ ' 2 4 - 9 0 5 7 4
' l o g i n 1 => [ ' w e n d y f ' ] ,
' type ' => [ ' faculty ' ] ,
'password 1 => ['password'],
1
status ' => [ ' to_be_created ' ] ,
'fullname 1 => ['Wendy F a t e 1 ] ,
id' => [ ' 5 0 - 9 0 5 7 ' ]

.6. ,
XML-

3.
, */ . :
1. *. .

2 * , * X M L : : Simple . (. 3.6), () :
$queue = XMLin("<quif |queuecontents."</queue>",
1Eg-ray=>1, keyattr => [""]);
, , , .
3 , .
( ,
,
, XMlSuple, .
3 ,
*, (. 3.5),
% (. 3.6).
1:
sub TransformForWritel
my Squeueref = shift
my $toplevel = scalg% %$queueref;
foreaclH my Suser (ki{$queueref->{$toplevel}}){
my %innerhash =
map {$_,[$queu#--'{$toplevelH$user}{$J] }
keys %{$fef->($toplevel}{$user}};
$innerhash{'loginF[$user];
push @outputarray;*iinerhash;
>
SoutpJtref = { $topd => \@outputarray};
return Soutputref;

>
T r a n s f o r m F o r W r i t e ( ) .
! (. 3.5, . 3.6), ^
- : ,
account. ,
, ,
ueref:
my Stoplevel = scalah %$queueref;

101


:
my %innerhash =
{$_, [$queueref->{$toplevel}{$user}{$J] }
keys %{$queueref->{$toplevel}{$user}};
( ) ,
, (. . login,
type, password status). :
keys %{$queueref->{$toplevel}{$user}};
,
: , :
{$_, [$queueref->{$toplevel}{$user}{$_}] }
, (), :
(login,[bobf], type, [staff], password,[password]...)
-,
. %innerhash,
- (my %innerhash =). ,
l o g i n , :
$innerhash{'login'} = [$user];
, , - , , , . .
:
push @outputarray, \%innerhash;
login ( ). ,
, .
, , , .
. :
Soutputref = { $toplevel => \@outputarray};
return Soutputref;
, & T r a n s f o r m F o r W r i t e ( ) , , :

102

3.
Squeue = XMLin("<queue>".$queuecontents."</queue>",keyattr => ["login"]);
...
print OUTPUTFILE XMLout(TransformForWrite($queue),rootname => "queue");

.
, :
1. , , ,
XML:;Writer XML;:Simple
.
X M L : : Simple, .
X M L : : W r i t e r ( print) , , . .
"<queue>".$queuecontents. "</queue>".
- , XML-.
, XML: '.Simple: XMLoutQ rootname undef, XML- . ,
() , . ,
.
2. ,
.
, (
XML), , . Perl - eval() $@ .1 :
eval {$p->parse("<queue>".$queuecontents,"</queue>")};
if ($@) { - ... };
X M L ; : Checker, . . .
(Daniel Burckhardt) PerlXML, .
Perl $@ , . , , .

103


, , ,
, , , . ,
.
.
,
,
- .
, , , - .

Unix
Unix. , . ,
, , .
? , , , , .
, :
(. . , , ).
(
), .
, . , Digital Unix NIS- .
:


, . ,
Unix (

104

3.
Linux, BSD) ^
: useradd user.
del. BSD adduser rmuser, .
,
.


, ps.
(, ), .

- , .


. , , -
. .

, , . , ,

.
. ,
, , ,
, , . , , .
, , .
, ,
Linux Solaris,
, NIS BSD.
,
Cf gTie (Randy Maas).
, :
#
#

$useraddex
= "/usr/sbin/useradd"; n useradd
Spasswdex
= "/bin/passwd";
passwd
ShomeUnixdirs = "/hone";
ft
#
$skeldir
= "/home/skel";


$defshell
= "/bin/zsh";
#
8
sub CreateUnixAccount{
my ($account,$record) = @_;
, :
- =
ft -d =
-g = ( )
- =
-k = -
-s =
( -G group, group, group
)
my @cmd = (Suseraddex,
"-", $record->{"fullname"},
"-d", "$homeUnixdirs/$account",
"-g", $record->{"type"},
"-n",
"-k", Sskeldir,
"-s", Sdefshell,
Saccount);
print STDERR "Creating account...";
my $result = Oxff & system @>cmd;
0 0 ,
#
if (!$result){
print STDERR "failed.\n";
return "$useraddex failed";
}
else {
print STDERR "succeeded.\n";
}
print STDERR "Changing passwd...";
unless (Sresult = &InitUnixPasswd($account,$record->{"password"})){
print STDERR "succeeded.\n";
return "";
}
else {
print STDERR "failed.\n";
return Sresult;

105

106

3. /
, .
(.profile, .tcshrc, .zshrc, . .) ^.
.
, .
. useradd
(, Solaris)
, pass
wd. ,
,
. ,
, :
if

$userdelex = "/usr/sbin/userdel"; # userdel
sub DeleteUnixAccount{
ray ($account,$record) = @_;
### , :
ft -r =
my @cmd = (Suserdelex, "-r", Saccount);
print STDERR "Deleting account...";
my $result = Oxffff & system @cmd;
0 , 0 - ,
#
if (!$result){
print STDERR "succeeded. \n";
return "";
>
else {
print STDERR "failed. \n";
return "$userdelex failed";

NT, '
InitUnixPasswd( ), '
. ( , S<>'
laris), '
passwd. passed <accountname> "
.
, . passwd
. '
, , 0'
I

107

. :
#
open(PW,"Ipasswd $account");
print PW $oldpasswd,"\n";
print PW $newpasswd,"\n";
, ; -
passwd , ,
Perl. ,
Expect.pm, (Austin Schutz), - (pty), . Expect.pm Tel- Expect
(Don Libes). , . 6 , Net:: Telnet (Jay Rogers).
:
, , ,
. . passwd ,
. passwd :
use Expect;
sub InitUnixPasswd {
my ($account,$passwd) = _;
8
my $pobj = Expect->spawn($passwdex, Saccount);
die "Unable to spawn $passwdex:$'\n" unless (defined $pobj);
8 (. .
8 )
$pobj->log_stdout(0);
#
# , .
$pobj->expect(10,"New password: ");
# Linux , ,

sleep 1;
print Spobj "$passwd\r";
$pobj->expect(10, "Re-enter new password: ");
print Spobj "$passwd\r";
8 ?
Sresult = (defined ($pobj->expect(10,
"successfully changed")) ? "" : "password change
failed");

108

3.
# , 15 ,
$pobj->soft_close();
I
return Sresult;
}

Expect.pm ,
, .

Expect.pm.

Windows NT/2000
Windows NT/2000 , Unix, API
NT. Unix,
, (,
net USERS/ADD), API- ,
. , , W i n 3 2 : : N e t A d m i n , W i n 3 2 : : U s e r A d m i n , W i n 3 2 A P I : : N e t W i n 3 2 : : L a n m a n .
Windows 2000
ADSI 6.
, , . ,
.
Network Management SDK http://msdn.microsoft. com ( , NetUserAdd). NetUserAddO

. , 1,
, , :
typedef struct _USER_INFO_1 {
LPWSTR
usri1_name;
LPWSTR
usri1_password;
DWORD
usri1_password_age;
DWORD
usri1_priv;
LPWSTR
usri1_home_dir;
LPWSTR
usri1_comment;
DWORD
usri1_flags;
LPWSTR usri1_script_path;
}
, 2, ^
:
typedef struct _USER_INFO_2 {

,3

LPWSTR
LPWSTR
DWORD
DWORD
LPWSTR
LPWSTR
DWORD
LPWSTR
DWORD
LPWSTR
LPWSTR
LPWSTR
LPWSTR
DWORD
DWORD
DWORD
DWORD
DWORD
PBYTE
DWORD
DWORD
LPWSTR
DWORD
DWORD

109

usri2_name;
usri2_password;
usri2_password_age;
usri2_priv;
usri2_home_dir;
usri2_comment;
usri2_flags;
usri2_script_path;
usri2_auth_flags;
usri2_full_name;
usri2_usr_comment;
usri2_parms;
usri2_workstations;
usri2_last_logon;
usri2_last_logoff ;
usri2_acct_expires;
usri2_max_storage;
usri2_units_per_week;
usri2_logon_hours;
usri2_bad_pw_count;
usri2_num_logons;
usri2_logon_server;
usri2_country_code;
usri2_code_page;

He ,
,
, .
,
.
Perl? :
1. Perl, ?
2. (. . )
?
Win32API: :Net W i n 3 2 : :UserAdmin . W i n 3 2 : : NetAdmin W i n 3 2 : : Lanman
. W i n 3 2 : :NetAdmin
; , f ull_name
.
W i n 3 2 : : N e t A d m i n , , ,
, , .
W i n 3 2 : :NetAdmin W i n 3 2 : :AdminMisc,
, -

110

3.
^
Win32:: NetAdmin, .
, - . , , , .
Win32: :Lanman.
:

use Win32::Lanman; ft
use Win32:'.Perms; ft
ShomeNTdirs = "\\\\homeserver\\home"; ft
ft
sub CreateNTAccount{
my (Saccount, Srecord) = @>_;
ft
(. ., )
$result = Win32::Lanman::NetUserAdd("",
{'name' => Saccount,
'password' => $record->{password},
'home_dir' => "$homeNTdirs\\$account",
'full_name' => $record->{fullname}});
return Win32::Lanman::GetLastError() unless ($result);
ft (
ft SID )
ft ,

die "SID lookup error: ".Win32::Lanman::GetLastError()."\n"
unless (Win32::Lanman::LsaLookupNames("", [Saccount],
\@info));
Sresult = Win32::Lanman::NetLocalGroupAddMember("",
$record->{type), ${$info[0]}{sid});
return Win32::Lanman::GetLastError() unless (Sresult);
ft
mkdir "$homeNTdirs\\$account",0777 or
return "Unable to make homedir:$!";
ft ACL
$acl = new Win32::Perms("$homeNTdirs\\$account");
$acl->0wner($account);
ft
ft ,
( )


$acl->Allow($account,
FULL,
DIRECTORY | CONTAINER_INHERIT_ACE) ;
$acl->Allow($account,
FULL,
FILE | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE) ;
Sresult = $acl->Set();
$acl->Close();
return($result ? "" : Sresult);
}

:
use Win32: :Lanman;
use File: :Path;

n
8

sub DeleteNTAccount{
my($account, Srecord) = @_;
8 .
8 ,
8 "Local" Win32: :Lanman: :NetUser*
8 (, NetUserGetGroups)
die "SID lookup error: ".Win32: :Lanman: :GetLastError(). "\n"
unless (Win32: :Lanman: :LsaLookupNames("",
[Saccount], \@info));
Win32: :Lanman: :NetUserGetLocalGroups($server, $account, ' ' ,
\@groups);
foreach $group (@groups){
print "Removing user from local group ".
$group->{name}. "...";
print(Win32 : : Lanman : : NetLocalGroupDelMember( "" ,
$group->{name},
${$info[0]}{sid}) ?
"succeeded\n" : "FAILED\n");

8 (. . , )
Sresult = Win32: :Lanman: :NetUserDel("", Saccount);
return Win32: :Lannan: :GetLastError() if (Sresult);
8
Sresult = rmtree("$homeNTdirs\\$account",0, 1);
# rmtree ,
# ,
8
return Sresult;

111

112

3.
%
, File: :Path. - Win32, , , Win32: : FileOp
(Jenda Krynicky), http://jenda.krynicky.cz/. Win32:: FileOp , rmtree(), :
,
,

Sresult = Recycle("$homeNTdirs\\$account");
Delete(), ,
rmtree() (, ) .

, ,
, .
(Account.pm),
, . ,
:
sub InitAccount{
use XML::Writer;
Srecord = { fields => [login,fullname,id,type,password]};
Saddqueue = "addqueue"; ft
Sdelqueue = "delqueue";
Smaindata = "accountdb";

if ($"0 eq "MSWin32"){
require Win32::Lanman;
require Win32::Perms;
require File::Path;

Saccountdir = "\\\\server\\accountsystem\\";
8
Smaillists = "$accountdir\\maillists\\";

ShomeNTdirs = "\\Y\nomeserver\\home";
,
Saccountadd = "CreateNTAccount";
,
Saccountdel = "DeleteNTAccount";

else {
require Expect;
8
$accountdir = "/usr/accountsystem/";
ft
$maillists
= "$accountdir/maillists/";
# useradd
Suseraddex
= "/usr/sbin/useradd";
# userdel
$userdelex
= "/usr/sbin/userdel";
ft passwd
Spasswdex
= "/bin/passwd";
#
$homeUnixdirs = "/home";
ft
$skeldir
= "/home/skel";
ft
$def shell
= "/bin/zsh";
,
Saccountadd = "CreateUnixAccount";
ft ,
Saccountdel = "DeleteUnixAccount";

, :
use Account;
use XML: :Simple;
&InitAccount; ft
&ReadAddGueue; ft
&ProcessAddQueue;
&DisposeAddQueue; ft
ft , ,
ft -
ft $queue
sub ReadAddQueue{
open(AOD, Saccountdir. $addqueue) or
die "Unable to open ".$accountdir.$addqueue. ":$!\n";
read(ADD, Squeuecontents, -s ADD);
close(ADD);
Squeue = XMLin("<queue>".$queuecontents. "</queue>",
keyattr => ["login"]);
ft ,
(. . )
sub ProcessAddQueue{
foreach my $login (keys %{$queue->{account}}){

113

114
_

_^

3. _
-

Sresult = &$accountadd($login,
$queue->{account}->{$login});
if (!$result){
$queue->{account}->{$login}{status} = "created";
}
else {
$queue->{account}->{$login> {status} =
"error:$result";

ff .
ft "created," .
,
ft .
sub DisposeAddQueuel
foreach my $login (keys %{$queue->{account}}){
if ($queue->{account}->{$login}{status} eq "created")!
$queue->{account}->{$login} {login} = $logirv,
$queue->{account}->{$login}{creation_date} = time;
&AppendAccountXML($accountdir.$maindata,
$queue->{account}->{$login});
delete $queue->{account}->{$login};
next;

ft , Squeue, - ,

tt
open(ADD, ">" . Saccountdir. $addqueue) or
die "Unable to open ",$accountdir.$addqueue.":$!\n";
, ,

if (scalar keys %{$queue->{account}}){
print ADD XMLout(&TransformForWrite($queue),
rootname => undef);
}
close(ADD);
, , :
use Account;
use XML: -.Simple;
&InitAccount;

SReadDelQueue; it
&ProcessDelQueue; ft
&DisposeDelQueue; ft


,
# , -
$queue
sub ReadDelQueue{
open(DEL, Saccountdir. $delqueue) or
die "Unable to open ${accountdir}${delqueue} :$!\n";
read(DEL, Squeuecontents, -s DEL);
close(DEL);
$queue = XMLin("<queue>".$queuecontents. "</queue>",
keyattr => ["login"]);
# ,
# (. . )
sub ProcessDelQueue{
foreach my $login (keys %{$queue->{account}}){
$result = &$accountdel($login,
$queue->{account}->{$login} );
if (>$result){
$queue->{account}->{$login} {status} = "deleted";
}
else {
$queue->{account}->{$login}{status} =
"error;$result";


Squeue.
# "deleted," .
tt . , ,
. .
sub DisposeDelQueue{
SReadMainDatabase;
foreach my $login (keys %{$queue->{account}}){
if ($queue->{account}->{$login}{status} eq "deleted")}
unless (exists $maindb->{account}->{$login}){
warn "Could not find Slogin in $maindata\n";
next;
}
$maindb->{account}->{$login}{status} = "deleted";
$maindb->{account}->{$login}{deletion_date> = time;
delete $queue->{account}->{$login};
next;

&WriteMainDatabase;

115

116

3.
ft , Squeue, - ,

open(DEL, ">" . Saccountdir. $delqueue) or
die "Unable to open ",$accountdir.$delqueue. ":$!\n";
if (scalar keys %{$queue->{account}}){
print DEL XMLout(&TransformForWrite($queue),
rootname => undef);
}
close(DEL);
}

.'.

sub ReadMainDatabase{
open(MAIN,$accountdir.$maindata) or
die "Unable to open ".$accountdir.$maindata.":$!\n";
read (MAIN, Sdbcontents, -s MAIN);
close(MAIN);
$maindb = XMLin("<maindb>".$dbcontents."</maindb>",
keyattr => ["login"]);
sub WriteMainDatabase{
# : *
ft
(f ,
open(MAIN, ">".$accountdir.$malndata) or
die "Unable to open ".$accountdir.$maindata.":$!\n";
print MAIN XMLout(&TransformForWrite($maindb),
rootname => undef);
close(MAIN);
. ,
,
. , ?
? , , . ,

. , ( ):
use Account;
use XML: -.Simple;

&InitAccount;
&ReadMainDatabase;
&WriteFiles;

117

sub ReadMainDatabase{
open(MAIN, Saccountdir. $maindata) or
die "Unable to open ",$accountdir.$maindata. ":$!\n";
read (MAIN, Sdbcontents, -s MAIN);
close(MAIN);
Smaindb = XMLin("<maindb>".$dbcontents. "</maindb>",
keyattr => [""]);
# ,
# .
.
sub WriteFiles {
foreach my Saccount (@{$maindb->{account}}){
next if $account->{status} eq "deleted";
push(@{$types{$account->{type}}}, $account-> {login});
foreach $type (keys %types){
open(OUT, ">".$maillists.$type) or
die "Unable to write to
". Saccountdir. $maillists. $type. " : $! \n";
print OUT join("\n",sort @{$types{$type}}). "\n";
close(OUT);

, :
> dir

faculty staff


.
.
, , ( , ):


.
40-50% - .

, , . ,
, .

118

3.
, ' . X M L : :Twig 1.
(Michel Rodriguez)
. . XML-,
.

- . ,
,
. , , ,
. 20-30% , .

. , , . , ,
, ,
.
, ,
.
- .
. , . , , .
(
), , , .
; .
, , '
. ,
, Perl.

.
- lockfile,
procmail, *
http://www.procmail.org. 1
, 6
, lockfile
, , ,
.

119

,
, . , File: : Flock
(David Muir Sharnoff), File: : LockDi Perl Cookbook (Perl: ) (Tom Christiansen) (Nathan Torkington) (O'Reilly) Win95/98
(William Herrera) File: :FlockDir, File: : L o c k
(Kenneth Albanowski), F i l e : : Lockf (Paul
Henson) Lockfile::Simple (Raphael Manfredi).
, , File: : FlockDir
Lockf ile: .'Simple ,
f lock() Perl. , MacOS, . , .
, , (
, ),
, , (,
).
, Perl FAQ, f lock() DB_File Perl.

, ,
.
. , .

CPAN

User:: pwent ( Perl)


F i l e : : stat ( Perl)
Win32: :AdminMisc
www.roth.net)

http://

W i n 3 2 . : Perms ( http://www.roth.net)
Win32:: Lanman ( ftp://ftp.roth.net/pub/
ntperl/'Others /Lanman/)
: : File ( Perl)
GBARR
XML: .-Writer
DMEGG
XML::Parser
COOPERCL

20000117
20000216
1.05
1.20
0.30
2.27

3.

120

Data: : Dumper

XML: : Simple
Expect.pm
File : : Path ( Perl)
Win32: :FileOp


CPAN
GSAR
GRANTM
AUSCHUTZ
JENDA

2.101
1.01
1.07

1.0401
0.10.4


Unix
http://www.freebsd.org/cgi/man.cgi. line- *BSD
Unix. (useradd .)
.
Practical Unix & Internet Security, (2nd Edition), Simson Garfinkel,
Gene Spafford (O'Reilly, 1999).
.
NT
http://Jenda.Krynicky.cz -
Win32 .
http://windows.microsoft.com/windows2000/en/server/help/
Windows 2000. ( Active Directory-Concepts-
Understanding Active Directory-^Understanding Groups). Windows 2000.
http://www.activestate.com/support /mailing_lists.htm.

Perl-Win32-Adniin Perl-Win32-Users.
Win32.
Win32 Perl Programming: The Standard Extensions, Dave Roth (Macmillan Technical Publishing, 1999) Win32 Perl.
Windows NT User Administration, Ashley J.Meggitt, Timothy
D. Ritchey (O'Reilly, 1997).
http://www.mspress.com. Microsoft NT Resource Kit. '
RK.

121

http://www.roth.net. W i n 3 2 : :AdminMisc,
W i n 3 2 : : Perms Win32, .
XML


XML. - , ,
, , XML.
, XML Perl , , .
http://msdn.microsoft.com/xml

http://www.ibm.com/developer/xml . Microsoft, IBM XML.


http://www.activestate.com/support/mailing_lists.htm - Perl-XML. ( ) .
http://www.w3.org/TR/1998/REC-xml-19980210. XML1.0.
, - XML, .
- , , .
http://www.xml.com. , XML. , (Tim Bray), .
XML: The Annotated Specification, Bob DuCharme (Prentice Hall,
1998).
XML.
XML Pocket Reference, Robert Eckstein (O'Reilly, 1999). ,
XML .

http://www.mcs.anl.gov/~evard. (Remy Evard). -


, ;
. , Tenwen, ( ,
). , Implemented
the Hosts Database.
http://www.rpi.edu/~finkej/.
(Jon Finke) .

MacOS
NT/200Q
Unix



.

, . ,
, .
:

, ,
. , , .

, , , ,
. ., - . Unix . Unix
. ,
/ , , . 2 , .

. ,
.

MacOS

123

,
- ,
,
API. , , API
, . . ,
. ,
,
, http://www.macperl.com.
, Perl.
, ,
, .
Perl- k i l l ( ) ,
MacOS.
, ( Perl).
,
, .
MacOS
- , MacOS,
, . M a c : :Processes,
Macintosh (Macintosh Process Manager) MacOS Toolbox API . , Inside Macintosh:Processes .
Mac: :Processes use
Mac::Processes, %Process.
- ,
Perl, . %Process
, . (Process Serial Number , PSN - MacOS
),
:
use Mac: Processes;
Print map{"$_\n"} keys %Process;
, , . , Processlnfo.

124

4.
, ^ . ,
, Inside Macintosh:Processes. processName(), processNumber(), p r o _
cessTypeO, processSignatureO, processSizeO, processModeO, processLocation(), processLauncher(), processLaunchDate(), processActiveTime() processAppSpec().
:
use Mac::Processes;
while(($psn, $psi) = each (%Process)){
$name = $psi->processName();
write;
format STDOUTJTOP =
Process Serial Number

Process Name

format STDOUT =
@
$psn,

$name

:
Process Serial Number

Process Name

8192
8193
8194
8195
8198

FaxMonitor
Queue Watcher
Finder
Serial Port Monitor
MacPerl

, , ,
. , . , , - SetFrontProcess($psn). (Perl k i l l ( ) ). , ,- DO'
AppleEvent, , . cpfi'
- Mac: : A p p s : '.Launch (Chns
Nandor). Q u i t A p p s ( ) ,
, ID. : : Apps: : Launch
*
/ . ,
: : Processes.

NT/2000

125

,
.
NT/2000
NT/2000,
, . : .
Microsoft Resource Kit
3 , NT Resource Kit . : pulist.exe
kill.exe. , - .
tlist.exe, pulist.exe,
, ,
pulist.exe. , pulist.exe
,
.
pulist:
Process
TAPISRV.EXE
TpChrSrv.exe
RASMAN.EXE
mstask.exe
mxserver.exe
PSTORES.EXE
NDDEAGNT.EXE
explorer.exe
SYSTRAY.EXE
cardview.exe
ltmsg.exe
daemon.exe

PID
119
125
131
137
147
154
46
179
74
184
167
185

User
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
OMPHALOSKEPSIS\Administrator
OMPHALOSKEPSIS\Administrator
OMPHALOSKEPSIS\Administrator
OMPHALOSKEPSIS\Administrator
OMPHALOSKEPSIS\Administrator
OMPHALOSKEPSIS\Administrator

pulist.exe Perl . :
Spulistexe = "\\bin\\PULIST.EXE"; #
open(PULIST,"$pulistexe|") or die " $pulistexe:$!\n";
scalar <PULIST>;
#
while(defined($_=<PULIST>)){
($pname,$pid,$puser) = /~(\S+)\s*(\d+)\s*(.+)/;
print "$pname:$pid:$puser\n";
close(PULIST);

126

4.
- kill.exe. . , .
, , .
kill.exe . - ;
kill.exe <process id>
. //,
kill.exe /f <process id> Perl - .

Win32::IProc
- Win32: : IP roc (Amine Moulay Ramdane). ,
, , HoWin32::Iproc,B , , Win32::Process. Win32;:Process , :
, .
,
. W i n 3 2 : : IP roc,
.
:
use Win32::IProc;
. "IProc"
$pobj = new Win32::IProc or die " proccess: $!\n";
,
. ,
, :
$poPj-> EnumProccesses(\@processlist) or
die " :$!\";
processlist - . : ProcessName Processld .
:
use Win32::IProc;
$pobj=new Win32::IProc or die " process: $!\n";
$pobj->EnuraProcesses(\@processlist) or
die " :$!\";

NT/2000

127

foreach Sprocess (@processlist){


$pid = $process->{Process!d};
$name = $process->{ProcessName};
write;
format STDOUT_TOP =
Process ID
Process Name
format STDOUT =
@><
$pid,
$name
:

Process ID

Process Name

System-Idle

System

25
39
41
48
78
82

smss.exe
winlogon.exe
services.exe
lsass.exe
spoolss.exe
DKSERVICE.EXE

pulist.exe , W i n 3 2 : :1
.
, pulist.exe.
pulist.exe ,
Win32: :1 - . ,
, , (.dll) . :
FULLPATH,
# , NOPATH
use Win32::IProc "FULLPATH";
Spobj = new Win32::IProc;
$pobj->EnumProcesses(\@processlist) or
die " :$!\";
foreach $process (@processlist){
print "\n",$process->{ProcessName},
"\n",('=' x length($process->{ProcessName})),"\n";
Spobj->GetProcessModules($process->{ProcessId},

128

4.
\@modules,FULLPATH);
print join("\n",map {lc $_->{ModuleName}} ^modules), "\n";

GetProcessModulesO , , , . , ,
, ,
.
. ( ) ,
,
ModuleName.
:'
smss. exe
\systemroot\system32\smss.
:\winnt\system32\ntdll. dll
winlogon.exe
\??\:\winnt\system32\winlogon.
:\winnt\system32\ntdll.dll
:\winnt\system32\msvc rt.dll
c:\winnt\system32\kernel32.dll
c:\winnt\system32\advapi32. dll
c:\winnt\system32\user32.dll
:\winnt\system32\gdi32.dll
c:\winnt\system32\rpcrt4.dll
c:\winnt\system32\userenv.dll
:\winnt\system32\shell32.dll
:\winnt\system32\shlwapi.dll
:\winnt\system32\comctl32.dll
c:\winnt\system32\netapi32.dll
c:\winnt\system32\netrap.dll
c:\winnt\system32\samlib.dll
:\winnt\system32\winmm.dll
:\winnt\systen32\cwcmmsys.dll
:\winnt\system32\cwcfm3.dll
c:\winnt\system32\msgina.dll
:\winnt\system32\rpclts1.dll
c:\winnt\system32\rpcltc1.dll...
. '
, . 46

.

NT/2000

129


.
, . ,
.
. - - , , .
, , .
, , O p e n ( ) W i n 3 2 : :1. ()
, ,
, .
, . W i n 3 2 : :1
Processes and Threads Win32 SDK , http://msdn.microsoft.com. , (), CloseHandle().
, () :

$pobj->Kill($handle,Sexitcode);
, . ,
, GetStatusO, .
, :
use Win32::IProc qw(PROCESS_QUERY_INFORMATION INHERITED DIGITAL);
Spobj = new Win32::IProc;
$pobj->Open($ARGV[0],PROCESS_QUERY_INFORMATION,INHERITED, \$handle) or
warn " :".$pobj->LastError()."\n";
DIGITAL =
$pobj->GetStatus($handle,\$statusinf,DIGITAL);
Spobj->CloseHandle($handle);
while (($procname,$value)=each %$statusinfo){
print "$procname: $value\n";

130

4.
- :
KernelTime: 00:00:22:442:270
ExitDate:
ExitTime:
CreationDate: 29/7/1999
CreationTime: 17:09:28:100
UserTime: 00:00:11:566:632
,
. ExitDate ExitTime , . , , , ,
?
. -,
,
, . GetStatusQ
.
- ate( ), .
Create () Win32: -.IP roc ,
Win32: : Process. ,
($pobj), ,
. , , , . , ,
.

Win32::Setupsup
,
, , .
Win32: : Setupsup (Jens Helberg). Setupsup,
(
Setup.exe).

.
, .
( ), . Win32: : Setupsup . '

NT/2000

131

( ,
).
,
, Win32 : : Setupsup.
Win32: : Setupsup,
. ,
:
use Win32: :Setupsup;
$rnachine = ""; #
Win32: -.Setupsup: :GetProcessList($machine, \@processlist, \@threadlist) or
die " : ".Win32: :Setupsup: :Getl_astError(). "\n";
pop(@processlist); ft ,

foreach $processlist (@processlist){
$pid = $processlist->{pid};
$name = $processlist->{name};
write;
format STDOUT_TOP =
Process ID
Process Name
format STDOUT =
@<
$pid,
$name
:
KillProcess($pid, $exitvalule, Ssystemprocessflag) or
die " : ".Win32::Setupsup::GetLastError()."\n";
.
, , (
0).
( , Debug Prog rams).
. , , . ,
, :
Win32::Setupsup::EnumWindows(\@windowlist) or
die " :
".Win32::Setupsup::GetlastError()."\n";

132

4. ^
@windowlist , , .
,
, ,
GetWindowText( ) :
use Win32: :Setupsup;
Win32: :Setupsup: :EnumWindows(\@windowlist) or
die " :
".Win32: : Setupsup: :GetLastError(). "\n";
foreach Swhandle (@windowlist){
if (Win32: : Setupsup: :GetWindowText($whandle,\$text)){
print "$whandle: $text","\n";
}
else {
warn " Swhandle" .
Win32: -.Setupsup: :GetLastError(). "\n";

:
66130: chapter02 - Microsoft Word
66184: Style
194905150:
66634: setupsup - WordPad
65716: Fuel
328754: DDE Server Window
66652:
66646:
66632: OleMainThreadWndName
, , .
-
. 66130 Microsoft Word, ( ). 661 84 , Microsoft Word.
, ?
Win32: :Setupsup EnumChildWindowsO, '
.
:
use Win32: :Setupsup;
ft
Win32: :Setupsup: :EnumWindows(\@windowlist) or
die " :
".Win32: :Setupsup: :Getl_astError() . "\n"; .

NT/2000

133

#
# :
# ,
# . ,
# GetWindowProperties
# ( ),
# .
# .
for (@windowlist){$windowlist{$_}++; }

foreach $whandle (@windowlist){
if (Win32: :Setupsup: :EnumChildWindows($whandle,\@children)){
#
$children{$whandle} = [sort {$a <=>$b} ^children];
# ,
# %windowlist
#
1
foreach $child (@children){
delete $windowlist{$child};

ft
# , ,
#
( )
foreach my $window (sort {$a <=> $b} keys %windowlist){
&printfamily($window,0);
ff
# ()
sub printfamily {
, ?
my($startwindow,$level) = @_;
#
print((" " $level). "$startwindow\n");
return unless (exists $children{$startwindow}); ,
#
: # remove all children from
the hash, we won't iterate over them ( ,
). - . . .


134

4.

$level++;
foreach $childwindow (@{$children{$startwindow}}){
&printfamily($childwindow,$level);

, , : GetWindowProperties(). GetWindowProperties() . , GetWindowPropertiesO, ,


.
Win32: : IP .
W i n 3 2 : : Setupsup ,
. , . GetWindowPropertiesO : ,
, , ,
.
:
Win32::Setupsup::GetWindowProperties($ARGV[0],["rect","id"],\%info);
print "\t" . $info{rect}{top} . "\n";
print $info{rect}{left} . " -" . $ARGV[0] .
"- " . $info{rect}{right} . "\n";
print "\t" . $info{rect}{bottom} . "\n";
. ( , , ) 66180:
154

272 -66180- 903


595
GetWindowPropertiesO
rect.
. , Perl , windowse, http://greatis.virtualave.net/
products.htm.
, ,
,
? , . , :

NT/2000

135

"Prestidigitation In Progress . . . 32% complete"


, :
Win32::Setupsup::SetWindowText($handle,$text);
rect .

:
use Win32::Setupsup;
$info{rect}{left} = 0;
$info{rect}{right} = 600;
$info{rect}{top} = 10;
$info{rect}{bottom}= 500;
Win32::Setupsup::SetWindowProperties($ARGV[0],\%info);
.
SendKeysO
. :
use Win32::Setupsup;
Stexttosend = "\\DN\\Low in the gums";
Win32::Setupsup::SendKeys($ARGV[0], Stexttosend, ",0);
, , . SendKeysO :
, , , , ,
. ,
, .
.

. (
), . API. GUI,
1
.
1


Win32Guitest (Ernesto Guisado).
, Win32: :Setupsup.

136

4. ^


(Window Management Instrumentation, WMI)
, NT/2000. , , . (WMI)
Windows 2000 ( NT4.0 SP4+).1 , Windows 2000 , WMI
NT/2000.
, WMI , . - , , . , -
RAID, , ,
RAID, . ,
WMI ,
.
, WMI,
LearnWBM WMI SDK WMI http:/ /msdn.microsoft.com/developer/sdk. , - Distributed Management Task Force http://
www.dtmf.org. , .
WMI - ( Microsoft) Web-Based Enterprise Management WBEM. - , World Wide Web. , Distributed Management Task
Force (DMTF), -,
. , , WBEM '
. WBEM , . WBEM
,
, , Simple Network Management Protocol (SNMPI
( 10
) Common Management Information Protocol (CMIP).
1

Download SDK WMI http://msdn.microsoft.com/de'


8
veloper/sdk ,
WMI NT4.0SP4 ( ).

NT/2000

137

WBEM
(Common Information Model, CIM). CIM -
WBEM/WMI.
, , .
,
. , .
CIM , .
: CIM
CIM. , ( ,
. .); - (. .
). SNMP SMI
MIB ( 10).
CIM, , , .
, (Managed Object
Format, MOF), .
CIM :

(core model) ,
WBEM.

(common model) ,
. : , , , .


(Extension schema), , .
WMI, WBEM, - Win32, ,
Win32, . WMI WBEM,
CIM, Win32. 1 , , Perl WMI.
: ODBC ( ) COM/DCOM ( /
)
Microsoft , Win32-OKpy>KeHHH .
Win32 .

138

4.
. COM/DCOM, ODBC WMI ( , ^
). COM/DCOM , , .
Perl ^
, . , :

WMI.
, (. .
).

.
. WMI Win32.


WMI VBscript/JScript Perl.

.
Perl, WMI, , ,
. , ,
: , ..
, - w b e m E r r F a i l e d 0x8004100
. , Perl . ,

.

. ,
,
:

, W i n 3 2 : :OLE, . Win32-Users ActiveState


http://www.activestate.com - . '
VBscript, '
. , ADSI ( ) 6.

Perl
Win32
Perl - TurboPerl (William

NT/2000

139

P. Smith), http://users.erols.com/turboperl/, dumpvar.pl D a t a : : D u m p e r . E


( ), Perl.
.

WMI SDK.
VBscript .

WMI WMI SDK.


.

Perl. - ,
Win32 .
(namespace) WMI. WMI SDK .
cimv2, .
,
.
; , , . Win32_Process ( Win32).
, . ,
, .
.
use Win32: :OLECirT);
Sserver = ''; #
SWbemLocator
$lobj = Win32::OLE->new('WbemScripting.SWbemLocator')
or die " : ".Win32::OLE->LastError()."\n";
# ,
$lobj->{Security_}->{impersonationlevel} = 3;
ft SWbemServices
Ssobj = $lobj->ConnectServer($server, 'root\cimv2')
or die " :
".Win32: :OLE->l_astError(). "\n";

140

4.

Sprocschm = $sobj->Get('Win32_Process');
:

, -

, . .
cimv2 WMI
Win32_Process
, COM moniker's
display name. WMI SDK, () -
- . . :
use Win32::OLE('in');
Sprocschm = Win32::OLE->GetObject(
'winmgmts: {impersonationl_evel=impersonate}!Win32_Process')
or die " : ".Win32::OLE->LastError()."\n";
, Win32_Process, ,
Win32. Win32_Process, . ; , , - in Win32: :OLE. , .
Sprocschm : Properties_ Methods. , collection object . collection object ;
(Properties..) (Methods_) . in '
. ,
,
Name . '
in ADSI (
) 6. :
1

use Win32::OLE('in );
# ,
# Win32_process,

NT/2000

141

#
Iprocschm = Win32::OLE->GetObject(
'winmgmts:{impersonationLevel=impersonate}!Win32_Process')
or die " : ".Win32::OLE->LastError()."\n";
print "--- Properties \n";
print join("\n",map {$_->{Name}}(in $procschm->{Properties_}));
print "\n Methods ---\n";
print join("\n",map {$_->{Name}}(in $procschm->{Methods_}));
( NT4.0) :
--- Properties --Caption
CreationClassName
CreationDate
CSCreationClassName
CSName
Description
ExecutablePath
ExecutionState
Handle
InstallDate
KernelModeTime
MaximumWorkingSetSize
MinimumWorkingSetSize
Name
OSCreationClassName
OSName
PageFaults
PageFileUsage
PeakPageFilellsage
PeakWorkingSetSize
Priority
Processld
QuotaNonPagedPoolUsage
OuotaPagedPoolUsage
QuotaPeakNonPagedPoolUsage
QuotaPeakPagedPoolUsage
Status
TerminationDate
UserModeTime
WindowsVersion
WorkingSetSize
--- Methods --Create
Terminate
GetOwner
GetOwnerSid

142

4.
. , Win32_Process :
use Win32: :OLE( 'in' );
#
$sobj = Win32: :OLE->GetObject(
'winmgmts: {impersonationLevel=impersonate} ' )
or die " : ".Win32: :OLE->LastError(). "\n";
foreach Sprocess (in $sobj->InstancesOf("Win32_Process")){
print $process->{Name}. " pid #".$process->{Process!d}, "\n";

}

(. . ! Win32_Process). , . InstancesOf ()
- (collection object), .
Name Processld. ,
.

,
:
foreach Sprocess (in $sobj->InstancesOf("Win32_Process")){
$process->Terrrinate(1 ) ;
, . ; , .
,
WMI . WMI \32-
, "
.
, WinNT
2000. .
Unix
Unix 10
, .
,
NT, Unix '
:

Unix

143

1. .
2. .
3. .
Perl setprio r i t y O , setpgrpQ k i l l ( ) . . , :

, ps

/dev/kmem

: : ProcessTable

.
, : : ProcessTable, .
, . . .

Unix ps, .

, , ,
. :
.
- ( ). ps SunOS:
USER
dnb
dnb
dnb
remy
sys
dnb
dnb
dnb
root

PID
385
24103
389
15396
393
29488

%CPU
0.0
0.0
0.0
0.0
0.0
0.0
29544 0.0
5707 0.0
28766 0.0

%MEM SZ RSS TT
0.0 268
0 p4
2.610504 1092 P3
2.5 3604 1044 p4
0 p9
0.0 252
0.0 28
09
0.0 68
0 P5

STAT START TIME COMMAND


IW Jul 2 0 :00 /bin/zsh

S
S
IW
IW
IW
0.4 24 148 P7 R
0 p6 IW
0.0 260
0 7 IW
0.0 244

Aug 10
Jul 2
Jul 7
Jul 2
20:15
20:39
Jul 24
13:20

35 :49
60 :16
0.:01
0:02
0:00
0 :00
0 :00
0:00

emacs
emacs

-zsh (zsh)
in. identd
screen
less
-zsh (zsh)
-:0 (xdm)

. . ,
, . Unix
, .
Perl, , :
( ) ps, while(<FH>){...}

144

'

4.

splitO, unpack() s u b s t r ( ) .
(Tom Christiansen) (Nathan Torkington) Perl:
, - , 2000 . (Perl Cookbook, O'Reilly).

. , , /dev/
kmem, .
. ,
(
), (
, , ),
.
, ,
packQ, u n p a c k ( )
. ( /dev/kmem),
r e a d ( ) u n p a c k ( ) .
, top ( ftp://ftp.groupsys.com/
pub/top), ,
.
.
/
Unix
- /. .
.
, .
,
. , .
. , / , 10
, .
, /,
,
, . ,
,
( 4, 5 8) proofs mount_procfs.
/ "
. -

Unix

145

, Perl lstat():
opendir(PROC, "/proc") or die " /proc:$!\n";
while (defined($_= readdir(PROC))){
next if ($_ eq "." or $_ eq "..");
next unless /"\d+$/; # ,
ft
print "$_\t". getpwuid((lstat Yproc/$_")[4])."\n";

closedir(PROC);
;

,
/ u n p a c k ( ) . status psin/o.
-, , , , (include) , . ( ), .
, , ,
, . , ,
.

Proc::ProcessTable
. (Daniel J. Urist) ( ) : : ProcessTable, Unix. / kmem, .
, : :ProcessTable: :Process
:
use Proc::ProcessTable;
$tobj = new Proc::ProcessTable;
(tied variable) .
. %Process, : : Processes .
, table():

4. ;

146
Sproctable = $tobj->table();

table() , .
. .
,
. , .
:
use Proc: :ProcessTable;
$tobj = new Proc: : ProcessTable;
Sproctable = $tobj->table();
for (@$proctable){
print $_->pid."\t". getpwuid($_->uid). "\n";
, , fieldsO Proc: iProcessTable (..
$tobj).
Proc : : ProcessTable
: kill(), p r i o r i t y O pgrp(),
,
.
, . , , ,
Proc : : ProcessTable Unix,
.
Proc: : ProcessTable:
use Proc: : ProcessTable;
$t = new Proc: :ProcessTable;
foreach $p (@{$t->table}){
if ($p->pctmem > 95){

, 95%
Unix, *
pctmemQ ( ). *1
, , ,
.
kill () - :
print " ". $p->pid. "\t" . getpwuid($p->uid) . "\n";
print "? (yes/no) ";

Unix

147

chomp($ans = );
next unless ($ans eq "yes");
: ,
, , . ,
, , , , . ,
, , ,
' , ,
.
, - . , , (,
). ,
IRC-. - -,
IRC- .
, , , IRC. , - , (
), , - -. , , .
eggdrop. , , :
use Proc::ProcessTable;
open(LOG, "$logfile") or die " :$!\n";
$t = new Proc::ProcessTable;
foreach $p (@{$t->table}){
if ($p->fname() =" /eggdrop/i){
print LOG time."\t".getpwuid($p->uid).
"\t".$p->fname()."\n";
}
}
close(LOG);
, : ! ,
, , , . , , .
, Perl . -

148

4.
.
. - .
,
, .
, . . ,
. , , , , .
-
, , , , , . ,
. , - .

, : : cessTable. , .
, , , .
. , (), ,
:
use Proc: :ProcessTable;
$interval
= 600; 5
Spartofhour = 0; # ,
$tobj = new Proc: :ProcessTable;
# , Sinterval

&collectstats;
&dumpand reset if (Spartofhour >= 3600);
sleep($interval);

sub collectstats {

Unix

149

my(Sprocess);
foreach $process (@{$tobj->table}){
#
next if ($process->pid() == $$);
#
push(@last,$process->pid(), $process->fname());
# ,
next if ($last{$process->pid()} eq $process->fname());
# ,
$collection{$process->fname()}++;
}
%last,
%last = @last;
Spartofhour += Sinterval;


sub dumpandreset{
print scalar Iocaltime(time).("-"x50)."\n";
for (sort reverse_value_sort keys %collection){
write;
undef %collection;
Spartofhour = 0;
# () %collection
#
sub reverse_value_sort{
return $collection{$b} <=> $collection{$a} || $a crop $b;
format STDOUT =
$collection{$_}
format STDOUT_TOP =
Name
Count

.
(. .
), -

150

4.
, . . , .


. , , .

. .
, . , , ( , ,
). , , .
Windows NT/2000
, ,
, ,
, - nthandle (Mark Russinovich),
http://www.sysinternals.com. .
:
System pid: 2
10: File
84: File
cc: File
dO: File
d4: File
e8: File
fc: File
118: File
128: File
134: File
154: File
1bO: File
294: File
2a4: File
SMSS.EXE
4:
c:
28:

C:\WINNT\SYSTEM32\CONFIG\SECURITY
C:\WINNT\SYSTEM32\CONFIG\SAM.LOG
C:\WINNT\SYSTEM32\CONFIG\SYSTEM
:\WINNT\SYSTEM32\CONFIG\SECURITY.LOG
C:\WINNT\SYSTEM32\CONFIG\DEFAULT
C:\WINNT\SYSTEM32\CONFIG\SYSTEM.ALT
C:\WINNT\SYSTEM32\CONFIG\SOFTWARE.LOG
C:\WINNT\SYSTEM32\CONFIG\SAM
C:\pagefile.sys
C:\WINNT\SYSTEM32\CONFIG\DEFAULT.LOG
C:\WINNT\SYSTEM32\CONFIG\SOFTWARE
\Device\NamedPipe\
C:\WINNT\PROFILES\Administrator\ntuser.dat.LOG
C:\WINNT\PROFIlES\Administrator\NTUSER.DAT

pid: 27 (NT AUTHORITY-.SYSTEM)


Section
C:\WINNT\SYSTEM32\SMSS.EXE
File
C:\WINNT
File
C:\WINNT\SYSTEM32

151

:
> nthandle c:\temp
Handle V1.11
Copyright () 1997 Mark Russinovich
http://www.sysinternals.com
WINWORD.EXE
WINWORD.EXE
WINWORD.EXE

pid: 652
pid: 652
pid: 652

C:\TEMP\"DFF2B3.tmp
C:\TEMP\~DFA773.tmp
C:\TEMPVDF913E.tmp

nthandle -.
Perl ,
. ,
- .
NT/2000 , .
stat() ,
. NT/2000 .
:
W i n 3 2 : : C h a n g e N o t i f y (Christopher J. Madsen)
W i n 3 2 : : A d v N o t i f y (Amine Moulay Ramdane).
, . .
.
W i n 3 2 : : A d v N o t i f y - .
AdvNotify:
# ,
#
use Win32::AdvNotify qw(All %ActionName);
use Data::Dumper;
Saobj = new Win32::AdvNotify()
or die " \";
(monitoring thread) . W i n 3 2 : :AdvNotify ,
. :
Sthread = $aobj->StartThread(Directory => 'C:\temp',
Filter => All,
WatchSubtree => 0)
or die " \";

152

4.
; .
Filter (. 4.1)
(SETTING1 | SETTING2 | SETTINGS.. .), .
4.1. Filter Win32::AdvNotify

FILE_NAME
DIR_NAME
ATTRIBUTES
SIZE
LASTJWRITE
CREATION
SECURITY

, , ()
()


()
()
(ACL .) ()

A l l - ,
. Filter
, A l l . WatchSubtree , .
Sta rtTh read () , ,
:
$thread->EnableWatch() or die " \";
DisableWatch(), .
, , ? -,
, . ,
9 .
, ,
:
while($thread->Wait(INFINITE)){
print "- !\";
last if ($changes++ == 5);
}

w h i l e ( ) WaitQ .
, . Wait()
,
. , '
. W a i t ( ) .

153

,
. :
$thread->Terminate();
undef $aobj;
. , -
, , .
, while( )
:
while($thread->Wait (INFINITE) ){
while ($thread->Read(\@status)){
foreach $event (@status)<
$filename = $event->{FileName};
$time
= $event->{DateTime};
Section = $ActionName{$event->{Action}};
write;

format STDOUT =
@< < @<
$filename, $time, Saction
format STDOUT_TOP =
File Name
Date

Action

- ReadQ. @status . ,
:
{'FileName' => "GLF2425.TMP',
'DateTime' => '11/08/1999 06:23:25',
'Directory' => 'C:\temp',
'Action' => 3 }
,
Read() while().
, :
File Name

Date

Action

"DF40DE.tmp
~DF6E5C.tmp

11/08/1999 07:29:56p FILE_ACTION_REMOVED


11/08/1999 07:29:56p FILE_ACTION_ADDED

154

4. ;
~DF6E66.tmp
"DF6E5C.tmp

11/08/1999 07:29:56 FILE_ACTION_ADDED


11/08/1999 07:29:56 FILE_ACTION_REMOVED

, NT/2000
. , , (, , )
. , , .
, , 0
TCPVstat, . TCPVstat TCP View Professional Edition, http://www.winternals.com.
,
,
. Win32: :IpHelp. , :
use Win32: : IpHelp;
: "IpHelp" 1
my $iobj = new Win32: : IpHelp;

Siobj ->GetTcpTable(\@table , 1 ) ;
foreach Sentry ( table) {
print $entry->{LocalIP)->{Value} . ":" .
$entry->{LocalPort}->{Value}. " -> ";
print $entry->{RemoteIP}->{Value} . ":" .
$entry->{RemotePort}->{Value}."\n";
, Unix.
Unix
Unix '
. ,
. 1
Abell) , ^
" Isof (LiSt Open Files), ftp'-i
vic.cc.purdue.edu/pub/tools/unlx/lsof. Isof ?

Unix-. - ^
, Perl . - - "
. .

156

4.
netscape 21065 dnb
pseudo/mm@0:ze -

VCHR

13,12

OtO

5821 /devices/

netscape 21065 dnb


Ox6034d1eO

7u FIFO Ox6034d264

Ot1

47151 PIPE->

netscape 21065 dnb


8u inet Ox6084cb68 Oxfb210ec
edu:46575->host2.ccs.neu. edu:6000 (ESTABLISHED)

TCP host.ccs.neu

netscape 21065 dnb 29u inet 0x60642848 Ot215868


edu:46758-> www.mind-bright.se:80 (CLOSE_ WAIT)

TCP host.ccs.neu

, .
(VDIR),
(VREG), (VCHR), (FIFO) (inet), .
Isof Perl -
field (-F).
,
ps. .
. (process sets)
(file sets), . - ,
; - . ,
0.
NUL (ASCII 0), - N1 (ASCII 12). , (NUL ~@):
p21065~@cnetscape~@u6700"@Ldnb~@
fcwd~@a "@1 ~@tVDIR~@DOx2bOOb4b"@s8192~@i12129~@n/home/dnb~@
ftxt"@a " ~<s>tVREG~@DOx2b004de~@s14382364~@i656749~@n/net/arch-solaris
(fileserver:/vol/systems/arch-solaris)~@
ftxt"@a ~@1 ~@tVREG"@DOx800006~@s54656~@i35172~@n/usr (/dev/dsk/cOtOdOs6)"@
ftxfda "@1 "@tVREG~@DOx800006~@s146740~@i6321~@n/usr/lib/libelf.so.r@
ftxt~@a "@1 "@tVREG~@DOx800006~@s40184"(>i6089~@n/usr (/dev/dsk/cOtOdOs6)~@
ftxt~a ~@1 "@tVREG~@DOx800006"@s69292"@i1026ir@n/usr (/dev/dsk/cOtOdOs6)"g
ftxt~@a "@1 "@tVREG"@DOx800006~@s21376~@i79751~@n/usr/lib/locale/en_US/
en_US.so.1"@
ftxt"@a "@1 ~@tVREG"@DOx800006"@s19304"ia)i5804"ian/usr/lib/libmp. so. 2"@
ftxt"@a ~@1 ~@tVREG~@DOx800006~@s98284"@i22860~@>n/usr/openwin/lib/
libICE.so.6"@

157

ftxt~@a ~@1 ~@tVREG"@DOx800006"@s46576"@i22891"@n/usr/openwin/lib/


libSM.so.6"@
ftxt"@a ~@1 "@tVREG"@DOx800006"@s1014020"@i5810"@n/usr/lib/libc.so.@
ftxt"@a ~@1 "@tVREG"@DOx800006"@s105788"@i5849"ian/usr/lib/libm. so. 1"@
ftxt"@a ~@1 "@tVREG"@DOx800006~@s721924"<5>i5806~@n/usr/lib/libnsl.so. @
ftxt~@a "@1 "VREG^)Ox800006"(3>s166196~(s>i5774~@n/usr/lib/ld. so. 1"@
fO"@au"@l "@tVCHR"@DOx600003"@o73"@i5863"@n/devices/pseudo/
):3->ttcompat->ldterm->pteni->pts~@
f3"@au~@l ~@tVCHR~@DOx34000c~@oO~@i582r@n/devices/pseudo/mm@0:zero~@
f7"@au~@l "@tFIFO"@dOx6034d264"@oT@i47151"@nPIPE->Ox6034d1eO"@
f8"@au"@l "@tinet"@dOx6084cb68"@o270380692"isPTCP"@nhost. ccs.neu.edu:46575->
host2.ccs.neu.edu: 6000"@TST=ESTABLISHED"@
f29~@au~@l "@tinet"@dOx60642848"@o215868"@PTCP"@nhost.ccs.neu.edu:46758->
www.mindbright.se: 80"@TST=CLOSE_WAIT"@
. - ( ):
p21065"@cnetscape~@u6700~@Ldnb~@
, ( (pid), - , - (uid) L - (login)),
. .
/ , .
.
, ,
:
use Text::Wrap;
Slsofexec = "/usr/local/bin/lsof"; fl Isof
it (F)ield, NUL (0), (L)ogin,
# (t)ype (n)ame
Slsofflag = "-FLOtn";
open(LSOF,"$lsofexec $lsofflag|") or
die " $lsofexec:$!\n";
while(<LSOF>){

if (substr($_,0,1) eq "p"){
($pid,$login) = split(/\0/);
$pid = substr($pid,1,length($pid));

158

4.
ft .
8 :
if (substr($_,0,5) eq "tVREG"){
($type,$pathname) = split(/\0/);
8 ,
8 ,
#
next if ($seen{$pathname} eq $pid);
$seen{$pathname} = $pid;
Spathname = substr($pathname,1,length($pathname));
push(@{$paths{$pathname}},$pid);

close(LSOF);
for (sort keys %paths){
print "$_:\n";
print wrap("\t","\t",join(" ",@{$paths{$_}})), "\n";
Isof . , .
,
( (David Muir Sharnoff )
Text : :Wrap):
/usr (/dev/dsk/cOtOdOs6):
115 117 128 145 150 152 167 171 184 191 200 222 232 238
247 251 276 285 286 292 293 296 297 298 4244 4709 4991
4993 14697 20946 21065 24530 25080 27266 27603
/usr/bin/tcsh:
4246 4249 5159 14699 20949
/usr/bin/zsh:
24532 25082 27292 27564
/usr/dt/lib/libXn.so.3:
21065 21080
/usr/lib/ld.so.1:
115 117 128 145 150 152 167 171 184 191 200 222 232 238
247 251 267 276 285 286 292 293 296 297 298 4244 4246
4249 4709 4991 4993 5159 14697 14699 20946 20949 21065
21080 24530 24532 25080 25082 25947 27266 27273 27291
27292 27306 27307 27308 27563 27564 27603
/usr/lib/libc.so. 1:
267 4244 4246 4249 4991 4993 5159 14697 14699 20949
21065 21080 24530 24532 25080 25082 25947 27273 27291
27292 27306 27307 27308 27563 27564 27603

159

, Unix, - .
-, . , , , . 6660-7000. Isof
:
$lsofexec = "/usr/local/bin/lsof";
$lsofflag = "-FLOc -iTCP:6660-7000";

160

4. ^
,
.
. ,
(. . , ), , , , .
- ,
. 3 , . , . : , ,
Perl
. .
- , - ,
.



CPAN
Mac: '.Processes ( MacPerl; - CNANDOR
Mac-Glue)
Win32: :1

1.01
0.011

Win32 ::ISync ( http://www.generation.net/~aminer/Perl/)


Win32: :IProc ( http://www.genera.tion.net/~aminer/Perl/)

1.11

Win32: -.Setupsup ( ftp-./lftp.roth.net/


pub/NTPerl/Others/SetupSup/ http://Jenda.Krynichy.cz)
Win32: :Lanman ( ftp: / /ftp.roth.net/
pub /ntperl/ Others /Lanman/)
Win32 : : OLE ( ActiveState Perl)
JDB

980320

Proc: :ProcessTable
DURIST
Win32: :AdvNotify ( http://www.generation.net/~aminer/Perl/)
Data: : Dumper
GSAR
Win32: :IpHelp ( http:/ /www.generation.net/~aminer/Perl/)
MUIR
Text : : Wrap ( Perl)

0.26

1.32

1.05
1.11
1.01
2.101
1.02

98.1129^,

161

Win32::IProc
Win32 ::1
, . http://www.generation.net/
-aminer/Perl/. Win32: :1, : Win32: :ISync Win32:.'API
(Aldo Calpini). ,
ActiveState http://dada.perl.it/.

.
. , Perl,
ActiveState C:\Perl:
1. install Win32-API
2. md c:\Perl\site\lib\auto\Win32\Sync C:\Perl\site\lib\auto\Win32\
Iproc
3. timer.dll sync.dll c:\Perl\site\lib\auto\Win32\Sync
4. iprocnt.dll, psapi.dll iproc.dll C:\Perl\site\lib\auto\
Win32\Iproc
5. iproc.pm, iipc.pm isync.pm C:\Perl\site\lib\Win32\
6. DLLPath iproc.pm :
my($DLLPath) ="C:\\Perl\\site\\lib\\auto\\Win32\\Iproc\\IProc.dll";
my($DLLPath1)="C:\\Perl\\site\\lib\\auto\\Win32\\Iproc\\IprocNT.dll";
my($DLLPath2)="C:\\Perl\\site\\lib\\auto\\Wln32\\Sync\\Sync.dll";
7. DLLPath iipc.pm :
my($DLLPath)="C:\\Perl\\site\\lib\\auto\\Win32\\Sync\\sync.dll";
8. DLLPath isync.pm :
my($OLLPath) ="C:\\Perl\\site\\lib\\auto\\Win32\\Sync\\sync.dll";
my($DLLPath1)="C:\\Perl\\site\\lib\\auto\\Win32\\Sync\\timer.dll";
Win32::Setupsup
Win32: :Setupsup / , ZIP- ftp://
ftp.roth.net/pub/NTPerl/Others/SetupSup/.
ActiveState, (Jenda Krynicky) , .
, , http://Jenda.Krynicky.cz.

-J52

4.
, pod , rldoc HTML.
setupsup.pm ( ,
< Perl >\site\lib\Win32\) .
, ,
, .


http://pudget.net/macperl - (Chris Nandor). MacPerl ( , ).
http://www.activestate.com/support/mailing_lists.htm.
Perl-Win32-Admin Perl-Win32~Users.
- Win32.
http://www.microsoft.com/management - Microsoft, WMI.
http://www.sysinternals.com - nthandle ( Handle)
NT/2000. http://
www.winternals.com .
MacPerl:Power and Ease, Vicki Brown, Chris Nandor (Prime Time
Freeware, 1998) - MacPerl. - http://www.macperl.com.
http://www.dmtf.org- Distributed Management
Task Force WBEM.
http://www.mspress.com - Microsoft NT Resource Kit.
RK.


NIS.NIS+uWINS
(DNS)

TCP/IP


(Transmission Control
Protocol), , , , (Internet Protocol)1.
TCP/IP. TCP/IP-
, IP-. IP- NNN.NNN.N.N, , 192.168.1.9.

, ,
. TCP/IP , 12 , .
IP- , .
, www.oog.org, 192.168.1.9,
, . , Perl .

IPv4,
. , IPv6 ( IP) .

164

5. TCP/IP


, 1- , :
, IP- . Unix /etc/
hosts, MacOS Macintosh HD:System Folder:Preferences:hosts %
\$systemroot$\System32\Drivers\Etc\hosts NT/2000. NT/2000
Imhosts, ,
. Unix:
127.0.0.1
192.168.1.1
192.168.1.2

localhost
everest.oog.org
rivendell.oog.org

everest
rivendell

.
oog.org TCP/IP- , , ,
. oog.org ,
( ).
,
Internet/ARPAnet. ,
, . , (NIC) (
SRI-NIC, . . SRI),
HOSTS.TXT. FTP NETINFO SRI-NIC.
, , . , . ,
SunOS /etc/hosts,
IP-. ~
, .
, IP-.
, (
) "
. - ( "
),
.

, .

165

(. . ,
, ).
, ,
.
- , . Perl , Perl . ,
.
,
:
open(HOSTS, "/etc/hosts") or die " :$!\";
while (defined ($_ = <HOSTS>)) {
next if /"#/; ,
next if /"$/:
s/\s*#.*$//;
it
($ip, @names) = split;
die "IP- Sip ! \"
if (exists $addrs{$ip});
$addrs{$ip} = [names];
for (@names){
die " $_ ! \"
if (exists $names{$_});
$names{$_} = $ip;
close(HOSTS);

/etc/hosts (
)
. -
, IP-.

:
$addrs{ '127. 0.0.1'} = ['localhost'];
$addrs{'192.168.1.2' } = [' rivendell.oog.org' ,' rivendell' ];
1
$addrs{ '192. 168. 1. 1 ' } = [ 'everest.oog.org' , 'everest ];
- - , . %names :
Snamesf 'localhost' }='127.0.0. 1 '
$names{ ' eve rest '} = ' 192. 168. 1.1

166

5. /|
$names{'eve rest.oog.org'}='192.168.1.1'
$names{'rivendell1}='192.168.1.2'
$names{'rivendell.oog.org'} = '192.168,1.2'
, 0.
. ,
IP- ( -
TCP/IP-). ,
, . ,
, 0
.
.


-
.
:
name: shimmer
address: 192.168.1.11
aliases: shim shimmy shimmydoodles
owner: David Davis
department: software
building: main
room: 909
manufacturer: Sun
model: Ultra60
name: bendir
address: 192.168.1.3
aliases: ben bendoodles
owner: Cindy Coltrane
department: IT
building: west
room: 143
manufacturer: Apple
model: 7500/100
name: Sulawesi
address: 192.168.1.12
aliases: sula su-lee.
owner: Ellen Monk
department: design
building: main
room: 1116
manufacturer: Apple
model: 7500/100

167

name: sander
address: 192.168.1.55
aliases: sandy micky mickydoo
owner: Alex Rollins
department: IT
building: main
room: 1101
manufacturer: Intergraph
model: TD-325
: _: , -=-
. ,
,
. , , ,
.
, :
Sdatafile =",/database";
$recordsep = "-=-\n";
open(DATA,Sdatafile) or die " :$!\";
$/=$recordsep; #
print "#\nfl host file - GENERATED BY $0\n# DO NOT EDIT BY HAND!\n#\n";
while (<DATA>) {
chomp;
#
key1,value1,...bingo,
%record = split /:\s*|\n/m;
print "$record{address}\t$record{name} $record{aliases}\n";
}
close(DATA);

n
host file - GENERATED BY createhosts
ft DO NOT EDIT BY HAND!

192.168.1.11 shimmer shim shimmy shimmydoodles


192.168.1.3
bendir ben bendoodles
192.168.1.12
Sulawesi sula su-lee
192.168.1.55 sander sandy micky mickydoo
Perl-
. - $/. , Perl
, -=-\, . -

5. /|

168

, while $_.
- split. ,
, - .
, , . $_ split().
, s p l i t ( ) ,
. 5.1.
5.1. , split()

$record[0]
$record[1]
$record[2]
$record[3]
$record[4]
$record[5]
$record[6]
$record[7]
$record[8]
$record[9]
$record[10]
$record[11]
$record[12]
$record[13]
$record[14]
$record[15]
$record[16]
$record[17]

Name
Shimmer
Address
192.168.1.11
Aliases
Shim shimmy shimmydoodles
Owner
David Davis
Department
Software
Building
Main
Room
909
Manufacturer
Sun
Model
Ultra60

. $record[0], - (. . =, =\, iwno4=Address, =192.168.1.11\...), .


.

169


?
3
.
. ,

, ,
. . .

.
. , , , . (, ),
. , (parser).
, .



- . , ,
. , ,
, , , . ,
:
$datafile ="./database";
Srecordsep = "-=-\n";
open(DATA,$datafile) or die " :$!\n";
$/=$recordsep; tt

170

5. /|

print "\\# host file - GENERATED BY $0\n# DO NOT EDIT BY HAND! \ntt\n";
while (<DATA>) {
chomp;
key1,value1, .. .bingo,
%record = split /:\s*[\n/m;
#
if ($record{name) =" /["-.a-zA-ZO-9]/) {
warn "!!!! $ record {name} ,
. . . \";
next;

if ($record{aliases} =" /["-.a-zA-ZO-9\s]/) {
warn "!!!! $record{name} ,
. . ,\";
next;
#
if (! $record{address}) {
warn "!!!! $record{name} IP-, . . .\n";
next;
.
if (defined $addrs{$record{address}}) {
warn "!!!! IP-: $record{name} &
$addrs{$record{address}}, . . .\n"
next;

else {
$addrs{$record{address}} = $ record {name};
print "$record{address}\t$record{name} $record{aliases}\n";
}
close(DATA);

9
. '
, .
:

host file - GENERATED BY createhosts3

171

DO NOT EDIT BY HAND!

ft Converted by David N. Blank-Edelman (dnb) on Sun Jun 7 00:43:24 1998


ft
number of hosts in the design department: 1.
# number of hosts in the software department: 1.
number of hosts in the IT department: 2.
# total number of hosts: 4
#
Owned by Cindy Coltrane (IT): west/143
192.168.1.3
bendir ben bendoodles
# Owned by Alex Rollins (IT): main/1101
192.168.1.55
sander sandy micky mickydoo
# Owned by Ellen Monk (design): main/1116
192.168.1.12
Sulawesi sula su-lee
# Owned by David Davis (software): main/909
192.168.1.11
shimmer shim shimmy shimmydoodles
( ),
:
Sdatafile =". /database";
# WinNT/2000, Unix
$user = ($"0 eq "MSWin32")? $ENV{USERNAME} :
(getpwuid($<))[6]." (". (getpwuid($<))[0]. ")";
open(DATA, $datafile) or die " :$!\";
$/=$recordsep; #
while (<DATA>) {
chomp;
#
# key1,value1
record = split /:\s*|Wm;
$record ={};
%{$record} = record;


n
# record

#
if ($record->{name} =" /["-.a-zA-ZO-9]/) {
warn "! ! ! ! ". $record->{name} .
, . .. \";
next;

172

5. /"
if ($record->{aliases} =" /r-.a-zA-ZO-9\s]/} {
warn " ! ! ! ! ".$record->{name} .
" , . . ".
next;

#
if (!$record->{address}) {
warn "!!!! ". $record->{name> .
" IP-, . . ";
next;


if (defined $addrs{$record->{address}}) {
warn "!!!! IP- :".$record->{name}.
" & ".$addrs{$record->{address}}. ", . . "
next;
}
else {
$addrs{$record->{address}} = $record->{name};
$entries{$record->{name}} = Srecord; ft

close(DATA);

#
print "#\n\# host file - GENERATED BY $0\n DO NOT EDIT BY HAND!\n#\n";
print "tt Converted by $user on ".scalar(localtime). "\n#\n";
tf
#
foreach my Sentry (keys %entries){
$depts{$entries{$entry}->{department}}++;
foreach my Sdept (keys %depts) {
print "ft number of hosts in the Sdept department; $depts{$dept}.\n"
print "ft total number of hosts: ".scalar(keys %entries)."\n\n\n";
tt ,
foreach my Sentry (keys %entries) {
print "tt Owned by ", $entries{$entry}->{owner), " (",
$entries{$entry}->{department},"): ",
$entries{$entry}->{building},"/",
Sentries{$entry}->{room},"\n";
print $entries{$entry}->{address}, "\t",
$entries{$entry}->{name}," ",
$entries{$entry}->{aliases},"\n\n";
}

173

-
.

, %record.

( ),
.
- ( , needspace 2
),
.
s e r i a l _ n u m b e r ,
, $ r e c o r d - > { s e r i a l _ n u m b e r } .
, Perl ,
, .
:
, . ,
.
, , .
( ),
-
%entries ,
. , %entries , - -,
, (IP-, . .).
, , IP-? , , :
foreach my Sentry (keys %entries) {
:

foreach my Sentry (sort byaddress keys %entries) {


:
sub byaddress {
@a = split(/\./,$entries{$a}->{address});
@b = split(/\./,$entries{$b}->{address});
($a[0]<=>$b[0]) ||
($a[2]<=>$b[2]) |
($a[3]<=>$b[3]) ;

174

5. TCP/ip
:
tt Owned by Cindy Coltrane (IT): west/143
192.168.1.3
bendir ben bendoodles
ft Owned by David Davis (software): main/909
192.168.1.11
shimmer shim shimmy shimmydoodles
8 Owned by Ellen Monk (design): main/1116
192.168.1.12
Sulawesi sula su-lee
# Owned by Alex Rollins (IT): main/1101
192.168.1.55
sander sandy micky mickydoo
, . Perl
.


IP- ,
, - .
. , , , .
.
- . :

,
,
.
,
. . , .
. ,
, , of
( !
IP-, ).
. ?
, , '

175

, , , , ,
, :

. ,
, , Perl , (
, Perl).


( ), . , .
RCS. RCS , Perl :
RCS . GNU
RCS 5.7 Unix-, Windows NT, MacOS . .
.
, .

. ( RCS).

RCS . , RCS, ,
. ,
$Date: $
RCS.
RCS . GNU- RCS
, ,
. RCS ftp://
ftp.gnu.org/gnu/rcs.
RCS,
. , RCS.
(Craig Freter) - Res, RCS Perl. :

5. TCP/ip

176
1. .
2. , RCS.

3. Res,
.
4. (
RCS).
Res , , , . , STDOUT, . . , . . . ,
:
$outputfile="hosts.$$"; ft
$target="hosts";
ft

open(OUTPUT,"> Soutputfile") or
die " $outputfile:$!\n";
print OUTPUT "\n\ft host file - GENERATED BY $0\n
ft DO NOT EDIT BY HAND!\nft\n";
print OUTPUT "ft Converted by Suser on ".scalar(localtime)."\ntf\n";
foreach my $dept (keys %depts) {
print OUTPUT "# number of hosts in the $dept department:
$depts{$dept}.\n";
}
print OUTPUT "8 total number of hosts: ".scalar(keys %entries). "\nft\n\n"
ft
#
foreach my Sentry (sort byaddress keys %entries) {
print OUTPUT
"ft Owned by ",$entries{$entry}->{owner}, " (",
$entries{$entry}->{department}, "): ",
Sentries! Sent ry}->{building},"/",
Sent ries{$entry}->{ room}, "\n";
print OUTPUT
$entries{$entry}->{address}, "\t",
$entries{$entry}->{name}, " ",
Sent ries{ Sent ry}->{aliases}, "\n\n";
close(OUTPUT);

use Res;
fl RCS
Rcs->bindir( '/usr/local/bin' );
ft RCS-

MIS, NIS+MWINS

177

my Srcsotrj = Rcs->new;
ft
$rcsobj->file($target);
RCS ( )
$rcsobj->co('-!');

rename($outputfile,$target) or
die " $outputfile $target:$!\n";
# RCS
$rcsobj->ci("-u","-m"."Converted by $user on ".scalar(localtime));
,
.
rlog hosts, , :
revision 1.5
date: 1998/05/19 23:34:16; author: dnb; state: Exp; lines: +1 -1
Converted by David N. Blank-Edelman (dnb) on Tue May 19 19:34:16 1998
revision 1.4
date: 1998/05/19 23:34:05; author: eviltwin; state: Exp; lines: +1 -1
Converted by Divad Knalb-Namlede (eviltwin) on Tue May 19 19:34:05 1998
revision 1.3
date: 1998/05/19 23:33:35; author: dnb; state: Exp; lines: +20 -0
Converted by David N. Blank-Edelnan (dnb) on Tue May 19 19:33:16 1998
, ( , lines:), , .
, , rcsdiff. , , -
.
NlSf NIS+MWINS
Sun Microsystems, ,
, (Yellow Pages YP). YP ,
/etc/hosts, /etc/passwd, /etc/services . .
IP-.

178

5. /|
YP (Network
Information Service NIS) 1990 ., British Telecojji
( ) Yell ow
Pages . -
Unix-,
NIS ypcat, ypmatch, yppush . .
Unix NIS. NT
NIS , 1, NIS-
NT . NIS MacOS.
NIS , .
(master), -
(slave). ( /etc/hosts /etc/passwd),
. .
,
IP- , ,
. , . NIS-. - , Unix DBM .
( makedbm
) Makefile,
/var/yp. NIS- , , NIS-.
NIS . ,
oog.org ,
.
NIS- . NIS- . NIS ,
( ,
) ( ).
, , , Perl , NIS. ^'
1

- NISGINA, '
(Nigel Williams); http://
www.dcs.qmw.ac.uk/~williams/. , , .

179

IS, NIS+nWINS

NIS. , , ,
. , , NIS, (, push mechanisms), , make /var/yp.
Makefile /var/yp
NIS- .
NIS- Makefile.
NTS-.
, , /etc/passwd

, .
- NIS, NIS. Net : : NIS (Rik Harris). , 1995 ,
-, , , .1
,
, Net : : NIS. NIS peat:
use Net: :NIS;
NIS-
Sdomain = Net: :NIS: :yp_get_default_domain();
8
(Sstatus, $info) = Net: :NIS: :yp_all($domain, "hosts. byname");
foreach my $name (sort keys %{$info}){
print "$name => $info->{$name}\n";


. ,
N e t : :NIS: :yp_all() . (, ) , . , .
2.
, $Net: : NIS: : ERR_KEY $Net: : NIS: : ERR_MAP.
, .
, , , .

180

5. TCP/IP
IP- ,
:
use Net::NIS;
$hostname = "olaf.oog.org";
$domain = Net::NIS::yp_get_default_domain();
($status,$info) = Net::NIS::yp_match($domain,"hosts.byname",Shostname);
print $info,"\n";
Net: :NIS: : y p _ m a t c h ( ) (), .
Net: :NIS , .
, :
@hosts='<nyrb K>/ypcat hosts'
:

open(YPCAT, "< /<>/ypcat hosts|");


while (<YPCAT>){...}
, .
,
NIS-
yppoll. - , :
use Net::NIS;
Syppollex = "/usr/etc/yp/yppoll"; # yppoll
Sdomain = Net::NIS::yp_get_default_domain();
($status,$info) = Net::NIS::yp_all($domain,"ypservers");
foreach my $name (sort keys %{$info}) {
Sanswer = '$yppollex -h $name hosts.byname';
if (Sanswer /has order number/) {
warn "$name !\";

NIS+
Solaris NIS+ - NIS. NIS+ , NIS, , . (
, . . NIS+

|S, N15+ WINS

181

), NIS+ Unix, NIS.


,
Sun. NIS+
Linux, (Thorsten
Kukuk) (http://www.suse.de/~kukuk/nisplus/index.html),
Unix NT MacOS.
, NIS+ , . NIS+ Perl, Net::NISPlus.
Windows- (WINS)
Microsoft
NetBIOS TCP/IP (NetBT),
IP- . Imhosts, .
NIS- . NT 3.5
Windows- (Windows Internet Name Service, WINS). WINS NIS:
WINS IP-. NIS, (, , ).

WINS- ( ). IP- , (Dynamic Host Configuration Protocol, DHCP) WINS-


. NIS, , , .

WINS, NIS, ,
, -.
Windows 2000 WINS ( ), (Dynamic Domain Name Service),
DNS-, .
, WINS ,
. WINS Perl .
, WINS.
,

1
182

5. /ip

Windows NT Server Resource Kit, WINSCHK


WINSCL.
(DNS)

, NIS WINS ,
,
.

, .1
,
, . , WINS -
. WINS- WINS- .

,
. NIS, , . ,
, NIS-,
.
.
.
,
NIS/NIS+/WINS-noflo6HbiM ,
(DNS). DNS
.
. .
,
, .
.
, , , . , , , .
. DNS-cep'
NIS+ , , DNS.

(DNS)

183

( ),
.
DNS- ,
,
, -
( ), ,
DNS-.
,
, ,
. DNS
, NIS WINS, DNS. , NIS- SunOS ,
DNS-,
, . NIS-, - . DNS- Microsoft :
DNS- Microsoft , , DNS- ,
WINS- .
DNS
DNS
,
NIS:

(
, , ,
).

,
.

RGS ( )
.

DNS ,
. , 1
(Paul Albitz) (Cricket Liu) DNS and BIND
(DNS BIND, O'Reilly), , , , .
, DNS BIND ( 4- 2001.),
IV ., -, 2001 . - ..

184

5. /|

DNS , ,
. - .
SOA (Start of Authority). SOA :
, DNS-cep.
DNS- .
()
DNS-.
(
).
- (refresh) (retry) (. . ,
).

(TTL) (. .
).

:
@ IN SOA

dns.oog.org. hostmaster.oog.org. (
1998052900 ; serial
10800 ; refresh
3600
; retry
604800 ; expire
43200) ; TTL
IN NS dns.oog.org.


. , , - . X (X ) , , .
DNS- ( BIND v8+ Microsoft DNS) , , .

SOA. SOA 6
, ,
( '
). , 11
.
.

(DNS)

185

, :
1.
.
2. , , ( , ,
RCS).
,

DNS. , (YYYYMMDDXX,
Y=rofl, =, = = ,
):
YYYYMMDD
@localtine = localtime;
Stoday = sprintf("%04d%02d%02d",$localtime[5]+1900,
$localtime[4]+1,
$localtime[3]);
# NT/2000, Unix
$user = ($'0 eq "MSWin32")? $ENV{USERNAME} :
(getpwuid($<))[6]." (". (getpwuid($<))[0]. ")";
sub GenerateHeader{
my($header);
8 , ,
# ,
if (open (OLDZONE,$target)){
while (<OLDZONE>) {
next unless (/(\d{8}).*serial/);
Soldserial = $1;
last;
}
close (OLDZONE); .
}
else {
Soldserial = "00000000";
#
# , 2 ,
#
Solddate = substr($oldserial,0,8);
Scount = ((Solddate == Stoday) ? substr($oldserial, 8, 2)+1 : 0);
Sserial = sprintf("%8d%02d", Stoday, $count);

186

5. TCP/ip


$header .= "; dns - $0\";
Sheader .= "; !\;\";
$header .= "; $user
".scalar((localtime))."\n;\n";
tf
foreach my Sentry (keys %entries){
$depts{$entries{$entry}->{department}}++;
}
foreach my $dept (keys %depts) {
Sheader .= "; $dept:
$depts{$dept}.\n";
}
$header .= "; : ".scalar(keys %entries)."\nl\n\n";
Sheader .= "EOH";
@ IN SOA

dns.oog.org, hostmaster.oog.org. (
Sserial ; serial
10800 ; refresh
3600
; retry
604800 ; expire
43200) ; TTL

IN NS dns.oog.org.

EOH
return $header;
}

. . , . , , 00. ,
, .


, .
DNS- ( IP-), (IP- )
( ), .
. *
.

(DNS)

187

,
, .

1
DNS .
, ,
. , DNS. ,
.
(. .
) .
, , :
1. , .
2. .
3. (
IP-) RCS.
4. ( IP- ) RCS.
:
use Res;

Sdatafile
Soutputfile
Starget
$revtarget
Sdefzone
$recordsep

=
=
=
=
=
=

"./database"; ft
"zone.$$"; ft
"zone.db"; ff
"rev.db"; ft
".oog.org"; ft
"-=-\n";

ft YYYYMMDD
@localtime = localtime;
Stoday = sprintf("%04d%02d%02d",$localtime[5]+1900,
$localtime[4]+1,
$localtime[3]);
, NT/2000, Unix
$user = ($-0 eq "MSWin32")? $ENV{USERNAME} :
(getpwuid($<))[6]." (".(getpwuid($<))[0].")";
$/ = Srecordsep;
ft
open(DATA,Sdatafile) or die "! datafile:$!\n";
,
. - . . .

188

5. TCP/ip

while (<DATA>) {
chomp; n
# key1,value1
@record = split /:\s*|\n/m;
$ record ={};
%{$record} = record;


# record

#
if ($record->{name} =~ /["-.a-zA-ZO-9]/) {
warn "!!!! ",$record->{name} .
" , . . "
next;
#
if ($record->{aliases} =" /[~-.a-zA-ZO-9\s]/) {
warn "!!!! " . $record->{name} .
, . . "
next;
#
unless ($record->{address}) {
warn "!!!! " . $record->{name} .
" IP-, . . ";
next;
#
if (defined $addrs{$record->{address}}) {
warn "!!!! IP-:" . $record->{name}.
" & " . $addrs{$record->{address}} . ", . . "
next;
}
else {
$addrs{$record->{address}} = $record->{name};
$entries{$record->{name}} = $record; #
close(DATA);
'$header = &GenerateHeader;

open(OUTPUT,"> $outputfile") or
die "! $outputfile:$!\n";
print OUTPUT $header;

^ (DNS)

189

foreach my Sentry (sort byaddress keys %entries) {


print OUTPUT
"; -- ",$entries{$_}->{owner}, " (",
$entries{$entry}->{department}, ") : ",
Sent ries{$entry}->{ building}, "/",
Sent ries { Sent ry}->{ room}, "\n";
ft
printf OUTPUT "%-20s\tIN A
%s\n",
Sent ries{ Sent ry}->{ name}, Sent ries{ Sent ry}->{address};
ft CNAMES ()
if (defined $entries{$entry}->{aliases}){
foreach my Salias (splitC ' ,$entries{$entry}->{aliases})) {
printf OUTPUT "%-20s\tIN CNAME %s\n", $alias,
Sent ries { Sent ry}->{ name};
print OUTPUT "\n";
close(OUTPUT);
Rcs->bindir( '/usr/local/bin' );
my Srcsobj = Rcs->new;
$rcsobj->file($target);
$rcsobj->co( '-!');
rename($outputfile, Starget) or
die "! Soutputfile $target:$!\n"
$rcsob]->ci("-u", "-m". " Suser
".scalar(localtime));
ft
open(OUTPUT,"> Soutputfile") or
die "! $outputfile:$!\n";
print OUTPUT $header;
foreach my Sentry (sort byaddress keys %entries) !
print OUTPUT
"; -- ", $entries{$entry}->{owner}, " (",
$entries{$entry}->{department}, ") : ",
Sent ries{ Sent ry}->{building}, "/",
$entries{$entry}->{room}, "\n";
printf OUTPUT "%-3d\tIN PTR %s$defzone. \n\rT,
(split/\./,$entries{$entry}->{address})[3],
Sent r ies { Sent ry}->{ name};

close(OUTPUT);

190

5. /ip
$rcsobj->file($revtarget);
$rcsobj->co('-!'); it ,
#
rename($outputfile,$revtarget) or
die "! Soutputfile $revtarget:$!\n";
$rcsobj->ci("-u","-m"." $user
".scalar(localtime));
sub GenerateHeader{
my($header);
if (open(OLDZONE,$target)){
while (<OLDZONE>) {
next unless (/(\d{8}).serial/);
Soldserial = $1;
last;
}
close(OLDZONE);
}
else {
Soldserial = "000000";
Solddate = substr($oldserial,0,6);
Scount = (Solddate == Stoday) ? substr($oldserial,6,2)+1 : 0;
Sserial = sprintf("%6d%02d",Stoday,Scount);
Sheader .= "; dns - $0\";
Sheader .= "; HE !\;\";
Sheader .= "; Suser
".scalar(localtime)."\n;\n";
ff
foreach Sentry (keys %entries){
Sdepts{$entries{$entryJ->{department}}++;
foreach Sdept (keys %depts) {
Sheader .= "; Sdept $depts{$dept} .\n";
Sheader .= "; : ".scalar(keys %entries)."\n#\n\n";
Sheader .= "EOH";
@ IN SOA dns.oog.org. hostmaster.oog.org. (
Sserial
serial
10800
refresh
retry
3600
604800
expire
TTL
43200)
IN NS dns.oog.org.

(DNS)

191

return Sheader;
sub byaddress {
@a = split(/\V,$entries{$a}->{address});
@b = split(/\./,$entries{$b}->{address});
($a[0]<=>$b[OJ) ||
($a[2]<=>$b[2]) ||
($a[3]<=>$b[3]);
():
dns - createdns
!
David
Fri May 29 15:46:46 1998

Blank-Edelman (dnb);

design 1 .
software 1 ,
IT 2 ,
: 4
IN SOA

dns.oog.org. hostmaster.oog.org. (
1998052900 serial
refresh
10600
retry
3600
expire
604800
TTL
43200)
IN NS dns.oog.org.

; -- Cindy Coltrane (marketing): west/143


bendir
IN A
192.168.1.3
ben
IN CNAME bendir
bendoodles
IN CNAME bendir
; -- David Davis (software): main/909
shimmer
IN A
192.168.1.11
shim
IN CNAME shimmer
shimmy
IN CNAME shimmer
shimmydoodles
IN CNAME shimmer
; -- Ellen Monk (design): main/1116
Sulawesi
IN A
192.168.1.12

5. TCP/IP

192
sula
su-lee

IN CNAME Sulawesi
IN CNAME Sulawesi

; -- Alex Rollins (IT): main/1101


sander
IN A
192.168.1.55
sandy
IN CNAME sander
micky
IN CNAME sander
mickydoo
IN CNAME sander
(rev.db):
dns - createdns
!
David N. Blank-Edelman (dnb);
Fri May 29 15:46:46 1998
design 1 ,
software 1 ,
IT 2 ,
: 4
IN SOA

dns.oog.org. hostmaster.oog.org. (
1998052900 serial
refresh
10800
retry
3600
expire
604800
TTL
43200)
IN NS dns.oog.org.

; -- Cindy Coltrane (marketing): west/143


3 IN PTR
bendir.oog.org.
; -- David Davis (software): main/909
11 IN PTR
shimmer.oog.org,
; -- Ellen Monk (design): main/1116
12 IN PTR
sulawesi.oog.org.
; -- Alex Rollins (IT): main/1101
55 IN PTR
sander.oog.org.
. , .
, , '
. ,
.

(DNS)

193

, . , DNS , MX (Mail exchange),


, .
:

printf OUTPUT "%-20s\tIN A
%s\n",
Sentries{$entry}->{name},Sentries{$entry}->{address};
:
ft
printf OUTPUT "%-20s\tIN A
%s\n",
Sentries{Sentry}->{name},Sentries{Sentry}->{address};
# MX
print OUTPUT "

IN MX 10 $mailserver\n";

, , , $mailserver.
, , (
), Perl.
DNS:

, ,
. , , .
, / DNS- ?. , ,
, ?, , ,
? ?. .
2 , Perl . Perl . -
, ( ), .
Perl
, -

194

5. /|

. , ,
.
DNS. ,
, , ,
. , Perl; . , N e t : : DNS,
, . , Net: : DNS , .
, .
: Perl,
DNS-, ,
. , , IP-
(. . IP-).
,
, :
Shostname = $ARGV[0];
servers = qw(nameserver1 nameserver2 naineserverS); #
foreach Sserver (^servers) {
&lookupaddress($hostname,$server);
ft
%results
>
%inv = reverse %results;
ft

if (keys %inv > 1) {
print " DNS- :\";
use Data:: Dumper;
print Data::Dumper->Dump([\%results],["results"]),"\n";
}
DNS-, servers, &lookupaddress(), DNS, IP- ,
%results. DNS- %result
, IP-,
( ).
,
%results (. . , DNS-
). %results
-, . %results ,
. , ,
, Data: :Dumper->Dump()

(DNS)

195

%results, .
, -
:
DNS- :
Sresults = {
nameserverl => '192.168.1.2',
nameserver2 => '192.168.1.5',
nameserverS => '192.168.1.2',
&lookupaddress().
nslookup

Unix
Perl,
.
, Perl , :
use Data::Dumper;
Shostname = $ARGV[0];
$nslookup = "/usr/local/bin/nslookup";
# nslookup
servers = qw(nameserver1 nameserver2 nameserverS); #
foreach Sserver (servers) {
&lookupaddress($hostname,$server);
# %results
%inv = reverse %results;
#
if (scalar(keys %inv) > 1) {
print " DNS- :\";
print Data::Dumper->Dump([\%results],["results"]),"\n";
, IP-
,
. %results
sub lookupaddress {
my($hostname,Sserver) = @_;
open(NSLOOK,"$nslookup $hostname Sserver|") or
die " nslookup:$!\n";
while (<NSLOOK>) {
it , "Name:
next until (/"Name:/);
- Address:
chonp($results{$server} = <NSLOOK>);
ti

196

5. /|
die " nslookup \n" unless /Address/;
$results{$server} =" s/Address(es)?:\s+//;
# , nslookup
last;
}
close(NSLOOK);
}

:
, (, ).

Unix,

, ,
.
,
Perl; , , - .
:
. ? ,
?
. ,
, . ,
nslookup, , .
, , ,
.
.
. ,
nslookup ( , , nslookup) - ,
.

, "
, . '
DNS, , Perl.
, , '

(DNS)

197

, .
, , .
,
( (Michael Fuhr), ). . DNS , DNS-, .1
DNS- ( , )
:
Header()
,
( ).
Question ()
(
).
Answer ()
DNS- ( DNS-).
Authority ()
, .
Additional ()
, .
.
DNS-na pack(). 10: : Socket,
. ( unpack()).
.
, . RFC1035 ( 4.1.4) DNS-: .
( host.oog.org) .
1


RFC1035.

198

5. /|
.
, , , BO
, .
( ) . hostl , host2 host3 longsubdomain.longsubdomain.oog.org
longsubdomain.longsubdomain.oog.org. , &decompress.
:
use 10: -.Socket;
Shostname = $ARGV[0];
Sdefdomain = ".oog.org"; #

>- :

servers = qw(nameserver1 nameserver2 nameserverS); *


foreach Sserver (servers) {
&lookupaddress($hostname, Sserver);
#
%results
}

%inv = reverse %results;


ft
-
if (scalar(keys %inv) > 1) { # ,
print " ONS- :\";
use Data: : Dumper;
print Data: :Dumper->Dump([\%results], ["results"]), "\n";
sub lookupaddress{
my($hostname, Sserver) = @_;
my($qname,$rname,$header,$question,$lformat,@labels,$count);
local($position,$buf);

$header = pack("n C2 n4",


++$id, #
1, qr, opcode, aa, tc, rd ( rd)
0,

1,
,
,
0);

# rd, ra

#
tt
#
# rr addtl

(qdcount)
(ancount)
ns authority (nscount)
(arcount)

# ,
#
if (index($hostname, ' . ' ) == -1) {
$hostname .= $def domain;

(DNS)

qname ( )
for (split(/\./,$hostname)) {
Slformat .= " * ";

$labels[$count++]=length;
$labels[$count++]=$_;

888
flftft
Squestion = pack($lformat. " 2",
labels,
0, it
1, 8 qtype A
1); 8 qclass IN

##

$sock = new 10: : Socket : :INET(PeerAddr => Sserver,


PeerPort => "domain",
Proto => "udp");
$sock->send($header.$question);
8 UDP,
$sock->recv($buf,512);

close($sock);
8 ,
( Sposition)
Srespsize = length($buf);

ttttn

nn#
888

($id,
$q r_opcode_aa_tc_rd ,
$rd_ra,
Sqdcount,
Sancount,
Snscount,
Sarcount) = unpack("n C2 n4",$buf);
if (!$ancount) {

warn " $hostname $server!\n"


return;

ft
nntt

199


200

5. /|

12
($position,$qname) = &decompress(12);
($qtype,$qclass)=unpack( '@' .$position. 'n2' ,$buf );

Sposition += 4;

ttnn

###

for ( ;$ancount;$ancount--){
(Sposition, Srname) = &decompress($position);
(Srtype, $rclass, $rttl, $rdlength)=
unpack( '@' ,$position. 'n2 N n',$buf);
Sposition +=10;
#
# ;
#
$results{$server}=
join( ' . ' , unpack( '@' . Sposition. '' . $rdlength, $buf ));
Sposition +=$rdlength;

# , "" RFC1035
#
# (
# ) ,
#
sub decompress {
my($start) = $_[0];
my($domain,$i,$lenoct);
for ($i=$start;$i<=$respsize; ) {
$lenoct=unpack('<g>' ,$i. 'C', $buf); #
if (!$lenoct){
$i++;
last;

# 0 ,

if ($lenoct == 192) { ,
# ,
$domain.=(&decompress((unpack('@' .$i. 'n',$buf) &
$i+=2;
last
}
else {

$domain.=unpack( '@' . ++$i. 'a' .Slenoct, $buf ). ' . ' ;
$i += Slenoct;

6 (DNS)

201

return($i, Sdomain);
,
,
nslookup (-,
). , , .
:
- .
.
, , ,
.

(- ).

, :

, , .
,
(. . , , , DNS-,
nslookup ).
, ,
( ,
).
Net::DNS
1, Perl ,
, . Perl , , , , - .
Net: :DNS (Michael Fuhr), . ,
, DNS-, , , ,
:
use Net: :DNS;

^servers = qw(nameserver1 nameserver2 nameserverS); #


foreach Sserver (^servers) {

202

5. /|
&lookupaddress($hostname,$server);

%results
>
%inv = reverse %results;
(t
if (scalar(keys %inv) > 1) { n ,
print " DNS- ";
use Data: : Dumper;
print Data: :Dumper->Dump([\%results], ["results"]), "\n";
fl Net::DNS
sub lookupaddressi
my($hostname, $server) = @_;
$res = new Net: :DNS: :Resolver;
$res->nameservers($server);
Spacket = $res->query($hostname);
if (!$packet) {
warn " $hostname $server!\n";
return;
}
RR
foreach $rr ($packet->answer) {
$results{$server}=$rr->address;

, .

.
, ( Perl
C++), ,
.
, -
, . ,
, .
,
, - , . , !
, .
. .

203

:
. ,
. ,
.

. , .
- , , !

Res
Net::NIS
Data : : Dumper ( Perl)

10 : : Socket ( Perl)
N e t : : DNS

CPAN
CFRETER

RIK

GSAR
GBARR
MFUHR

2.101

0.09

1.20
0.12


DNS and BIND, 3rd Edition, Paul Albitz, Cricket Liu (O'Reilly, 1998).
RFC849: Suggestions For Improved Host Table Distribution, Mark
Crispin, 1983.
RFC881: The Domain Names Plan and Schedule, J. Postel, 1983.
RFC882: Domain Names: Concepts And Facilities, P. Mockapetris,
1983.
RFC 1035: Domain Names: Implementation And Specification, P. Mockapetris, 1987.

?
Finger:
WHOIS
LDAP:
ADSI (
)

, , .
,
. , . ,
,
. .
, Perl
, Finger, WHOIS, LDAP ADSI.
?
7 SQL ,
. -
. ,
* :

. , , '
( /etc/passwd),
.

205

/
. - SQL,
7 D SQL. .
.

, .
,
.
/ /.
, ,
, , ,
. ,
, .
Finger:
Finger WHOIS - . Finger, , (,
). Finger,
GNU Finger ,
,
.
Finger .
-

finger. finger
harry@hogwarts.edu ,
h a r r y , hpotter - (,
).
finger , , . . .

206

6.
Finger Perl -
TMTOWTDI. CPAN -
Finger, . - N e t : : Finge r
(Dennis Taylor),
. , , ,
, ,
.
Finger - TCP/IP.
RFC1288,
TCP- 79. , CRLF.i
, , .
. , , Finger telnet:
$ telnet kantine.diku.dk 79
Trying 192.38.109.142 ...
Connected to kantine.diku.dk.
Escape character is '"]'.
cola<CR><LF>
Login: cola
Directory: /home/cola
Never logged in.
No mail.
Plan:

Name: RHS Linux User


Shell: /bin/noshell

Current state of the coke machine at DIKU


This file is updated every 5 seconds
At the moment, it's necessary to use correct change.
This has been the case the last 19 hours and 17 minutes
Column 1 is currently *empty*.
It's been 14 hours and 59 minutes since it became empty.
31 items were sold from this column before it became empty.
Column 2 contains some cokes.
It's been 2 days, 17 hours, and 43 minutes since it was filled.
Meanwhile, 30 items have been sold from this column.
Column 3 contains some cokes.
It's been 2 days, 17 hours, and 41 minutes since it was filled.
Meanwhile, 11 items have been sold from this column.
Column 4 contains some cokes.
It's been 5 days, 15 hours, and 28 minutes since it was filled.
1

+ , . . ASCII- 13 !0.

finger:
Meanwhile, 26 items have been sold
Column 5 contains some cokes.
It's been 5 days, 15 hours, and 29
Meanwhile, 18 items have been sold
Column 6 contains some coke-lights.
It's been 5 days, 15 hours, and 30
Meanwhile, 16 items have been sold

207
from this column.
minutes since it was filled.
from this column.
minutes since it was filled.
from this column.

Connection closed by foreign host.

$
Finger, cola, .
, ,
. Finger
.
, , . , Finger, (Bennet Yee)
Internet Accessible Coke Machines Internet Accessible Machines
n&http://www.cs.ucsd.edu/~bsy/fun.html.
, telnet,
Perl. Perl .
, N e t : : Telnet (Jay Roger) , .
(
) Comm.pl (Eric Arnold), Expect. (Austin Schutz) , chat2.pl . (Randal
L. Schwartz).
N e t : : T e l n e t .
, Net::Telnet
,
, .
Net: : Telnet- Finger-. user@finger_server.
,
. ,
:
use Net::Telnet;
($username,$host) = split(/\@/,$ARGV[0]);


208

6.
$host = $host ? $host : 'localhost';
#
$cn = new Net: : Telnet ( Host => $host,
Port => 'finger');
#
unless ($cn->print("$username")){ # "/W $username"
$cn->close;
die " : ". $cn->errmg. "\n";
# ,
while (defined ($ret = $cn->get)1) {
$data .= $ret;
#
$cn->close;
tt
print $data;
RFC1288 , , , /W , .
, Finger
TCP, . , Daytime (
) :
use Net: :Telnet;
$host = $ARGV[0] ? $ARGV[0] : ' localhost';
$cn = new Net: :Telnet(Host => Shost,
Port => 'daytime' );
while (defined ($ret = $cn->get)2) {
$data .= $ret;
}
$cn->close;
Perl 5.6.I.
. - . ..
Perl 5.6.I.
. - . . .

WHOIS

209

print $data;
, TCP. - , , . Finger N e t . : Finger :
use Net: -.Finger;
finger() user@host
print finger($ARGV[OJ);
,
( ):
($username,$host) = split('@',$ARGV[0]);
$host = $host ? $host : 'localhost';
# finger executable, MacOS

Sfingerex = ($"0 eq "MSWin32") ?
$ENV{'SYSTEMROOT'}."\\System32\\finger" :
"/usr/ucb/finger"; # ( /usr/bin/finger)
print 'Sfingerex ${username}\@${host}'
Finger-. , , , . .
. N e t : : F i n g e r Finger-; N e t : : Telnet
.
WHOIS
WHOIS - ,
. WHOIS , , .
, IBM, UC Berkeley MIT,
WHOIS, WHOIS-
InterNIC , , RIPE ( IP-) APNIC (Asia/Pacific, /
).
, ,
WHOIS .

210

WHOIS- GUI-, 11.


, . Unix :
% whois -h whois.networksolutions.com brandeis.edu
<large legal paragraph omitted>
Registrant:
Brandeis University (BRANDEIS-DOM)
Information Technology Services
Waltham, MA 02454-9110
US
Domain Name: BRANDEIS.EDU
Administrative Contact:
Koskovich, Bob (BK138) user@BRANDEIS.EDU
+1-781-555-1212 (FAX) +1-781-555-1212
Technical Contact, Zone Contact:
Hostmaster, Brandeis (RCG51) hostmaster@BRANDEIS.EDU
+1-781-555-1212 (FAX) +1-781-555-1212
Billing Contact:
Koskovich, Bob (BK138) user@BRANDEIS.EDU
+1-781-555-1212 (FAX) +1-781-555-1212
Record last updated on 13-0ct-1999.
Record created on 27-May-1987.
Database last updated on 19-Dec-1999 17:42:19 EST.
Domain servers in listed order:
LILITH.UNET.BRANDEIS.EDU
FRASIER.UNET.BRANDEIS.EDU
DIAMOND.CS.BRANDEIS.EDU
DNSAUTH1.SYS.GTEI.NET
DNSAUTH2.SYS.GTEI.NET

129.64.99.12
129.64.99.11
129.64.2.3
4.2.49.2
4.2.49.3

IP-, WHOIS:
% whois -h whois.arin.net 129.64.2
Brandeis University (NET-BRANDEIS)
415 South Street
Waltham, MA 02254
Netname: BRANDEIS
Netnumber: 129.64.0.0
Coordinator:
Koskovich, Bob (BK138-ARIN)
617-555-1212

user@BRANDEIS.EDU

WHOIS

211

Domain System inverse mapping provided by:


BINAH.CC.BRANDEIS.EDU
NIC.NEAR.NET
NOC.CERF.NET

129.64.1,3
192.52.71.4
192.153.156.22

Record last updated on 10-Jul-97.


Database last updated on 9-Oct-98 16:10:44 EOT.
The ARIN Registration Services Host contains ONLY Internet
Network Information: Networks, ASN's, and related POC's.
Please use the whois server at rs.internic.net for DOMAIN related
Information and nic.mil for NIPRNET Information.
WHOIS- Unix, . Windows NT MacOS
, , .
, Net: : Whois Perl ( Net: : Whois (Chip Salzenberg),
(Dana Hudes)).
- , :
use Net::Whois;
# ,
my $w = new Net::Whois::Domain $ARGV[0] or
die " Whois\n";
die " $ARGV[0] \ " unless ($w->ok);

print ": ", $w->domain, "\n";
print ": ", $w->name, "\n";
print ": ", $w->tag, "\n";
print ":\n", map { " $_\ } $w->address;
print ": ", $w->country, "\n";
print " : ".$w->record_created."\n";
print " : ".$w->record_updated."\n";
# ($w->servers returns a list of lists)
print " ", map { " $$_[0] ($$_[1])\n" } @{$w->servers};
# ($w->contacts returns a hash of lists)
my($c,$t);
if ($c = $w->contacts) {
print "Contacts:\n";
for $t (sort keys %$c) {
print " $t:\n";

212

.
print map { "\t$_\n" } @{$$c{$t}};

WHOIS InterNIC/Network Solutions - . Net::Wh 0 .


is : : Domain. ,
WHOIS-, .
WHOIS 8
, .
, Finger WHOIS.
Finger WHOIS - .
Finger . , . WHOIS-cep InterNIC/Network Solutions
. , ,
, Name, Address Domain. Net : :Whois
, . (Vipul Ved Prakash) Net: :Xwhois, ,
, -
WHOIS-.
WHOIS , .
, ,
.
LDAP:
LDAP (Lightweight Directory Access Protocol,
) ADSI
.
LDAP ( 2 3; ).
. LDAP, . . .
:
NIS-K-LDAP

Finger-K-LDAP
( , )

213

( )
, LDAP , Microsoft (Microsoft Active Directory), ADSI ( ).
, LDAP , . LDAP-
;
SQL, SQL.
Perl LDAP. , LDAP .
LDAP
LDAP , .
,
LDAP, - ,
.500. LDAP .500, , , . - , LDAP Perl.
LDAP Perl

Perl, LDAP
. LDAP ,
. , -, LDAP, . ,
: (Graham Barr)
Net: : LDAP, (Leif Hedstrom)
(Clayton Donley) Mozilla: :LDAP (
PerLDAP).
(. 6.1).
6.1. j ^DAP-

Net::LDAP Mozilla::LDAP (PerLDAP)


Perl Mozilla/Netscape LDAP C-SDK ( ). SDK Unix, NT MacOS

SSL-

- API

214

6.
, , .
, . ., , .
, , .
,
10 .
LDAP-. use modulename
, .
Netscape 4.0 Directory Server OpenLDAP ( http://www.netscape.com http:// www.openldap.org).
,
Perl.

LDAP-
- , ,
- LDAP-. LDAP (binding to the server). B LDAPv2 , LDAPvS .
LDAP-
(Distinguished name, DN), (bind DN) .
. ( ) . LDAP , LDAP-
. (root Distinguished Name), (Relative Distinguished Name) , . ,
root Unix Administrator
NT/2000. manager DN.

(, DN- ) ,
(anonymous authentication). #
.

i :

215

LDAPvS :
SASL.
. SASL (Simple Authentication and Security
Layer, ) - , RFC2222, / , Kerberos .
,
. , , , .
(,
TLS), .
LDAP SASL . LDAP
SSL (Secure Socket Layer, ). LDAP , HTTPS. LDAP-

(trusted client's certificate). Perl- PerLDAP LDAPS ( SSL-). ,
,
.

Perl:
use Mozilla::LDAP::Conn;
Sbinddn Spasswd
$ = new Mozilla::LDAP::Conn($server, Sport, Sbinddn, Spasswd);
die " Sserver" unless $c;
$c->close();

:
use Net::LDAP;
$c = Net::LDAP->new($server, port => Sport) or
die " Sserver: $@\n";
ft bind()
$c->bind($binddn, password => Spasswd) or
die " : $@\";
$c->unbind();

216

6.
M o z i l l a : : LDAP:: Conn . Net: : LDAP . Mozilla: : LDAp
(ldap_init()) - M o z i l l a : : L D A P : : A P I .

,
Perl: ,
: +, (), , , ' ,
> , < ; ,
, (\). ,
. .
, .

LDAP
D LDAP Directory (. . ), .
LDAP , . LDAP :

(base DN) (search base). DN-
DN- ,
.

(scope) . : base ( DN-),
one ( , DN, DN-) sub ( DN- , ).

(search filter).
.

,
,
. , , "

217

, . ,
, ,
, .
Perl (
):
use Mozilla::LDAP::Conn;
Sentry = $c->search($basedn, $scope, $fliter);
die " : ". $c->getErrorString()."\n" if $c->getErrorCode();

:
use Net::LOAP;
$searchobj = $c->search(base => Sbasedn, scope => $scope,
filter => $filter);
die " , #".$searchobj->code() if Ssearchobj>code();
,
$f liter. :
ottribute name> Comparison operator> ottribute value>
<comparison operator> RFC2254 , . 6.2.
6.2. LDAP

. , Ottribute value> * ( en=Tim *).
, <attribute name>, , .
<attribute value> *, (, =* , ).
.
.
.
Perl, . , Perl, ~= =*.
; .
. , soundex -

218

6.
,
( ), .!
, Perl, - =. ( , ), = *
,
. , =* , (common name) . =**
, , , .

ottribute name>, Comparison operator>, ottribute value>
, .
:
(<boolean operator^ (<simple1>) (<simple2>) (<simple3>) . . . )

, LISP, ;
, , , . , , (&()()). , , (|()()()). : ,
: ( & ( ) ( ! ) ) . ,
. , :
(&(sn=Finkelstein)(l=Boston))
, , :
(|(sn=Finkelstein)(sn=Hinds))
, :
(&(sn=Finkelstein)(!(l=Boston)))

,
:
(&(|(sn=Finkelstein)(sn=Hinds))(!l=Boston))
1

, soundex, (Mark Mielke) Text: . Soundex.

1_:

219

, LDAP-
:
use Mozilla::LDAP::Conn;
Sserver
Sport
Sbasedn
$scope

=
=
=
=

$ARGV[0];
getservbyname("ldap","tcp") || "389";
"c=US";
"sub";

$c = new Mozilla::LDAP::Conn($server, $port, "","");


die " $server\n" unless $c;
Sentry = $c->search($basedn, $scope, $ARGV[1]);
die " : ". $c->getErrorString()."\n" if $c->getErrorCode();
search()
while (Sentry) {
$entry->printl_DIF();
Sentry = $c->nextEntry();
>
$c->close();
use Net::LOAP;
use Net::LDAP::LDIF;
Sserver
Sport
Sbasedn
Sscope

=
=
=
=

$ARGV[0];
getservbyname("ldap", "tcp") || "389";
"c=US";
"sub";

$c = new Net::LDAP($server, port=>$port) or


die " Sserver: $@\n";
$c->bind() or die "Unable to bind: $@\n"; #
Ssearchobj = $c->search(base => Sbasedn, scope => Sscope,
filter => $ARGV[1]);
die " , ft".$searchobj->code() if Ssearchobj>code();
search()
if (Ssearchobj){
Sldif = new Net::LDAP::LDIF("-");
$ldif->write(Ssearchobj->entries());
$ldif->done();
}

:
$ Idapsrch ldap.bigfoot.com '(sn=Pooh)'

220

6.

dn: cn="bear pooh",mail=poohbear219@hotmail.com,c=US,o=hotmail.com


mail: poohbear219@hotmail.com

en: bear pooh


o: hotmail.com
givenname: bear
surname: pooh
, , , search(). ,
. LDIF (LDAP Data Interchange Format, LDAP), , .
M o z i l l a : : LDAP
, API RFC1823.
, .
.
p r i n t L D I F ( ) .
N e t : : LDAP RFC2251. LDAP . e n t r i e s ( ) .

N e t : : L D A P : :LDIF. ,
printLDIF() , write(), .
.
, ,
. Mozilla: : LDAP , search ():
use Mozilla::LDAP:-.Conn;
Sentry = $c->search($basedn,$scope,$ARGV[1],0,@attr);
- , , - (0), . .
.
'
. Perl , "
,
):

:
Sentry =
$c->search($basedn,$scope,$ARGV[1],0,$attr[0],$attr[1],$attr[2]

221

);

:
Sentry = $c->search($basedn,$scope,$ARGV[1]);
:

@attr = qw(mail);
Sentry = $c->search($basedn,$scope,$ARGV[1],0,@attr);
, DN mail:
dn: cn="bear pooh",mail=poohbear219@hotmail.com,c=US,o=hotmail.com
mail: poohbear219@hotmail.com
, , N e t : : LDAP, :
use Net::LDAP;
# "typesonly => 1"
,
#
Ssearchobj = $c->search(base => Sbasedn, filter => $ARGV[1],
attrs => \@attr);
, N e t : . LDAP , , M o z i l l a : : LDAP.
Perl

, , Perl.
LDAP, ,
.
Mozilla: :LDAP
, , , Perl
. $entry->{attributename} - 1 . , . .
1

, (, ,
). - . . .

222

6.
,
. $entry->{attributename}->[0]. Mozilla: : L D A P : : E n t r y
(. 6.3).
6.3. Mozilla::LDAP::Entry

true,
Sentry->hasValue($attrname,$attrvalue) true,

Sent ry->matchValue($att rname,$att rvalue) , ,

,


$entry->exists($attrname)

$entry->size($attrname)


( 1, )

, Mozilla: : L D A P : : Entry.
,
Net : : LDAP . .
, .
-, , . $searchobj->
as_struct() ,
. , DN- . ,
. , (. 6.1).

:
$searchstruct = $searchobj->as_struct;
for (keys %$searchstruct){
print $searchstruct->{$_}{cn}[0], "\n";

, "
:

1_0:

223

Sentry {uid=rsmith,ou=system,ou=people,c=ccs,dc=hogwarts,dc=edu| =
[rsmith]
^[Boston]

}=
I phones I =

ref

4 [ 617-555-1212,617-555-2121]

. 6.1. , as_struct()
#
Sentry = $searchobj->entry($entrynum);
shift() Perl
Sentry = $searchobj->shift_entry;
() Perl
Sentry = $searchobj->pop_entry;
#
gentries = $searchobj->entries;
,
(. 6.4).
6.4. Net::LDAP

$entry->get($attrname)
$entry->attributes()

. ,
:
$value = $searchobj->entry(1)->get(cn)
,
, , , .
LDIF

LDAP,
, , , . , -

224

. 0

.
LDIF.
1
LDIF, RFC , .
LDIF (Gordon
Good):
version: 1
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
en: Barbara Jensen
en: Barbara J Jensen
en: Babs Jensen
sn: Jensen
uid: bjensen
telephonenumber: +1 408 555 1212
description: A big sailing fan.
dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
en: Bjorn Jensen
sn: Jensen
telephonenumber: +1 408 555 1212
. LDIF DN- , objectclass . .
- LDIF .
(
LDIF), LDIF-
Perl,
.
LDAP , LDIF. ,
:
use Mozilla::LDAP::Conn;
use Mozilla::LDAP::LDIF;
<
.
. . .

225

open(LDIF, ">$l_DIFfile ") or die "" $LDIFfile:$! \n";


LDIF
$ldif = new Mozilla: :LDAP: :LDIF(\.LDIF);
while (Sentry) {
$ldif->writeOneEntry( Sentry);
Sentry = $c->nextEntry();
$c->close();
close(LDIF);
Mozilla : : LDAP writeEntries( ),
.
Net : : LDAP, . :
Sldif = new Net:: LDAP: :LDIF("-");
:
Sldif = new Net: : LDAP: :LDIF($filename,"w");
, .
LDIF (
, ). ,
, . 2
LDIF- Perl , , .

, . ,
. , Mozilla: : LDAP
:
use Mozilla: :LDAP: :Conn;
use Mozilla: :LDAP::LDIF;
Sserver = $ARGV[0];
SLDIFfile = $ARGV[1];
Sport
= getservbyname("ldap", "tcp") || "389";
$LDIFfile=$ARGV[l];. - . .
.
LDIF changetype:,
, , . Net: : LDAP
changetype: Net: : L D A P : : L D I F : : read_cmd().

226

.
Srootdn
$pw

= "cn=Manager, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";


= "secret";

# LDIF,

open(LDIF,"SLDIFfile") or die " $LDIFfile:$!\n";
Sldif = new Mozilla::LDAP::LDIF(\*LDIF);
tt , entries
entries = Sldif->readEntries();
close(LDIF);
n
$c = new Mozilla::LDAP::Conn($server,Sport,Srootdn,$pw);
die " $server\n" unless $c;
# ,
for (@entries){
$c->add($_); -
warn " ". $_->getDN().": ".$c->getErrorString()."\n"
if $c->getErrorCode();
$c->close();
getErrorCodeO getErr o r S t r i n g ( ) ( ), . , DN/RDN-,
, . .,
.
,
Net: : LDAP:
DN- (manager DN). ,
,
. LDAP- ( DN-)
.
.
N e t : : LDAP , LDIF-, :
use Net::LDAP;
use Net::LDAP::LDIF;
Sserver
SLDIFfile
Sport
Srootdn
$pw

=
=
=
=
=

$ARGV[0];
$ARGV[1];
getservbyname("ldap","tcp") || "389";
"cn=Manager, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";
"secret";

227

# LDIF,

# "" , "w"
$ldif = new Net::LDAP::LDIF($LDIFfile,"i-);
@entries = $ldif->read();
$c = new Net::LDAP($server, port => Sport) or
die " Sserver: $@\n";
$c->bind(dn -> Srootdn, password => $pw) or die " :
for (@entries){
$res = $c->add($_);
warn " ". $_->dn().": ".$res->code. "\n"
if $res->code();
$c->unbind();
:
LDIF
:
entries = new Net: :LDAP: :LDIF($LDIFfile, "r")->read;
add() ,
. , :
cn=Ursula Hampster, ou=Alumni Association,
ou=People,
o=University of Michigan, c=US: 68
, e r r o r ( ) , Mozilla : : LDAP:
print " : ". $res->error. "\n";
,
, LDAP
.
, Net : : LDAP: : Util : l d a p _ e r r o r _ t e x t ( ) l d a p _ e r r o r _ n a m e ( ) .
68 - 44 .
, Constant.pm
:
sub LDAP_ALREADY_EXISTS

() { 0x44 }

,
LDIF, .

228

. 0


LDAP
,
,
, .
-, . Mozii1: : LDAP -
. :
use Mozilla::LDAP::Entry;
$e = new Mozilla::LDAP::Entry()
. - DN. setDN():
$e->setDN("uid=jay, ou=systems, ou=people, dc=ccs, dc=hogwarts, dc=edu");
, objectClass,
. , ( , ), :
$e->{cn} = ['Jay Sekora 1 ];

, . M o z i l l a : : LDAP
, , , , , :
# (, , )
$e->{cn} = 'Jay Sekora';

:
$e->addValue('en', 'Jay Sekora 1 );
addValue():
$e->addValue('title', 'Unix SysAdmin');
$e->addValue('title', 'Part-time Lecturer');
, . .
, ,
.
, add() ^
. ,

LDAP;

229

. , (
) :
use Mozilla::LDAP::Conn;
Sserver
Sport
Ssuffix
$rootdn
$pw

= $ARGV[0];
= getservbyname("ldap", "tcp") || "389";
= "ou=People, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";
= "cn=Manager, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";
= "secret";

#
$c = new Mozilla::LDAP::Conn($server,Sport,Srootdn,$pw);
die " $server\n" unless $c;
$e = new Mozilla::LDAP::Entry;
tt DN- - ,
# ,
$e->setDN("uid=$ARGV[1],$suffix");
$e->addValue('uid', $ARGV[1]);
$e->addValue('cn', $ARGV[2]);
$c->add($e);
die " : ". $c->getErrorString()."\n" if $c>getErrorCode();
, . , ,
, ,
, . , .
Net: : LDAP. Net: : LDAP -.
E n t r y ( N e t : : LDAP: : E n t r y ) .
add(),
:
$res = $c->add(
dn => 'uid=jay, ou=systems, ou=people, dc=ccs, dc=hogwarts, dc=edu',
attr => [ 'en' => 'Jay Sekora',
'sn
=> 'Sekora',
'mail' => 'jayguy@ccs.hogwarts.edu',
'title'=>
['Sysadmin1,'Part-time Lecturer'],
1
'uid => 'jayguy',
die " , ft". $res->code() if $res->code();

230

6.
add() .1 - DN-
; - -. ,
title,
. , Perl -
.


- ( ,
). , ,
, , :
use Mozilla::LDAP::Conn;
8 ,
$c->delete($entry->getDN())
$c->delete($dn) or
die " : ". $c->getErrorString()."\n";
use Net::LDAP;
$res = $c->delete($dn);
die " , 8".$res->code() if $res->code();
, delete( )
. , , sub one,
, . , .

LDAP, ,
LDAP. - DN-
RDN-. RDN- ,
. Mozilla: : LDAP:
use Mozilla::LDAP::Conn;
$c->modifyRDN($newRDN,$oldDN,$delold) or
die " :". $c->getErrorStririg(). "\n";
, Perl, . . "
. . .

231

, Sdelold m o d i f y R D N ( ) . true, LDAP- ,


RDN-. , RDN- 1 ( location, ), RDN-
, 1
.
N e t : : LDAP:

use N e t : : L D A P ;

$res = $c->moddn($oldDN,
newrdn
=> SnewRDN,
deleteoldrdn => 1);
die " , #".$res->code() if $res->code();
m o d d n ( ) N e t : : L D A P
, .
RDN- ,
. LDAP 3 ,
. m o d d n ( ) , news u p e r i o r , .
:
Sresult = $c->moddn($oldDN,
newrdn
=> $newRDN,
deleteoldrdn => 1,
newsuperior => $parentDN);
die " , #".$res->code() if $res->code();
SoldDN DN, SparentDN.
, a d d ( ) delete(), , , LDAP-. , , .


. Mozilla: : LDAP
Net: :LDAP. Mozilla: :LDAP ,

232

. >

. 6.5.

6.5. Mozilla::LDAP

$entry->addValue($attrname,
$attrvalue)
$entry-> reraoveValue($attrnairie,
$attrvalue)

^
.

$entry-> setValue($attrname,
$attrvalue1,...)
$entry-> reraove($attrname)


.
(
) .

.

.

( ), update() LDAP, . update()


(. . $rupdate($entry)).
.
: . , :
use Mozilla::LDAP::Conn;
Sserver = $ARGV[0];
Sport = getservbyname("ldap", "top") || "389";
Sbasedn = "dc=ccs,dc=hogwarts,dc=edu";
Sscope = "sub";
$rootdn = "cn=Manager, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";
$pw
= "secret";

$c = new Mozilla::LDAP::Conn($server,Sport,$rootdn,$pw);
die " $server\n" unless $c;
# ,

Sentry = $c->search($basedn,Sscope, "(l=Boston)", 1, ");
die " :". Sc->getErrorString()."\n" if Sc->getErrorCode();
if ($entry){ - .- . - --, .
while($entry){
Sentry->removeValue("l","Boston");

233

1_:

$entry->addValue("l", "Indiana");
$c->update($entry);
die " :" . $c->getErrorString() . "\n"
if $c->getErrorCode();
Sentry = $c->nextEntry();
$c->close();
Net : : LDAP .
Mozilla : : LDAP modify(). , , (. 6.6).
6.6. Net::LDAP

add => {Sattrname => Sattrvalue}


add => {$attrname => [$attrvalue1,
$attrvalue2...]}
delete => {$attrname => Sattrvaliie}
I
delete => {$attrname => []}
delete => [$attrname1,$attrname2...]

.
.

.

.

replace => {Sattrname => Sattrvalue} , add, .


Sattrvalue
([]),

.

. , - . ,
.
modifyO, .
m o d i f y ( ) , , :
$c->modify($dn,replace => {' => "Medford"},
add
=>{'!' => "Boston"},
add
=> {'!' => "Cambridge"});
, . , , ,
. -

234

6.
, ^ . - : modifyO
changes, - . . - ,
, - , . , ,
, :
$c->modify($dn, changes =>
[ replace => [ => "Medford"],
add
=>['!' => "Boston"],
add
=> ['!' => "Cambridge"]
]):
:
, .
, modify( ), Net : : LDAP ,
:
use Net: :LDAP;
Sserver
Sport
$basedn
Sscope
$rootdn
$pw

=
=
=
=
=
=

$ARGV[0];
getservbyname("ldap", "tcp") || "389";
"dc=ccs,dc=hogwarts,dc=edu";
"sub";
"cn=Manager, ou=Systems, dc=ccs, dc=hogwarts, dc=edu";
"secret";

$c = new Net: :LDAP($server, port => Sport) or


die " Sserver: $@\n";
$c->bind(dn => Srootdn, password => $pw) or die " :
$@\n";
Ssearchobj = $c->search(base => Sbasedn, filter => "(l=Boston)",
scope => Sscope, attrs => [''],
typesonly => 1);
die " : ". $searchobj->error(). "\n" if ($searchobj->code()):
if (Ssearchobj ){
entries = $searchobj->entries;
for (@entries){
$res=$c->modify($_->dn(), # dn() DN-
delete => {"1" => "Boston"},
add
=> {"1" => "Indiana"});
die " , S".$res->code() if $res->code()>

$c->unbind();

235


, LDAP-, .
5 TCP/IP
LDAP ,
LDAP-.
( , ):
name: shimmer
address: 192.168.1.11
aliases: shim shimmy shimmydoodles
owner: David Davis
department: software
building: main
room: 909
manufacturer: Sun
model: UltraGO
name: bendir
address: 192.168.1.3
aliases: ben bendoodles
owner: Cindy Coltrane
department: IT
building: west
room: 143
manufacturer: Apple
model: 7500/100
, , - . ,
. -. , Netscape Directory Server Console . . OpenLDAP, ,
:
objectclass machine
requires
objectClass,
en
allows
address,
aliases,
owner,
department,

6.

236
building,
room,
manufacturer,
model

,
. -
LDIF.
LDIF, ,
. . , :

,
, , LDIF. LDIF , .

-=-.
(. . ) LDIF,

.

: aliases (). LDIF
, . ,
,
. , ,
LDIF, Perl.
:
Sdatafile = "database";
$recordsep = "-=-\n";
$suffix = "ou=data, ou=systems, dc=ccs, dc=hogwarts, dc=edu";
Sobjectclass = EOC;
objectclass: top
objectclass: machine
EOC
open(DATA,$datafile) or die " $datafile:$!\n";
Perl ,
# print "version: 1\n";

237

while (<DATA>) {

#
if (/name:\s*(..)/){
print "dn: cn=$1, $suffix\n";
print $objectclass;
print "en: $1\n";
next;

ft aliases
if (s/"aliases:\s*//){
aliases = split;
foreach $name (@aliases){
print "aliases: $name\n";
}
next;

ft
if ($_ eq $recordsep){
print "\n";
next;
}
#
print;
close(DATA);

, LDIF, :
dn: cn=shimmer, ou=data, ou=systems, dc=ccs, dc=hogwarts, dc=edu
objectclass: top
objectclass: machine
en: shimmer
address: 192.168.1.11
aliases: shim
aliases: shimmy
aliases: shimmydoodles
owner: David Davis
department: software
building: main
room: 909
manufacturer: Sun
model: Ultra60
dn: cn=bendir, ou=data, ou=systems, dc=ccs, dc=hogwarts, dc=edu
objectclass: top
objectclass: machine
en: bendir
address: 192.168.1.3
aliases: ben

238

6.
aliases: bendoodles
owner: Cindy Coltrane
department: IT
building: west
room: 143
manufacturer: Apple
model: 7500/100
LDIF-, , , . ,
Idif2ldbm, OpenLDAP Netscape Directory Server, LDIF-
, LDAP. ,
. ,
Perl
LDIF- LDAP-.
: , LDIF-, LDAP-:
use Net::LDAP;
use Net::LOAP::Entry;
$datafile = "database";
$recordsep = "-=-";
Sserver
= $ARGV[0];
Sport
= getservbyname("ldap","top") || "389";
Ssuffix
= "ou=data, ou=systems, dc=ccs, dc=hogwarts, dc=edu";
$rootdn
= "cn=Manager, o=University of Michigan, c=US";
$pw
= "secret";
$c = new Net::LDAP($server,port => Sport) or
die " $server: $@\n";
$c->bind(dn => $rootdn,password => $pw) or die " : $@\";
open(DATA,Sdatafile) or die " $datafile:$!\n";
while (<DATA>) {
chomp;
#
if (/-name:\s*(.*)/){
$dn="cn=$1, $suffix";
Sentry = new Net::LDAP::Entry;
$entry->add("cn",$1);
next;
}
--

239

if (s/~aliases:\s*//H
$entry->add( 'aliases' , [split()]);
next;
# ,
if ($_ eq $recordsep){
$entry->add("objectclass", ["top", "machine"]);
$entry->dn($dn);
$res = $c->add($entry);
warn " " . $entry->dn() . ":
$res->code. "\n"
if $res->code();
undef Sentry;
next;

$entry->add(split( ' :\s*' )); # ,

close(DATA);
$c->unbind();
, . LDAP-.
, , .
,
LDAP? :
use Mozilla: :LDAP;
Sentry = $c->search($basedn, 'one', '(objectclass=machine)' ,0,
'en' , 'address' , 'aliases' );
die " :". $c->getErrorString(). "\n" if $c->getErrorCode();
if ($entry){
print "#\n\# host file - GENERATED BY $0\n
# DO NOT EDIT BY HAND! \ntt\n";
while($entry){
print $entry->{address>[0], "\t",
$entry->{cn}[0], " ",
jain( ' ' ,@{$entry->{aliases}}), "\rt":
Sentry = $c->nextEntry();
$c->close();

240

6.
:

host file - GENERATED BY Idap2hosts


# DO NOT EDIT BY HAND!

192.168.1.11
192.168.1.3
192.168.1.12
192.168.1.55

shimmer shim shimmy shimmydoodles


bendir ben bendoodles
Sulawesi sula su-lee
sander sandy mickey mickeydoo

, Apple:
use Net: :LDAP;
$searchobj = $c->search(base => Sbasedn,
filter => "(manufacturer=Apple)",
scope => 'one', attrs => ['en']);
die " : ".$searchobj->error(). "\n" if ($searchobj->code());
if ($searchobj){
for ($searchobj->entries){
print $_->get( 'en' ), "\n";

$c->unbind();
:
bendir
Sulawesi
:
use Mozilla: :LDAP;
Sentry = $c->search($basedn, 'one' , ' (objectclass=machine)' ,0,
'en' , 'owner' );
die " :". $c->getErrorString(). "\n" if $c->getErrorCode();
if ($entry){
while($entry){
push(@{$owners{$entry->{owner}[0]}},$entry->{cn}[0]);
Sentry = $c->nextEntry();
$c->close();
for (sort keys %owners){
print $_.":\t". join( ' ',@{$owners{$_}})."\n";

051 ( )

241

:
Alex Rollins: sander
Cindy Coltrane: bendir
David Davis:
shimmer
Ellen Monk:
Sulawesi
, (-):
use Mozilla::LDAP::Conn;
use Sys::Hostname;
Suser = (getpwuid($<))[6];
$hostname = hostname;
Shostname =" s/"([".]+)\..*/$1/; #
Sentry = $c->search("cn=$hostname,Ssuffix",'base',"(owner=$user)",1,'');
if ($entry){
brint " (Suser) $hostname.\n";
}
else {
print "Suser ($hostname)\n.";
}
$c->close();
,
LDAP Perl ,
.
, , LDAP.
ADSI (
)
-
, .
Microsoft , LDAP,
Active Directory Windows 2000. Active Directory
(, , , . .),
Windows 2000.

242

. 0
Microsoft ,
. ADSI (Active Directory Service Interfaces, ). 0
Microsoft, , , NT.
ADSI , , . ,
, .

ADSI
ADSI , ADSI.
(providers), ADSI LDAP,
WinNT 4.0 Novell Directory Service. ADSI, (WinNT )
(data domains)
(namespaces). ADSI
, .
ADSI,
COM (Component Object Model), ADSI. , :

, , - (objects).1

, (interfaces), (methods), . Perl ,


IDispatch. ,
ADSI, ADSI
(, lADsUser, lADsComputer, lADsPrintQueue), IDispatch.
, , , (properti'
es). : ,
(interface-definedproperties), ,
(schema-defined properties). .
- ,
OLE (
).
Microsoft, , ,
, http://www.microsoft.com/com.

>DSI ( )

243

, -
. . , ,
.
- . ,
ADSI/COM - , LDAP.
, ADSI :
(leaf) (container). - ;
- , . . (parent). LDAP
. , , -
. ,
, ?
: , LDAP .
ADSI LDAP , ADSI LDAP,
-.
,
. ,
ADSI, LDAP.

: LDAP? : , ADSI
, , (,
, , ADSI-).
, , ADSI.
AdsPaths, ADSI- Perl. ADsPaths
. :
<progID>:<path to object>

I
^
'-

<progID> - ( WinNT LDAP),


a <path to object> -
. <progID> . winnt, Idap WINNT WinNT LDAP, .
ADsPath ADSI SDK:

244

6.
WinNT: //MyDomain/MySe rve r/L)se r
WinNT://MyDomain/JohnSmith,user
LDAP://ldapsvr/CN=TopHat,DC=DEV,DC=MSFT,DC=COM,0=Internet
LDAP://MyDomain.microsoft.com/CN=TopH,DC=OEV,DC=MSFT,DC=COM,0=Internet
, URL, . . URL ADsPath . ,
. AdsPath LDAP LDAP URL RFC, (RFC2255).
AdsPath
- WinNT LDAP. , , , ADSI Perl.

ADSI Perl
W i n 3 2 : : O L E , (Jan
Dubois) (Gurusamy Sarathy),
Perl ADSI ( OLE).
ADSI-:
use Win32::OLE;
Sadsobj = Win32::OLE->GetObject($ADsPath) or
die " $ADsPath\n";
Win32: :OLE->GetObject() (moniker) OLE ( , ADsPath) ADSL (binding) , LDAP.
, .
.

,
:
DB<3> x Sadsobj
Win32::OLE=HASH(Ox10feOd4)
empty hash
He . Win32: :OLE (tied variables).
, , , .
ADSI
:

051 ( )

245

ADSI
ADSI .
( DCOM) ADSI . (Toby Everett), , , ADSI
DCOM.
Windows 2000 ADSI. Win32-Ma
ADSI 2.5, http://www.microsoft.com/adsl.
ADSI, adsi25.chm, - HTML, ADSI.
Windows 2000,
ADSI SDK Microsoft ,
ADSI
AdsVW. SDK ADSI , Perl. , ADSI
OLE.pm, , , ,
.
, ADSI ( Perl) http:/'/
opensource.activestate.com/authors/tobyeverett. ADSL
, ADSI,

ADSI Perl.
$value = $adsobj->{key}
, Name,
( ), :
print $adsobj->{Name}."\n";

:
$adsobj->{FullNa(ne}= "Oog"; #
ADSI (
(property cache)). -

246

6. 0
. , .
, Getlnfo()
GetInfoEx() ( GetlnfoQ)
, , .
- , GetlnfoO GetInfoEx() .
, ,
. :
1. ,
GetlnfoExQ. LDAP- Microsoft Exchange 5.5
,
, GetlnfoExQ. http:/ /'opensource.activestate.com/authors/tobyeverett.
2. ,
- ,
. ,
. GetlnfoO GetlnfoExQ .
, ADSI, Setlnfo(). SetlnfoQ
. ( update() Mozilla: :LDAP.
.)
ADSI :
$adsobj->Method($arguments...)
, , , , :
$adsob]->Set!nfo();

.
Win32: :OLE->LastError() *1
Win32::OLE. , '
OLE. -w Perl (. . perl -w script)
*
OLE-. -
, ,
.

( )

247'

ADSI-, , Perl, . .
/
ADSI:
. - ,
( - OLE/COM) . ADSI , - , .
- , . . , .
Perl. W i n 3 2 : :OLE in( ), , . , :
use Win32: :OLE 'in' ;
in () ,
.
Perl:
foreach Schild (in $adsobj){
print $child->{Name}
, Win32: :OLE Win32: :OLE: :Enum. Win32: :OLE: :Enum>new( ) - - -:
use Win32: :OLE: :Enum;
$enobj = Win32: :OLE: :Enum->new($adsobj);
$adsobj . , Mozilla : : LDAP;
.
$enobj->Next( )
( X , ). $enobj->All .
Win32 : : OLE : : Enum (
), .

248

6.

-
, . Perl , .
, - - , , . , :
use Win32: :01_;
use Win32::OLE::Enum;
eval {$enobj = Win32::OLE::Enum->new($adsobj)};
print " " . ($@ ? " " : "") . " \";
- ,
. .
- ?
, ,
. . ,
,
, . ? ?
, ,
,
.
- ADSI, , ADSI. .
Active Directory Service
Interfaces 2.5>ADSI Reference>ADSI System Providers.
, ,
. ,
ADSI. , .
ADSI Schema,
ADsPath . ,
:
use Win32: :01_;
$ADsPath = "WinNT://BEESKNEES,computer";
Sadsobj = Win32::OLE->GetObject($ADsPath) or
die " $ADsPath\n";
print " ".$adsobj->{Class}.", :\".

( )

249

$adsobj->{Schema}, "\n";
:
Computer, : WinNT://DomainName/Schema/Computer
$adsobj->{Schema} - ADsPath , Computer . , LDAP. LDAP ,
. ADSI

.
: MandatoryProperties OptionalProperties.
print:
Sschmobj = Win32::OLE->GetObject($adsobj->{Schema}) or
die " $ADsPath\n";
print join("\n",@{$schmobj->{MandatoryProperties}},
@{$schmobj->{OptionalProperties}}), "\ri";
:
Owner
Division
OperatingSystem
OperatingSystemVersion
Processor
ProcessorCount

WinNT Computer. .
,
. :
#
Svalue = $obj->{property};
$obj->{property} = Svalue;
:
ft
Svalue = $obj->Get("property");
$obj->Put("property","value");
, , , (. . . SetTnfn;' i

250

6.

. .).
, ,
, - .
,
, . ,
:
$len = $userobj->{PasswordMinimumLength};
$len = $userobj->Get("MinPasswordLength"); #

"s

,
. , , . , , -, , . ADSI
. ,
. . .
,
, ADSI- ,
. (. 6.2).
ADSIDump General SDK,
ADSI.

, ,
. LDAP:
LDAP.
ADSI . - ,
Perl ( , OLE ) ADSI ; , ,
, . ( .)
, . .
ADSI ( , : Microsoft).
, , , , . ,
( base)

251

( )

, ADSI Inspector WmNT://STANDALONE/OMPHALOSKEPSIS/AdminislialoK


ADSI Inspector VVmNTl/STANDALONE/OMPHAlOSKEP'SIS;;

strators

ADSI Class Group


I Built In rr trties -'

Valje

-jjjjjlitfator:rnup
JJC1AADO- it. :-: -._r-aiF3-02606C=_;55;j
'l*rr//STANDALONE/OMPHALOSKEP3iS/A'.1i4!rli::t.-ators
nfJT /'STANDALONE/OMPHALOSK EPSIS
i iNT /;SrANDALONBSchema/Group
^embers can ftiil^administer the coiTip_uter/dc:- :
iers Win32 OLE=HA_SH(Ox114dabOJ_
IDS! Schema _WnNT/'ST.ANDALONBScherna/Group
chema Properties
Collection Object.
[Ready

"

. 6.2. ADSI- , Administrators


( one), Perl. :
:
if ($adsobj->{cn} eq "Mark Sausville" and $adsobj->{State} eq "CA"){...}

, , . .
, ,
, , -

252

ADO (ActiveX Data Objects, ActiveX). ADO


Microsoft OLE DB. OLE DB , , , . ADO
ADSI (, , ). ADO -
, ODBC, 7.
ADO LDAP ADSI.
WinNT .

ADO - , , , ADSL ADO http://www.microsoft.com/ado.


, ,
. .
use Win32: :OLE 'in';
# ADO, ,
$ = Win32: :OLE->new("ADODB. Connection");
$c->{Provider} = "ADsDSOObject";
$c->Open("ADSI Provider");
die Win32: :OLE->LastError() if Win32: :OLE->LastError();
#
SADsPath = "LDAP://ldapserver/dc=example,dc=com";
$rs = $c->Execute("<$ADsPath>; (objectClass=Group); Name;SubTree");
die Win32: :OLE->LastError() if Win32: :OLE->LastError();
until ($rs->EOF){
print $rs->Fields(0)->{Value}, "\n";
$rs->MoveNext;
$rs->Close;
$c->Close;

Connection,
, .
, ,
,
.

51 ( )

253

ExecuteO.
: SQL
ADSI.1 ADSI, , , ,
.2 :
ADsPath ( ), DN .
( LDAP-,
).
( ) .
: Base, OneLevel, SubTree ( LDAP).
ExecuteO ADO RecordSet, .
RecordSet, , , Value, Fields()
. Value ,
( Group). Windows 2000:
Administrators
Users
Guests
Backup Operators
Replicator
Server Operators
Account Operators
Print Operators
DHCP Users
DHCP Administrators
Domain Computers
Domain Controllers
Schema Admins
Enterprise Admins
Cert Publishers
Domain Admins
Domain Users
, SQL, . SQL . , MS SQL Server 7
, ADSI-,
. , SQL-, ActiveDirectory ADSI.
ADSI ADO: , .

254

6.
Domain Guests
Group Policy Admins
RAS and IAS Servers
OnsAdmins
DnsUpdateProxy


Win NT LDAP
, ,
, ADSI Perl. - ,
ADSL ,
.
.
- WinNT, Windows NT 4.0, , , ,
. .
- - LDAP. LDAP Windows 2000 Active Directory,
LDAP. WinNT
LDAP. Windows 2000 ,
, WinNT (, ).
, ,
( ,
ADSI),
. -, ADsPath .
ADSI SDK, ADsPath WinNT
:
WinNT:[//DomainName[/ComputerName[/ObjectName[,className]]]]
WinNT:[//DomainName[/ObjectName[,className]]]
WinNT:[//ComputerName,computer]
WinNT:
ADsPath LDAP :
LDAP://HostName[:PortNumber][/DistinguishedName]
, NT 4 ADsPath LDAP
( Windows 2000 ). , LDAP , WinNT, . . . WinNT ADsPath
W i n N T : .

51 ( )

255

, , . ,
WinNT LDAP,
Active Directory
LDAP.
. , User WinNT , User LDAP
samAccountName .
, . , -w
:
die " OLE: ".Win32: :OLE->LastError() if Win32: :OLE->LastError();
ADSI
:
use Win32: :OLE 'in';
SADsPath = "WinNT ://DomainName/PDCName, computer";
$c = Win32: :OLE->GetObject($ADsPath) or die " $ADsPath\n";
foreach Sadsobj (in $c){
print $adsobj->{Name}, "\n" if ($adsobj->{Class} eq "User");

( Full Name):
use Win32: :OLE;
$ADsPath="WinNT://DomainName/ComputerName, computer";
$c = Win32: :OLE->GetObject($ADsPath) or die " $ADsPath\n";
fl User
$ = $c->Create("user", Susername);
$u->Set!nfo( ); # ,
WinNT: "Full" "Name"
$u->{FullName} = $fullname;
$su->Set!nfo();
Compute rName - (Primary Domain Controller), . , .

256

6.
(
LDAP ) Active
Directory :
use Win32::OLE;
$ADsPath = "LDAP://ldapserver,CN=Users,dc=example,dc=com";
$c = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n" User
$u=$c->Create("user","cn=".$commonname);
$u->{samAccountName} = Susername;
# ,
$u->SetInfo();
# "Full" "Name"
LDAP:
$u->{'Full Name'} = Sfullname;
$u->Set!nfo();
:
use Win32::OLE;
$ADsPath = "WinNT://DomainName/ComputerName, computer";
$c = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n";
ft User, ,
$c->Delete("user",$username);
$u->Set!nfo();
:
use Win32::OLE;
SADsPath = "WinNT://DomainName/ComputerName/".Susername;
$u = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n';
$u->ChangePasssword($oldpassword,$newpassword);
$u->Set!nfo();

ADSI

, .
:
print $adsobj->{Name},"\n" if ($adsobj->{Class} eq "Group");

( )

257


CreateO DeleteO,
. -
group. :
$ = $c->Create("group",$groupname);
(
GroupName) :
use Win32::OLE;
$ADsPath = "WinNT://DomainName/GroupName, group";
$g = Win32::OLE->GetObjeot($ADsPath) or die " $ADsPath\n";
# ADsPath
$g->Add($userADsPath);
(),
. , $userADsPath PDC .
:
$c->Remove($userADsPath);
ADSI
ADSI,
. ADSI, :
use Win32: :0!_;
$ADsPath = "WinNT://ComputerName/lanmanserver";
$ = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n";
$s = $c->Create("fileshare",Ssharename);
$s->{path}
= 'C:\directory';
$s->{description} = "This is a Perl created share";
$s->Set!nfo();
DeleteO.
, SDK
- ADSI-. - . Acti-

258

6.
Directory Service Interfaces 2.5-+ADSI Referen.ce-> ADSI Interfa.
ces> Persistent Object Interfaces-* lADsFileShare
ADSI 2.5, , fileshare CurrentUserCount, , .
.

ADSI

, :
use Win32: :OLE 'in';
$ADsPath="WinNT : //DomainName/PrintServerName , computer" ;
$c = Win32: :OLE->GetObject($ADsPath) or die " $ADsPath\n";
foreach $adsobj (in $c){
print $adsobj->{Name}. ":".$adsobj->{Model}. "\n"
if ($adsobj->{Class} eq "PrintQueue");
, :
use Win32: :OLE 'in';

'Active Directory Service Interfaces 2.5->ADSI Reference->
ADSI Interfaces->Dynamic Object Interfaces->IADsPrintQueueOperations->
ft lADsPrintQueueOperations Property Methods' (!) ADSI 2.5 SDK
%status =
(0x00000001
0x00000003
0x00000005
0x00000007
0x00000100
0x00000400
0x00001000
0x00004000
0x00010000
0x00040000
0x00100000
0x00400000
0x01000000

'PAUSED',
'ERROR' ,
PAPERJMJT',
'PAPER_PROBLEM',
IO_ACTIVE',
'PRINTING',
'NOT_AVAILABLE',
'PROCESSING',
'WARMINGJP',
'NO_TONER',
'USERJNTERVENTION'
'DOORJ3PEN',
POWER_SAVE');

0x00000002
0x00000004
0x00000006
0x00000008
0x00000200
0x00000800
0x00002000
0x00008000
0x00020000
0x00080000
0x00200000
0x00800000

'PENDING_DELETION'
'PAPER_JAM',
'MANUALJEED',
'OFFLINE',
'BUSY',
'OUTPUT_BIN_FULL',
'WAITING',
'INITIALIZING',
'TONER_LOW ,
'PAGE_PUNT',
'OUT_OF_MEMORY',
'SERVER UNKNOWN',

SADsPath = "WinNT://PrintServerName/PrintQueueName";
$p = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n

$1 ( )

259

print " " . $c->{Name} . " -- " .


((exists $p->{status}) ? $status{$c->{status}} : "NOT ACTIVE") .
PrintQueue : Pause(), ResumeO Purge().
. ?
, PrintJobsO PrintQueue. PrintJobsO ,
P r i n t Job,
. ,
:
use Win32::OLE 'in';

#
tt


'Active Directory Service Interfaces 2.5->ADSI Reference->
AOSI Interfaces->Dynamic Object Interfaces->IADsPrintJobOperations->
lADsPrintJobOperations Property Methods' ( ) ADSI 2.5 SDK

%status = (0x00000001
0x00000004
0x00000020
0x00000080

=>
=>
=>
=>

'PAUSED', 0x00000002
'DELETING',0x00000010
'OFFLINE', 0x00000040
'PRINTED', 0x00000100

=>
=>
=>
=>

'ERROR',
'PRINTING',
'PAPEROUT',
'DELETED');

$ADsPath = "WinNT://PrintServerName/PrintQueueName";
$p = Win32::OLE->GetObject($ADsPath) or die " $ADsPath\n";
$jobs = $p->PrintJobs();
foreach $job (in $jobs){
print $job->{User} . "\t" . $job->{Description} . "\t" .
$status{$job->{status}} . "\n";

}
(Pause()) (ResumeO).
NT/2000 ADSI
, ,
NT/2000.
, .
:
use Win32::OLE 'in';

260

6.
#
tt 'Active Directory Service Interfaces 2.5->ADSI References
tt ADSI Interfaces->Dynamic Object Interfaces->IADsServiceOperations->
tf lADsServiceOperations Property Methods' ADSI 2.5 SDK
%status =
(0x00000001
0x00000003
0x00000005
0x00000007

=>
=>
=>
=>

'STOPPED',
0x00000002
'STOP_PENDING',
0x00000004
'CONTINUE_PENDING',0x00000006
'PAUSED',
0x00000008

=>
=>
=>
=>

'START_PENDING',
'RUNNING',
'PAUSE_PENDING',
'ERROR');

SADsPath = "WinNT;//DomainName/ComputerName,computer";
$c = Win32;;OLE->GetObject($ADsPath) or die " $ADsPath\n";
foreach Sadsobj (in $c){
print Sadsobj->{DisplayName} . ":" . $status{$adsobj->{status}} . "\n"
if ($adsobj->{Class} eq "Service");
>
, ,
(StartO, Stop() . .).
Network Time Windows 2000, :
use Win32;;OLE;
SADsPath = "WinNT;//DomainName/ComputerNaroe/W32Time,service";
$s = Win32;;OLE->GetObject($ADsPath) or die " $ADsPath\n";
$s->Start();
(t ,
#
, :
use Win32;;OLE;
$d = Win32;;OLE->GetObject("WinNT;//Domain");
$c = $d->GetObject("Computer", Scomputername);
$s = $c->GetObject("Service", "W32Time");
$s->Start();
:
$s->Stop();
,

.^

261

,
ADSI Perl. .

Net: : Telnet
Net: : Finger
Net: :Whois
Net: :LDAP
Mozilla: :LDAP
Sys : : Hostname ( Perl)
Win32 : : OLE ( ActiveState Perl)


CPAN
JROGERS
3.01
FIMM
1.05
DHUDES
GBARR
LEIFHED

0.20

JDB

1.11

1.9
1.4


Finger
RFC1288:The Finger User Information Protocol, D. Zimmerman, 1991.
WHOIS
ftp://sipb.mit.edu/pub/whois/whois-servers.list WHOIS-.

RFC954.-NICNAME/WHOIS, . Harrenstien, M. Stahl, and E. Feinler, 1985.


LDAP
An Internet Approach to Directories, Netscape, 1997 -

LDAP
(http://developer.netscape.com/docs/manuals/ldap/
ldap.html).
An LDAP Roadmap & FAQ, Jeff Hodges, 1999 (http://www.kingsmountain.com/ldapRoadmap.shtml).
http://www.ogre.com/ldap/
http://www.linc-dev.com/ -
PerLDAP.
http://www.openldap.org/ - LDAP-,
.

262

6.
http://www.umich.edu/~dirsvcs/ldap/index.html -
OpenLDAP Netscape.
.
Implementing LDAP, Mark Wilcox (Wrox Press, 1999).
LDAP-HOWTO, Mark Grennan, 1999 (http://www.grennan.com/ldapHOWTO.html).
LDAP Overview Presentation, Bruce Greenblatt, 1999 (http://www.directory-applications.com/presentation/).
LDAP:Programming Directory-Enabled Applications With Lightweight
Directory Access Protocol, Tim Howes and Mark Smith (Macmillan
Technical Publishing, 1997).
Netscape Directory Server Administrator's /Installation /Deployment Guides and SDK documentation (http://developer.netscape.com/docs/
manuals/directory.html).
RFC1823:The LDAP Application Program Interface, T. Howes,
M. Smith, 1995.
RFC2222:Simple Authentication and Security Layer (SASL), J. Myers, 1997.
RFC2251 .-Lightweight Directory Access Protocol (v3), M. Wahl, T. Howes, S.Kille, 1997.
RFC2252:Lightweight Directory Access Protocol (v3).-Attribute Syntax
Definitions, M.Wahl, A. Coulbeck, T. Howes, S. Kille, 1997.
RFC2254:The String Representation of LDAP Search Filters, T. Howes, 1997.
RFC2255:The LDAP URL Format, T. Howes, M. Smith, 1997.
RFC2256.-A Summary of the X.500(96) User Schema for use with
LDAPvS, M. Wahl, 1997.
The LDAP Data Interchange Format (LDIF)-Technical Specification (
), Gordon Good, 1999 ( http://
search.ietf.org/internet-drafts/draft-good-ldap-ldif-OX.txt, X -
).
Understanding and Deploying Ldap Directory Services, Tim Howes,
Mark Smith, Gordon Good (Macmillan Technical Publishing, 1998).
Understanding LDAP, Heinz Jonner, Larry Brown, Franz-Stefan Hin*
ner, Wolfgang Reis, Johan Westman, 1998.
LDAP (http://www.redbooks.ibm.com/ abstracts/sg244986.html).

ADSI
http://cwashington.netreach.net/ (6*1
Perl) ADSI
Microsoft.

263

http://www.microsoft.com/adsi
ADSI; ADSI SDK.
http://opensource.activestate.com/authors/tobyeverett - ADSI Perl .
http://www.15seconds.com- (
Perl) ADSI
Microsoft.
Windows 2000 Active Directory, by Alistair G. Lowe-Norris (O'Reilly,
1999).

SQL-
Perl
DBI
ODBC



SQL

, ,
?
, , Perl ,
:
1.
. ( ) , ;
. ,
Windows NT/2000 - , . (,
, Tivoli, HP Microsoft) . '
,
.
2. - . , ,
:
/

( . .)

SQL- Perl

265

? .
3. Perl - , , .
Perl , , ,
.
. Perl
, , Unix DBM, Berkeley DB . .,
. .
, ,
(SQL),
. Perl SQL, . .
SQL. SQL D
SQL. ,
, .
SQL- Perl
SQL-:
DBI (DataBase Interface) ODBC (Open DataBase Connectivity). DBI Unix, a ODBC - Win32, , ODBC Unix, a DBI Win32. DBD: : ODBC - DBD-, ODBC DBI.1
DBI ODBC , , .
DBI, ODBC , ,
, .
Sybperl (Michael Peppier), Perl Sybase.
DBI-. , Sybperl D B D : : Sybase. Win32 ActiveX (ADO),
6.

266

7.
(middleware). ,
, DBI/ODBC,
API - . ,
, , DBl/
ODBC. DBI DBD;
ODBC ODBC , ,
. . 7.1 DBI ODBC. :

DBI

Peri,

, DBIAPI ,

ODBC

API
DBI

...

OLE

. 7.1. DBI ODBC

1. (Oracle,
MySQL, Sybase, Microsoft SQL Server . .).
2. , ,
.
; . DBI
DBD.
Oracle DBD: .Oracle. DBD , .
ODBC ODBC-, .

SQL- Perl

267


Unix NT/2000
, , : Microsoft SQL Server Unix? Unix,
MS-SQL-
. .
SQL-,
Microsoft SQL-,
.
1. D B D : : Sybase. DBD: : Sybase
. , . - Sybase OpenClient - (,
Linux
Sybase Adaptive Server Enterprise). MS-SQL- 6.5 , DBD: :Sybase,
, .
7.0 , - Microsoft. http://support.Microsoft.com/support/kb/articles/
q239/8/83.asp (KB Q239883). - FreeTDS, http://
www.freetds.org. , .
2. D B D : : P r o x y . DBD
DBI. MS-SQL-
, - Unix-.
3. Unix ODBC DBD: :ODBC.
, MERANT (http://www.merant.com)
OpenLink Software (http://www.openlinksw.com),
;
, Open Source.
freeODBC
(Brian Jepson) http://users.ids.net/~bjepson/'freeODBC. ODBC Unix ( )
ODBC ( unixODBC 10DBC).

268

7. SQL
3.
(API).
Perl, . DBI
DBI (. . DBI-). ODBC
ODBC-
ODBC API.
, , DBI
ODBC, .
API- , .
. , , (. . ), , . .
,
.1 , , , .
, , , DBI ODBC. ,
,
.
, Perl . DBI MySQL; ODBC Microsoft SQL Server.

DBI
DBI.
DBI Programming the Perl DBI2
(Alligator Descartes) (Tim Bunce) (O'Reilly).
1:
, :
use DBI;

2:
Perl, DBI-
MySQL , '
:
MS-SQL Sybase,
.
, Perl DBI, -, 2000 .

DBI

269

# Sdatabase,
,
Sdatabase = "sysadm";
$dbh = DBI->connect("DBI:mysql:$database",$username,$pw);
die "! : $DBI::errstr\n" unless (defined
$dbh);
DBI DBD (DBD: :mysql). , ,
( connect()) . DBI connect () - R a i s e E r r o r Print E r r o r , , DBI , . , :
$dbh = DBI->connect("DBI:mysql:$database",
$username,$pw,{RaiseError => 1});
DBI die, ,
.
3: SQL-
, .
SQL-. , D. q (. . something
q{something}), , . DBI-, :
$results=$dbh->do(q{UPDATE hosts
SET bldg = 'Main 1
WHERE name = 'bendir'});
die " :$DBI::errstr\n" unless (defined
Sresults);
$ results ,
undef, . ,
,
, SELECT, .
, .
SQL ( prepare), (execute) . :
$sth = $dbh->prepare(q{SELECT * from hosts}) or
die "! :".$dbh->errstr."\n";
$rc = $sth->execute or
die "! :".$dbh->errstr."\n";

270

7. SQ[
( ) ,
: . ,
, SQL-, ( ). , execute .
.
, , ,
.
DBD (, , ) SQL-. ,
, .
. , DBI- do(), ,
(), execute().
do, , executeO
. , , . , , -1.
ODBC, (), DBD-,
(placeholders). , , , (executeO).
,
.
.
Perl, :
machines = qw(bendir shimmer sander);
$sth = $dbh->prepare(q{SELECT name, ipaddr FROM hosts WHERE name = ?});

foreach Sname (machines) {


$sth->execute($name);
----
, foreach, SELECT WHERE. "
:
$sth->prepare(
q {SELECT name, ipaddr FROM hosts

DBI

271

WHERE (name = ? AND bldg = ? AND dept = ?)});


$sth->execute($name,$bldg,$dept);
, , , , SELECT, ,
SELECT.
4: SELECT
, ,
D. executeO
SELECT, , .
DBI , . 7.1.
7.1. DBI-
,


fetchrow_arrayref() - undef
,

fetchrow_array()

, -

fetchrow_hashref()

, - undef
, -

fetchall_arrayref()

, .
,
:
$sth = $dbh->prepare(q{SELECT name, ipaddr, dept from hosts}) or
die " : ".$dbh->errstr. "\n";
$sth->execute or die " : ". $dbh->errstr. "\n";
f e t c h r o w _ a r r a y r e f ( ) :
while ($aref = $sth->fetchrow_arrayref){
print "name: " . $aref->[0] . "\n";
print "ipaddr: " . $aref->[1] . "\n";
print "dept: " . $aref->[2] . "\n";
DBI , f e t c h r o w _ h a s h r e f ( ) , fetchrow_arrayref ( ), - -

272

7. SQL
, " .
:
while ($href = $sth->fetchrow_hashref){
print "name: " . $href->{name} . "\n";
print "ipaddr: " . $href->{ipaddr}. "\n";
print "dept: " . $href->{dept} . "\n";
f e t c h a l l _ a r r a y r e f ( ) . , . , .
100 , .
, f e t c h r o w _ a r r a y r e f () (. 7.2).
:
$aref_aref = $sth->fetchall_arrayref;
foreach $rowref (@$aref_aref){
print "name: " . $rowref->[0]
print "ipaddr: " . $rowref->[1]
print "dept: " . $rowref->[2]
print ' - ' x 3 0 , " \ n " ;
, ,
. , ,
($rowref->[0]).
,
( ) . ,
$sth->{NUM_OF_FIELDS}, -

row
ref j

ref

|<

| row

row
ref

-j

row 1
ma .

aJ

[ columnl , column? , columns , column . 1


[columnl , coluinn2 , columns , column . . ]
[ columnl, column2 , columns, column. . ]
[ columnl , column2 , columns , column , . ]

Puc. 7.2. , fetchrow_arrayref

DBI

273

. $sth->{NAME} . :
$aref_aref = $sth->fetchall_arrayref;
foreach $rowref (@$aref_aref){
for ($1=0; $1 < $sth->{NUM_OF_FIELDS},$i++){
print $sth->{NAME}->[$i].": ".$rowref->[$i]."\n";
}
print '-'x30,"\n";
}
DBI,
.
5:
DBI :
# ,
(, . .
)
$sth->finish;
#
$dbh->disconnect;
DBI
, , ODBC. -, , (shortcut methods). , . 7.2, 3 4.
7.2. DBI


selectrow_arrayref($stmnt) prepare($stmnt), executeQ, f etch row_ar ray ref ()
selectcol_arrayref($stmnt) prepare($stmnt), execute(),
(@{fetchrow_arrayref()})[0]
(. . )
selectrow_array(Sstmnt)
prepare(Sstmnt), execute(),fetchrow_array()
-, DBI . b i n d _ c o l ( ) b i n d _ c o l u m n s ( )
.
, .
, bind_columns():
$sth = $dbh->prepare(q{SELECT name,ipaddr,dept from hosts}) or
die " :".$dbh->errstr".\n";
$rc = $sth->execute or

274

7. SQL
die " :".$dbh->errstr".\n";
1-, 2- 3- SELECT
$rc = $sth->bind_columns(\$name,\$ipaddr, \$dept);
while ($sth->fetchrow_arrayref){
# $name, $ipaddr $dept

----

ODBC
ODBC DBI.
1: Perl
use Win32: :ODBC;
2:
ODBC,
.
(Data Source Name, DSN). DSN - , (, ), , SQL-.
: (user) (system), ,
.1
DSN ODBC Windows
NT/2000, Perl.
, ,
Unix. MS-SQL:
# Microsoft-SQL-
# : ,
ODBC_ADD_DSN ODBC_ADD_SYS_DSN
if (Win32:: ODBC ::ConfigDSN(
ODBC_ADD_DSN,
"SQL Server",
("DSN=PerlSysAdm",
DESCRIPTION=DSN for PerlSysAdnf ,
- (file), DSN , . Win32::ODBC = > DSN .

ODBC

275
"SERVER=mssql.happy.edu", #
"ADDRESS=192.168.1.4",
# IP-
"DATABASE=sysadm",
ft

"NETWORK=DBMSSOCN",
# TCP/IP
))){
print "DSN \";
}

else {
die " DSN:" . Win32::ODBC::Error() . "\n";
}

, :
DSN,
$dbh=new Win32::ODBC("DSN=PerlSysAdm;UID=$username;PWD=$pw;");
die " DSN PerlSysAdm:" . Win32::ODBC::Error() ..
"\n"
unless (defined $dbh);
: SQL
ODBC- DBI- do(), prepare() execute()
, W i n 3 2 : :ODBC S q l ( )
. ODBC , W i n 3 2 : : ODBC. 1 W i n 3 2 : : ODBC ; , new.
:
$rc = $dbh->Sql(q{SELECT * from hosts});
ODBC DBI:
do() DBI, Sql() undef, , ,
.
, INSERT, DELETE UPDATE, RowCount(). Win32: :ODBC , ODBC (
SQL), , . execute()
, ,
Win32: : ODBC, . DBI (. . (),
Sql()), ODBC. http://www.roth.net.

276

7. SQL
DBI, RowCount() -1,
.
d o ( ) ODBC:
if (defined $dbh->Sql(q{UPDATE hosts
SET bldg = 'Main'
WHERE name = 'bendir'})){
die " : ".Win32::ODBC::Error()."\n"
>
else {
Sresults = $dbh->RowCount();
}
4: SELECT
SELECT ODBC , DBI, . ,
W i n 3 2 : : ODBC. FetchRow() , 1, , undef, - . ,
, .
Data() , , , , . D a t a ( )
, , (, , ).
D a t a H a s h ( ) ,
. DBI- f e t c h r o w _ h a s h r e f (),
, , .
Oata(), D a t a H a s h ( ) , .
:
if ($dbh->FetchRow()){
@ar = $dbh->Data();
---- @
}
:
if ($dbh->FetchRow()){
%ha = $dbh->DataHash('name','ipaddr');
-----${)--${111}
}
, , {NAME} DBI,
W i n 3 2 : :ODBC FieldNames(). -

277

( {NUM_OF_FIELDS}),
, FieldNames().
5:
$dbh->close();
, , , ,
:
# ODBC_REMOVE_DSN ODBC_REMOVE_SYS_DSN,
#
if (Win32::ODBC::ConfigDSN(ODBC_REMOVE_DSN,
"SQL Server","DSN=PerlSysAdm")){
print "DSN \";
}
else {
die " DSN:".Win32::ODBC::Error()."\n";
}
, Perl, DBI
ODBC. .

SQL-
, .
.
, , .
. .
(nonportable)
,
SQL-
DBI, ODBC. :
,
.
. , , NULL
NOT NULL. :
---sysadm
hosts
name [char(30)j
ipaddr [char(15)]

7. SQ|_

[78

aliases [char(50)]
owner [char(40)]
dept [char(15)]
bldg [char(10)]
room [char(4)]
manuf [char(10)]
model [char(10)]
hpotter
customers
cid [char(4)]
cname [varchar(13)]
city [varchar(20)]
discnt [real(7)]
agents
aid [char(3)]
aname [varchar(13)]
city [varchar(20)]
percent [int(10)]
products
pid [char(3)]
pname [varchar(13)]
city [varchar(20)]
quantity [int(10)]
price [real(7)]
orders
ordno [int(10)]
month [char(3>]
cid [char(4)]
aid [char(3)]
pid [char(3)]
qty [int(10)]
dollars [real(7)]
MySQL DBI
MySQL
DBI. MySQL
SHOW :
use DBI;

print " : ";


chomp($user = <STDIN>);
print " $user: ";
chomp($pw = <STDIN>);
$start = "mysql"; #
8
$dbh = DBI->connect("DBI:mysql:$start",$user,$pw);
die " : ".$DBI::errstr."\n" unless (defined $dbh);
II

279

#
$sth=$dbh->prepare(q{SHOW DATABASES}) or
die " show databases: ". $dbh->errstr. "\n"
$sth->execute or
die " show databases: ". $dbh->errstr. "\n";
while ($aref = $sth->fetchrow_arrayref ) {
push(@dbs,$aref->[0]);
}
$sth->finish;
#
foreach $db (@dbs) {
print "- $db \n";
$sth=$dbh->prepare(qq{SHOW TABLES FROM $db}) or
die " show tables: ". $dbh->errstr. "\n"
$sth->execute or
die " show tables: ". $dbh->errstr. "\n";
@tables=();
while ($aref = $sth->fetchrow_arrayref ) {
push(@tables, $aref->[0]);
$sth->finish;
9
foreach Stable (tables) {
print "\t$table\n";
$sth=$dbh->prepare(qq{SHOW COLUMNS FROM Stable FROM $db}) or
die " show columns: ". Sdbh>errstr. "\n";
$sth->execute or
die " show columns: ". $dbh->errstr. "\n"
while (Saref = $sth->fetchrow_arrayref) {
print "\t\t",$aref->[0], " [",$aref->[1], "]\n";
$sth->finish;
$dbh->disconnect;

,
DBI ,
SHOW. .

280

7. SQL

, SHOW TABLES SHOW COLUMNS


, . , DBD / ( ,
). .

, (
, , , ) . .
- T e r m : : Read key, .

Sybase DBI
Sybase. , :
use DBI;

print " : ";


chomp($user = <STDIN>);
print " $user: ";
chomp($pw = <STDIN>);
$dbh = DBI->connect('dbi:Sybase:',$user,$pw);
die " : $DBI::errstr\n"
unless (defined $dbh);
#
$sth = $dbh->prepare(q{SELECT name from master.dbo.sysdatabases}) or
die " sysdatabases: ".$dbh->errstr."\n";
$sth->execute or
die " sysdatabases: ".$dbh->errstr."\n";
while ($aref = $sth->fetchrow_arrayref) {
push(<s>dbs, $aref->[0]);
}
$sth->finish;
foreach $db (@dbs) {
$dbh->do("USE $db") or
die " $db: ",$dbh->errstr."\n";
print " -$db---\n";
#
$sth=$dbh->prepare(q{SELECT name FROM sysobjects WHERE type="U"}) or
die " sysobjects: ".$dbh->errstr."\n";

281

$sth->execute or
die " sysobjects: ". $dbh->errstr. "\n";
@tables=();
while ($aref = $sth->fetchrow_arrayref ) {
push(@tables, $aref->[0]);
>
$sth->finish;
""
$dbh->do("use $db") or
die " $db: ".$dbh->errstr. "\n";
8
foreach Stable (tables) {
print "\t$table\n";
$sth=$dbh->prepare(qq{EXEC sp_columns Stable}) or
die " sp_columns: ".$dbh->errstr. "\n";
$sth->execute or
die " sp_columns: ".$dbh->errstr. "\n";
while ($aref = $sth->fetchrow_arrayref ) {
print "\t\t",$aref->[3], " [-',$aref->[5], "(",
$aref->[6],")]\n";
}
$sth->finish;
$dbh->disconnect or
warn " : ",$dbh->errstr. "\n";
:

Sybase sysdatabases sysobjects.


sysobjects,
sysdatabases, .
databases, owner, table SELECT, .
sysobjects , USE. , cd, .

SELECT sysobjects WHERE,


. .
,
:
WHERE type="U" AND type="S"

282

7. SQL
, DBD : : Sybase , . , EXEC sp_columns.

MS-SQL ODBC
, MS-SQL
ODBC. , SQL
Sybase/MS-SQL.
:
DSN, , , sysdatabases.
$dbh~>DropCursor( ) $sth->f inish.

,
. - Win32 : : ODBC.

:
use Win32: :ODBC;
print " : ";
chomp($user = <STDIN>);
print " $user: ";
chomp($pw = <STDIN>);
$dsn="sysadm"; tt ,
DSN, $dsn,
die " DSN", Win32: -.ODBC: :Error(). "\n"
unless (%dsnavail = Win32: ; ODBC: :DataSources());
if (! defined $dsnavail{$dsn}) {
die " DSN:". Win32: :ODBC: :Error(). "\n"
unless (Win32: :ODBC: :ConfigDSN(ODBC_ADD_DSN,
"SQL Server",
("DSN=$dsn",
"DESCRIPTION=DSN for PerlSysAdm",
"SERVER=mssql. happy . edu" ,
"DATABASE=master",
"NETWORK=DBMSSOCN", TCP/IP

#
$dbh = new Win32: :ODBC("DSN=$dsn;UID=$user;PWD=$pw; ");
die " DSN $dsn: ".Win32: :ODBC: :Error(). "\n"

283

unless (defined $dbh);

|'

#
if (defined $dbh->Sql(q{SELECT name from sysdatabases})){
die " :". Win32: :ODBC: :Error(). "\n";
while ($dbh->FetchRow()){
push(@dbs, $dbh->Data("name"));
}
$dbh->OropCursor();
#
foreach $db (@dbs) {
if (defined $dbh->Sql("use $db"))<
die " $db:" .
Win32: :ODBC::Error() . "\n";
}
print " -$db---\n";
@tables=();
if (defined $dbh->Sql(q{SELECT name from sysobjects
WHERE type="U"})){
die " $db:" .
Win32: :ODBC::Error() . "\n";
}
while ($dbh->FetchRow()) {
push (tables, $dbh->Data( "name"));
}
$dbh->DropCursor();
#
foreach Stable (@tables) {
print "\t$table\n";
if (defined $dbh->Sql(" {call sp_columns (\'$table\' )} ")){
die "
Stable .-".Win32:: ODBC ::Error() . "\n";
}
while ($dbh->FetchRow()) {
@cols=();
@cols=$dbh->Data("COLUMN_NAME",
"TYPE_NAME", "PRECISION");
-1
print "\t\t",$cols[0], [",$cols[1],"(",$cols[2],")]\n";
}

$dbh->DropCursor();
$dbh->Close();
die " DSN: ".Win32: : ODBC: :Error( ). "\n"
unless (Win32: :OD6C: :ConfigDSN(ODBC_REMOVE_DSN,
"SQL Server", "DSN=$dsn"));

284

7. SQL.


,
,
, ,
. ,
. ,
, Sybase
( ) , . ,
:
use DBI;

: syaccreate <username>
$admin = '' ;
print " Sadmin: ";
chomp($pw = <STDIN>);
$user=$ARGV[0];
ft * ,
# , ,
, 6
$genpass = reverse join(' ', reverse split(//,$user));
Sgenpass .= "-" x (6-lengtn($genpass));
# SQL-,
ft : 1) USER_DISK
#
USER_LQG

2)

3)
ft 4)
commands = ("create database Suser on USER_DISK=5 log on USER_LOG=5",
"sp_addlogin $user,\"$genpass\", $user",
"use Suser",
"sp_changedbowner $user");
#
$dbh = OBI->connect( 'dbi:Sybase: ' ,$admin,$pw);
die " : $DBI: :errstr\n"
unless (defined $dbh);

,
I

#
for (^commands) {
$dbri->do($_) or die "He $_: " . $dbh->errstr . "\n";
$dbh->disconnect;

285

, , ,
$dbh->do(). , :
use DBI;

: syacdelete <username>
Sadmin = 'sa';
print " Sadmin: ";
Chomp($pw = <STDIN>);
$user=$ARGV[0];
SQL-, ;
# :


@commands = ("drop database $user",
"sp_droplogin $user");
#
$dbh = DBI->connect('dbi:Sybase:', Sadmin, $pw);
die " : $DBI::errstr\n"
unless(defined $dbh);
# ,
for (@commands) {
$dbh->do($_) or die " $_: " . $dbh->errstr . "\n";
\/
$dbh->disconnect or
warn " : " . $dbh->errstr . "\n";
, , . :


; , ( , ,
).

,
.

.

286

7. SQ|_


SQL-.
,
5 TCP/IP.

,
- .
, , .
, , . DBI,
Sybase.
, , .
,
. d , , 1 - .
( ):
Iddddddd
1
|

|15.23%/5MB
|
|0.90%/5

Iddddddd
|

|15.23%/5MB
I
|1.52%/5

hgranger

Idddddddd
1
|

|16.48%/5MB
|
11.52%/5

rweasley

Iddddddd
1
|1

|15.23%/5MB
I
|3.40%/5

|ddddddddddddddddddddddddddd
1

|54.39%/2
I

I- no log

hpotter

dumbledore

hagrid

:
use DBI;

$admin = 'sa';
print " $admin: ";
chomp($pw = <STDIN>);
Spages = 2 ; ft 2-

287

9
$dbh = DBI->connect('dbi:Sybase:',$admin,$pw);
die " : $DBI::errstr\n"
unless (defined $dbh);
9
$sth = $dbh->prepare(q{SELECT name from sysdatabases}) or
die " sysdatabases: ".$dbh->errstr."\n";
$sth->execute or
die " sysdatabases: ".$dbh->errstr."\n";
while ($aref = $sth->fetchrow_arrayref) {
push(@dbs, $aref->[0]);
}
$sth->finish;

foreach $db (@dbs) {
9 size
9 ,
$size
= &querysum(qq{SELECT size FROM master.dbo.sysusages
WHERE dbid = db_id(V$db\')
AND
segmap != 4});
9 size ,

$logsize = &querysum(qq{SELECT size FROM master.dbo.sysusages
WHERE dbid = db_id(\-$db\')
AND
segmap =4});
#
9
$dbh->do(q{use $db}) or
die " $db: ".$dbh->errstr."\n";
# reserved_pgs,
9 , (doampg)
9 (ioampg)
$used=&querysum(q{SELECT reserved_pgs(id,doampg)+reserved_pgs(id,ioampg)
.FROM sysindexes
WHERE id != 8});
9 ,
9
$logused=&querysum(q{SELECT reserved_pgs(id, doampg)
FROM sysindexes
WHERE id=8});
9
&graph($db,$size,Slogsize,Sused,$logused);
}
$dbh->disconnect;

9 / SELECT,

288

7. SQi
sub querysum {
my($query) = shift;
my($sth,$aref,$sum);
$sth = $dbh->prepare($query) or
die " Squery: ".$dbh->errstr."\n";
$sth->execute or
die " Squery: ".$dbh->errstr."\n";
while ($aref=$sth->fetchrow_arrayref) {
$sum += $aref->[0];
$sth->finish;
$sum;
ft , ,
ft
sub graph {
my($dbname,$size,$logsize,$used,Slogused) = @_;
(f
print ' '15 . T - ' d ' x (50 *($used/$size)) .
' ' (5Q-(50*($used/$size))) . ) ;
,
printf("%,2f",($used/$size*100));
print "%/". (($size * $pages)/1024)."MB\n";
print Sdbname.'-'x(14-length($dbname)).'-|'.(' 'x 49)."|\n";
if (defined Slogsize) { ft
ft
print ' '15 . ' '1' (50 *($logused/$logsize)) .
' ' (50-(50*($logused/$logsize))) . ';
ft ,
ft
printf("%.2f",($logused/$logsize*100));
print "%/". ((Slogsize * $pages)/1024)."MB\n";
else { ft
ft
print ' '15 . "|- no log".(' ' 41)."|\";
print "\n";
, SQL, , , ( q u e r y s u m )
,
SUM SQL. q u e r y s u m ( ) ,
Perl. Perl , , . , , ,

289

Perl,
( ).
?
, SQL- Perl, :
SQL Perl? SQL- (, SUM()) Perl
.
, DISTINCT,
, Perl,
Perl.
, ,
, .
, :

?

?

, ( )?
,
?
,
.


SQL-
DBI
, SQL-. ,
.
:
use DBI;

Ssyadmin = "sa";
print " Sybase: ";
chomp($sypw = <STDIN>);

290

7. SQi
Smsadmin = "sa";
print " MS-SQL: ";
chomp($mspw = <STDIN>);
tt Sybase
Ssydbh = DBI->connect( "dbi : Sybase : serve r=SYBASE" , Ssyadmin, $sypw) ;
die " Sybase: $DBI: :errstr\n"
unless (defined $sydbh);
tt ChopBlanks,
$sydbh->{ChopBlanks} = 1;
MS-SQL ( ,
DBD: :Sybase! )
Smsdbh = DBI->connect( "dbi : Sybase : server=MSSQL" , Smsadmin, Smspw) ;
die " mssql: $DBI: :errstr\n"
unless (defined Smsdbh);
tt ChopBlanks,
$msdbh->{ChopBlanks} = 1;
$|=1; it STDOUT
ft ,

$SIG{INT} = sub {Sbyebye = 1; };
if ,
ft
while (1) {
last if ($byebye);
ft spjnonitor
Ssysth = $sydbh->prepare(q{sp_monitor}) or
die " sy spjnonitor:". $sydbh->errstr. "\n";
$systh->execute or
die " sy sp_monitor:".$sydbh->errstr. "\n";
tt .
, , ,
cpu_busy
while($href = $systh->fetchrow_hashref or
$systh->{syb_more_results}) {
, ,
last if (defined $href->{cpu busy});
}
$systh->finish;
tt , %, ,
#
for (keys %{$href {
$href->{$J =' s/.-(\
tt
$info = "Sybase: (" . $href ->{cpu_busy} . " CPU), "

"I
^

291

"(".$href->{io_busy}. " 10), ".


"(".$href->{idle}. " idle) ";
# ,
# (MS-SQL)
$mssth = $msdbh->prepare(q{sp_monitor}) or
die " ms sp_monitor:".$msdbh->errstr. "\n";
$mssth->execute or
die " ms sp_monitor:".$msdbh->errstr. "\n";
while($href = $mssth->fetchrow_hashref or
$mssth->{sybjnore_results}) {
, ,
last if (defined $href->{cpu_busy});
>
$mssth->finish;
tt , %
for (keys %{$href}) {
$href->{$_} =- s/.
$info .= "MSSQL: (" . $href->{ 'cpu_busy' }. " CPU), ".
"(".$href->{'io_busy'}." 10), ".
"(".$href->{iidle'}." idle)";
print " "x78, "\r";
print $info, "\r";
sleep(5) unless (Sbyebye);
n ,
$sydbh->disconnect;
$msdbh->disconnect;
:
Sybase: (33% CPU), (33% 10), (0% idle)

MSSQL: (0% CPU), (0% 10), (100% idle)

sp_monitor,
Sybase-, MS-SQL-. sp_monitor :
last_run

current_run

Aug 3 1998 12:05AM

Aug 3 1998 12:05AM

cpu_busy

io_busy

0(0)-0%

0(0)-0%

seconds
1
idle
40335(0)-0%

292

7. SQ^
packets_received

packets_sent

1648(0)

1635(0)

packet_errors
0(0)

total_read

total_write

total_errors

connections

391(0)

180(0)

0(0)

11(0)

, spjnonitor
Sybase, MS-SQL: . . DBD:: Sybase ,
. :
while($href = $systh->fetchrow_hashref or
$systh->{syb_more_results}) {
,
:
# , ,
last if (defined $href->{cpu_busy});
,
( , <Ctrl>+<C> ). ,
, , .
perlipc . INT , .
, .1
, . ,
sp_monitor , ,
, '
... .
before shuffling off this mortal coil - 3
: When we have shuffled off this mortal coil... -
. :
.... . .

293


CPAN
TIMB

DBI

: :mysql)
DBD::Sybase

1.13

JWIED

1.2210

MEWP

0.21

W i n 3 2 : :ODBC ( http://www.roth.net) GBARR

970208


SQL

http://w3.one.net/~jhoffman/sqltut.htm - SQL (James Hoffman); , SQL.


DBI

Advanced Perl Programming, Sriram Srinivasan (O'Reilly, 1997).


http://www.symbolstone.org/technology/perl/DBI/index.html DBI; .
Programming the Perl DBI, Alligator Descartes, Tim Bunce (O'Reilly,
2000).
ODBC
http://www.microsoft.com/odbc - ODBC Microsoft.
ODBC
ODBC MDAC SDK http://msdn.microsoft.com.
http://www.roth.net/perl/odbc/ - W i n 3 2 : :.
Win32 Perl Programming: The Standard Extensions, Dave Roth (Macmillan Technical Publishing, 1999). W i n 3 2 : : ODBC, Win32 Perl.

http://sybooks.sybase.com - Sybase .
Sybase/MS-SQL, .
SQL.
http://www.mbay.net/~mpeppler/ - ( SybPerl D B D : : Sybase). Sybase, .

, - , . ,
Perl .
Perl ,
, . - -: , - ;
(, ),
-, . , Perl, ,
.
, Perl , . Perl 0
.
, ,
. , , , IETF . SMTP ( , RFC821),
RFC822. .

,
. ( Unix) Perl-

295

,
:
, sendmail
open(SENDMAIL, "|/usr/lib/sendmail -oi -t -odq") or
die " sendmail: $!\n";
print SENDMAIL "EOF";
From: <me\@host>
To: <you\@otherhost>
Subject:

.
EOF
close(SENDMAIL) or warn " sendmail ";
Perl 5 ( Perl 4), , , .
:
Saddress = "fred@example.com";
,
:

$address="fred\@example.com";
$address='fred@example.com';
$address= join('@', ' f r e d 1 , 'example.com');
, sendmail, ,
,
sendmail (,
NT MacOS), .
.
sendmail
( )
Win32, , . .
sendmail, Win32:
sendmail, Win32:

sendmail Cygwin (http://dome/weeg.uiowa.edu/pub/domestic/sos/ports)

sendmail Mercury Systems (http://www.demobuilder.com/sendmail.htm)


Sendmail for NT Sendmail, Inc. (http://
www.sendmail.com)

296

8.
, - Perl,
, , .
Win32:

blat (http://www.interlog.com/~tcharron/blat.html)
netmail95
mail.html)

(http://www.geocities.com/SiliconValley/Lakes/2382/net-

wmailto (http://www.impaqcomp.com/jgaa/wmailto.html)

, 3
.
() , ,
( Mail eXchanger DNS
), ,
. .
Perl, .
IPC,

MacOS Windows NT , IPC (Interprocess Communication, ).
sendmail MacOS,
AppleScript:
$to="someone\@example.com";
$from="me\@example.com";
$subject="Hi there";
$body="message body\n";
MacPerl: :DoAppleScript(EOC);
tell application "Eudora"
make message at end of mailbox "out"
-- 0 is the current message
set field \"fron\" of message 0 to \"$from\"
set field \"to\" of message 0 to \"$to\"
set field \"subject\" of message 0 to \"$subject\"
set body of message 0 to \"$body\"
queue message 0
connect with sending without checking
quit
end tell
EOC

297

AppleScript, Eudora.
, ,
.
, , : : Glue,
2 .
use Mac::Glue ':glue';
$e=new Mac::Glue 'Eudora';
$to="someone\@example.com";
$from="me\@example.com";
$subject="Hi there";
$body="message body";
$e->make(
new => 'message',
at => location(end => $e->obj(mailbox => 'Out'))
);
$e->set($e->obj(field => from
$e->set($e->obj(field => to
$e->set($e->obj(field => subject
$e->set($e->prop(body => message

=> message => 0), to => $from);


=> message => 0), to => $to);
=> message => 0), to => $subject);
=> 0), to => $body);

$e->queue($e->obj(message => 0));


$e->connect(sending => 1, checking => 0);
$e->quit;
NT Collaborative Data Objects Library ( Active Messaging), MAPI ( ).
, Outlook , W i n 3 2 : ; OLE :
$to="me\@example.com";
$subject="Hi there";
$body="message body\n";
use Win32::OLE;
ft OLE COINIT_OLEINITIALIZE,
8 MAPI.Session
Win32::OLE->Initialize(Win32::OLE::COINIT_OLEINITIALIZE);
die Win32::OLE->LastError(), "\n" if Win32::OLE->LastError();
ft , Logoff

298

8.
my Ssession = Win32::OLE->new('MAPI.Session','Logoff');
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
, OL98 Internet Profile
$session->Logon('Microsoft Outlook Internet Settings');
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
tt message
my Smessage = $session->Outbox->Messages->Add;
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
ft recipient
my $recipient = $message->Recipients->Add;
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
tt recipient
$recipient->{Name} = $to;
$recipient->{Type} = 1 ; tt 1 = "To:", 2 = "Cc:", 3 = ":"
ft
tt ( , , )
tt ,
ft recipient
$recipient->Resolve();
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
tt Subject:
$message->{Subject} = Ssubject;
$message->{Text} = $body;

8 1- =
tt 2- =
tt
ft 3- = , 2- True
$message->Send(0, , );
die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();
Ssession, $session->Logoff
undef Ssession;
,
. ( Outlook)
( Exchange) . CDO/AM 1.1 -
Session DeliverNowO, MAPI
. , ,
.

299

MAPI
OLE. MAPI,
, W i n 3 2 : :1,
( http://www.generation.net/
-aminer/Perl/ ).
, AppleScript/Apple Events MAPI,
, sendmail.
, .
.

- ,
. RFC821. SMTP
(Simple Mail Transfer Protocol, ).
, , :
X telnet example.com 25

-- SMTP-
example.com

Trying 192.168.1.10 . . .
Connected to example.com.
Escape character is ' " ] ' .
220 mailhub.example.com ESMTP Sendmail 8 . 9 . 1 a / 8 . 9 . 1 ; Sun, 11 Apr 1999
15:32:16 -0400 (EOT)
HELO client.example.com
-- ,
( EHLO)
250 mailhub.example.com Hello dnb@client.example.com [192.168.1.11], pleased
to meet you
MAIL FROM: <dnb@example.com>
-
250 <dnb@exarnple.com>... Sender ok
RCPT TO: <dnb@example.com>
--
250 <dnb@example.com>,.. Recipient ok
DATA
- ,
354 Enter mail, end with " . " on a line by itself
From: David N. Blank-Edelman (David N. Blank-Edelman)
To: dnb@example.com
Subject: SMTP -
, SMTP.
,
dNb
--
250 26624 Message accepted for delivery
QUIT
--
221 mailhub.example.com closing connection
Connection closed by f o r e i g n host.

300

8.
. Socket - N e t : : Telnet, 6
.
, .
(JendaKrynicky) Mail: '.Sender, Mail: :Sendmail (Milivoj Ivkovic) Mail::Mailer MailToois
(Graham Barr). , Perl. Mail::Mailer,
, .
- , :
use Mail::Mailer;
$from="me\@example.com";
$to="you\@example.com";
$subject="Hi there";
$body="message body\n";
$type="smtp";
$server="mail.example.com";
my Smaller = Mail::Mailer->new($type, Server => Sserver) or
die " mailer:$!\n";
$type :
smtp
, N e t : : SMTP ( libnet), -Unix Perl. MailToois 1.13 ,
SMTP-, =>. , libnet.
mail
mall (
, ).
AppleScri.pt MAPI.
sendmail
sendmail,
.
, PERL_MAILERS,
, (, sendmail) .

301

open () Mai . -.Mailer .


:
$mailer->open({From => $from,
=> $to,
Subject => $subject}> or
die " mailer:$!\n";
,
:
print Smailer Sbody;
$mailer->close;
, Perl
.
, $type , ( ) , , . smtp, , , .
. , .


,
.
, , , , .
, . , ,
. ,
, .

-
. , , , . - -
, - -

302

8.
. ,
- 0
. , .
, .

- , . , :
$last_sent = time;
N
Unix NT,
, ,
. , 1
.

. (exponential backoff):
$max = 24*60*60; # (1 )
$unit = 60;
# (1
)
# ,
# 2,
# .
#
sub time_closure {
my($stored_sent,$stored_power)=(0,-1);
return sub {
(($stored_sent,$stored_power) = @_) if @_;
[$stored_sent,$stored_power];

};
$last_data=&time_closure; #
# ""
8
sub expbackoff <
my($last_sent,$last_power) = @{&$last_data};
# true,
# ,

5|1

303

. true,
#
, ,
if (!$last_sent or
($last_sent +
(($unit * 2**$last_power >= $max) ?
$max : $unit 2**$last_power) <=
&$last_data(time(),++$last_power);
return 1;
}
else {
return 0;

expbackoff() t r u e (1),
, false (0), . true, ,
t r u e .
,
(closure) , . .
,

, ,
. , ,
.
&time_closure() , , . ,
: &$last_data. , , :
my($last_sent,$last_power) = @{&$last_data};
, :
, $stored_sent $stored_power ( my()), . $stored_sent $stored_power . ,
. :
#
$last_data=&time_closure;

304

8.
# ,
&$last_data(1,1);

$stored_sent = $stored_power = 2;
,
print "@{&$last_data}\n";
"1 1 " , ,
$stored_sent $stored_power. ,
, , .

,)|


. ,
, .
: ,
. ,
, , ,
. , ,
.
. , , .
, .
.
, ,
:
$ = 60*60*24; (1 )
$min = 60*5;
# (5 )
$unit = 60;
(1
$start_power = int log($max/$unit)/log(2);
sub time_closure {
my($last_sent, $last_power)=(0,$start_power+1);
return sub {
(($last_sent,$last_power) = @_) if @_;
keep exponent positive
$last_power = ($last_power > 0) ? $last_power : 0;
[$last_sent,$last_power];

$last_data=&time_closure; #

305

# true
#
sub exprampup {
my($last_sent,$last_power) = @{&$last_data};
# true,
# ,
ft ,
# 2,

if (!$last_sent or
($last_sent +
(($unit * 2**$last_power <= $min) ?
$min : $unit * 2**$last_power) <=
&$last_data(time(),++$last_power1);
return 1;
}
else {
return 0;


(&$last_data), ,
. , ,
. ,
, , , ,
.

-
. , - . ,
. .
. ,
,
. 2
1

--$last_power. . - . . .
- .

306

8.
, . :
- -- --
, , :
use Mail: : Mailer;
use Text: :Wrap;
ft ,
$repolist = "/project/machinelist";
ft ,
Srepodir = "/project/reportddir";
ft , .
ft File: :Spec
$separator= "/";
# ""
$reportf romaddr = "project\@example.com";
#
$reporttoaddr
= "project\@example.com";
ft .
ft , ,
ft
open(LIST, $repolist) or die " $repolist:$!\n";
while(<LIST>){
chomp;
$missing{$_}=1;
$machines++;
ft
ft :
ft
opendir(REPO, $repodir) or die " $repodir:$!\n";
while(defined($statfile=readdir(REPO))){
next unless -f $repodir.$separator.$statfile;
ft
open(STAT, $repodir. $separator. $statf ile)
or die " $statfile:$!\n";
chomp($report = <STAT>);
(Shostname, Sresult, $details)=split( ' ' , Sreport, 3);
warn " $statfile ,
Shostname! \n"
if($hostname ne $statfile);

307

#
delete $missing{$hostname};

if ($result eq "success")!
$success{$hostname}=$details;
$succeeded++;
}
else {
$fail{$hostname}=$details;
$failed++;
}
close(STAT);
}
closedir(REPO);

#
if (Ssucceeded == $machines){
$subject = "[report] Success: Smachines";
>
elsif (Sfailed == $machines or scalar keys %missing >= Smachines) {
Ssubject = "[report] Fail: $machines";
}
else {
Ssubject = "[report] Partial: Ssucceeded ACK,
Sfailed NACK".
((%missing) ? ", ".(scalar keys %missing)1. " MIA" : "");
mailer
$type="sendmail";
my $mailer = Mail: :Mailer->new($type) or
die " :$!\" ;
$mailer->open({From=>$reportfromaddr, To=>$reporttoaddr, Subject=>$subject})
or
die " mailer:$!\n";
#
print Smaller "Run report from $0 on " . scalar localtime(time) . "\n";
if (keys %success){
print Smaller "\n==Succeeded==\n";
foreach Shostname (sort keys %success){
print Smaller "Shostname: $success{$hostname}\n";

- ,
. - . . .

308

8.
if (keys %fail){
print Smaller "\n==Failed==\n";
foreach $hostname (sort keys %fail){
print Smaller "Shostname: $fail{$hostname}\n";

if (keys %missing){
print Smaller "\n==Missing==\n";
print Smaller wrapf"', "", join(" ".sort keys %missing)), "\n";
it
$mailer->close;
,
. , , , , , .
. , .
:
Date: Wed, 14 Apr 1999 13:06:09 -0400 (EOT)
Message-Id : <1 99904141706 . NAA08780@example . com>
Subject: [report] Partial: 3 ACK, 4 MACK, 1 MIA
To: project@example.com
From: project@example.com
Run report from reportscript on Wed Apr 14 13:06:08 1999
==Succeeded==
barney: computed 23123 oogatrons
betty: computed 6745634 oogatrons
fred: computed 56344 oogatrons
==Failed==
bambam: computed 0 oogatrons
dino: computed 0 oogatrons
pebbles: computed 0 oogatrons
wilma: computed 0 oogatrons
==Missing==
mrslate
, '
. .
.
:

309

use 10::Socket;
use Text::Wrap; #

# ,
Srepolist = "/project/machinelist";
#
Sserverport = "9967";
&loadmachines; tt
#
$reserver = 10::Socket::INET->new(LocalPort => $serverport,
Proto
=> "tcp",
Type
=> SOCK_STREAM,
Listen
=> 5,
Reuse
=> 1)
or die " : $!\";
#
while(($connectsock,$connectaddr) = $reserver->accept()){
#
$connectname = gethostbyaddr((sockaddr_in($connectaddr))[1],AF_INET);
chomp($report=$connectsock->getline);
($hostname,$result,$details)=split(' ',$report,3);
# ,
#
/
if (Shostname eq "DUMPNOW"){
&printmail($cormectsock);
close($connectsock);
undef %success;
undef %fail;
Ssucceeded = $failed = 0;
&loadmachines;
next;
warn "$connectname , $hostname!\n"
if($hostname ne Sconnectname);
delete $missing{$hostname};
if (Sresult eq "success"){
$success{$hostname}=$details;
$succeeded++;

}
else {
$fail{$hostname>=$details;
$failed++;

310 _ ^

__

8.

close($connectsock);
}
close($reserver);
tt
sub loadmachines {
undef %missing;
undef Smachines;
open(LIST, Srepolist) or die " $repolist:$!\n"
while(<LIST>){
chomp;
$missing{$_}=1;
$machines++;

. - ,
-
sub printmail{
($socket) = $_[0];
if (Ssucceded == $machines){
Ssubject = "[report] Success: $machines";
}
elsif ($failed == Smachines or scalar keys %missing >= Smachines) {
Ssubject = "[report] Fail: $machines";
}
else {
Ssubject = "[report] Partial: Ssucceeded ACK, Stalled NACK".
((%missing) ? ", ".(scalar keys %missing)V MIA" : "");
print Ssocket "$subject\n";
print Ssocket "Run report from $0 on ".scalar localtime(time)."\n";
if (keys %success){
print Ssocket "\n==Succeeded==\rf;
foreach Shostname (sort keys %success){
print Ssocket "Shostname: $success{$hostname}\n";

if (keys %fail){
print Ssocket "\n==Failed==\n";
foreach Shostname (sort keys %fail){
1

- ,
. - . . .

311

print Ssocket "$hostname: $fail{$hostname}\n";

if (keys %missing){
print $socket "\n==Missing==\n";
print Ssocket wrapf", "", join(" ",sort keys %missing)), "\n";

, , .
10 : : Socket , .
(10: : Socket ->new()), , (10 : : Socket->accept( )). ( ) ,
. , . .
, ,
.
- DUMPNOW. ,
, -. , ,
. ,
:
use 10: :Socket;
#
Sserverport = "9967";
tt
Sservername = "reportserver";
# IP-
Sserveraddr = inet_ntoa(scalar gethostbyname($servername));
Sreporttoaddr = "project\@exairiple.com";
Sreportf romaddr = "project\@example.com";
$reserver = 10: :Socket: :INET->new(PeerAddr => Sserveraddr,
PeerPort => $serverport,
Proto
=> "tcp",
Type
=> SOCK_STREAM)
or die " :: $!\";
if ($ARGV[0] ne "-m"){
print $reserver $ARGV[0];

312

8.
else {
use Mail: -.Mailer;
print $reserver "DUMPNOW\n";
chomp($subject = <$reserver>);
$body = join("",<$reserver>);
$type="sendmail";
my $mailer = Mail: :Mailer->new($type) or
die " mailer :$!\n";
$mailer->open({
From => $reportf romaddr,
To => Sreporttoaddr,
Subject => Ssubject
}) or
die " mailer :$!\n";
print Smaller $body;
$mailer->close;
close($reserver);
. . (
$ARGV[0]) . - ,
, ,
, .
-, DUMPNOW
. Mail: : Mailer , .
, ,
. , , ( ,
), ( ,
?), - . ,
. ,
.
Advanced Perl Programming (
Perl) (Sriram Srinivasan) Perl Cookbook
(Perl: ) (Tom Christiansen) (Nathan Torkington),

313

O'Reilly. N e t : : Daemon (Jochen Wiedmann) -.


,
, .

Subject:- , .
Subject: . ,
:
Super-User
Super-User
Super-User
Super-User
Super-User
Super-User
Super-User

File
File
File
File
File
File
File

history
history
history
history
history
history
history

database
database
database
database
database
database
database

merge
merge
merge
merge
merge
merge
merge

report
report
report
report
report
report
report

:
Super-User
Super-User
Super-User
Super-User
Super-User
Super-User

Backup
Backup
Backup
Backup
Backup
Backup

OK,
OK,
OK,
OK,
OK,
OK,

1
1
1
1
1
3

tape, 1.400 GB written.


tape, 1.768 GB written.
tape, 2.294 GB written.
tape, 2.817 GB written.
tape, 3.438 GB written.
tapes, 75.40 GB written.

Subject: ,
. , , -
.
.

, . , - , . :
?
? $0 ( ),

314

8.
. , .
?
- , .
!1() Perl :
: , caller(),
# Perl,
perlfunc
(Spackage, Sfilename, $Hne, Ssubroutine, $hasargs, $wantarray,
Sevaltext, $is_require) = caller($frames);
$f rames - ( ). $ frames 1. ,
caller() :
('main','repserver',32,'main::printmail',1,undef)
, ,
repserver 32, main. m a i n : : p r i n t m a i l ( ,
, ).
callerQ, , .
?
.
, ?
?
, : ?
, :
, DNS-
.
(, , ).
?
, , .
Perl, :
use Text::Wrap;
sub problemreport {
# Sshortcontext -
# Susercontext -

315

# $nextstep - , ,

my($shortcontext, Susercontext, Snextstep) = @_;

my($filename, Sline, Ssubroutine) = ( c a l l e r ( 1 ) ) [ l , 2 , 3 ] ;


push (@return, " $filename: $snortcontext\n");

push(@return, "*** $filename ***\n\n");


push(@return,fill("", "", "- : Susercontext"). "\n\n");
push(@return, "- : $line Sfilename
$subroutine\n\n");
push(@return, "- : ".scalar localtime(time). "\n\n");
push(@return, "- : $nextstep\n");
\@return;
sub fireperson {
$report = &problemreport(" ",EOR,ON);
.
ORA.
EOR
, , .
EON
print @{$report};

ifireperson;
Sproblem report , ,
, Mail : : Mailer, . a & f i r e p e r s o n .
, ,
.

,
(fetching). . M a i l : :POP3Client (Sean
Dowd) Mail: :Cclient (Malcolm Beattie)
POP (Post Office Protocol) IMAP (Internet Message Access Protocol). ,
, .

316

8.
, , , .
, MailTools
(Graham Barr), Mail: :Internet Mail: :Header.


Mail: '.Internet Mail::Header , RFC822.
RFC822 , .
M a i l : : Internet
, , :
use Mail::Internet;
$messagefile = "mail";
open(MESSAGE,"$messagefile") or die " $messagefile:$!\n";
$message = new Mail:'.Internet \*MESSAGE;
close(MESSAGE);
,
(. . ), :
use Mail::Internet;
$message = new Mail::Internet \*STDIN;
M a i l : : Internet .
:
body() head(). body() ,
. head() M a i l : : Header.
Mail: :Internet Mail::Header.
head() Mail:'.Internet,
Mail::Header. ,
, M a i l : :Internet, M a i l : : H e a d e r :
use Mail::Header;
Smessagefile = "mail";
open(MESSAGE,"Smessagefile") or die " $messagefile:$!\n
$header = new Mail::Header VMESSAGE;
close(MESSAGE);
$header 0
. ,

317

(
),
:
print join("\n".sort $header->tags);
- :

Date
From
Message-Id
Organization
Received
Reply-To
Sender
Subject
To

Received: .
:
received = $header->get("Received");
M a i l : : H e a d e r M a i l : : I n ternet. M a i l : : I n t e r n e t , , :
received = $message->head->get("Received");
, get () . , , . , get ("Received", 2) Received:
. Mail: : Header
;
.

,
, . mbox qmail ( ,
sendma.il), M a i l : : Folder
(Kevin Johnson). (
Unix), Eudora,
Unix mbox, .

318

8. ;;
- :
use Mail::Folder::Mbox; Unix mbox
Sfolder = new Mail::Folder('mbox',"filename");
new()
. folder, , ,
, :
Smessage = $folder->get_message(6);
Smessage M a i l : : I n t e r n e t . . , :
$header = $folder->get_header(6);
;
M a i l : : H e a d e r . , Mai 1:: Folde r.


, , , , . ,
, - ,
. . , .
, ,
.
- , , ,
. - (
)
, .
, .
, ,
.
:
,
.
. ,
.

319

(
, ).
(relaying),
-
, - . .
, , . (,
),
,
.

Perl . ,
, 5 TCP/IP 6.
Perl-
, adcomplain (Bill McFadden), http://www.rdrop.com/
users/billmc/adcomplain.html.
, , :
Received: from isiteinc.com (www.isiteinc.com [206.136.243.2])
by mailhost.example.com (8.8.6/8.8.6) with ESMTP id NAA14955
for <webadmin@example.com>; Fri, 7 1998 13:55:41 -0400 (EOT)
From: responses@example.com
Received: from extreme (host-209-214-9-150.mia.bellsouth.net
[209.214.9.150])
by isiteinc.com (8.8.3/8.8.3) with SMTP id KAA19050 for
webadmin@example.com; Fri, 7 1998 10:48:09 -0700 (EOT)
Date: Fri, 7 1998 10:48:09 -0700 (EOT)
Received: from login_0246.whynot.net mx.whynot.net[206.212.231.88])
by whynot.net (8.8.5/8.7.3) with SMTP id XAA06927 for
<webadmin@example.com>; Fri, 7 August 1998 13:48:11 -0700 (EOT)
To: <webadmin@example.com>
Subject: ***ADVERTISE VACATION RENTALS - $25/year*** - http://www.example.com
Reply-To: sample@whynot.net
X-PMFLAGS: 10322341.10
X-UIDL: 10293287J92832.222
Comments: Authenticated Sender is <user122@whynot.net>
Message-Id: <77126959_36550609>
- http://www.example.com Extreme
Technologies, Inc.
, ,
, WWW.
,

320

8.
. ,
, ,
/. ,
!
. -,
.
, (:, From: . .)
DATA . , , .
Received:.
Received:,
, .
, (, TCP/IP-
DNS),
.
, Received: . , , , ,
( ):
use Mail: '.Header;
Sheader = new Mail::Header \*STDIN;
$header->unfold('Received');
received = $header->get('Received');
for (reverse @received){
chomp;
parseline($_);
if (!defined $ehelo and '.defined $validname and !defined $validip){
print "$_\n";
}
else {
write;

format STDOUT =
@> < @<
Sehelo,$validname,Svalidip
sub parseline {

321

$ = $_;
# "" -- HELD (REAL [IP])
if (/from\s+(\w\S+)\sA((\S+)\sA[(\d+\.\d+\.\ct+\.\d+)/){
($ehelo,$validname,$validip) = ($1,$2, $3);
}
tt -- HELO ([IP])
elsif (/from\s+(\w\S+)\s+\(\[(\d+\Ad+\.\d+\.\d+)\]/){
($ehelo,$validname,$validip) = ($1,undef, $2);
}
ft exim -- [IP] (helo=[HELO IP])
elsif (/
from\s+\[(\d+\Ad+\.\d+\.\d+)\]\s+\(helo=\[(\d+\.\d+\.\d+\.\d+)\]/){
($validip,$ehelo,$validname) = ($1,$2, undef);
}
tt Sun Internet Mail Server -- [IP] by HELO
elsif (/from\s+\[(\d+\.\d+\Ad+\.\d+)\]\s+by\s+(\S+)/){
($validip,$ehelo,$validname) = ($1,$2, undef);
}
ft Microsoft SMTPSVC -- HELO - (IP)
elsif (/from\s+(\S+)\s+-\s+(\d+\.\d+\Ad+\.\d+)\s+/){
($ehelo,$validname,$validip) = ($1,$2, $3);
}
else { ft punt!
$ehelo = Svalidname = $validip = undef;
return [$ehelo,$validname,$validip];

( u n f o l d ( ) ) Received:. u n f o l d ( )
.
.
( ,
). ,
, . . ,
, Received:.
&parseline. , Received::
HELO/EHLO
, HELO EHLO SMTP-.
IP
IP- , . , , ,

8. -

322

, ,
SMTP-. , , , . ^
,
.

, IP- DNS. , , ( ).
Received: RFC821
RFC822. , ( ,
), ,
.
,
, ,
. , adcomplain.
, ,
:
login_0246.whynot.net
extreme
isiteinc.com

mx.whynot.net
206.212.231.88
host-209-214-9-150.mia 209.214.9.150
www.isiteinc.com
206.136.243.2

,
; - ,
; - IP- . , , .
Received:,
, HELO
EHLO. ,
, .
, . ,
Received: ? - IP- Received: . "
(1), 1-"
, - (0). :
use Socket;
sub checkrev{


^
----

323

my($ip, $name) = @_;


return 0 unless ($ip and $name);
my $namelook = gethostbyaddr(inet_aton($ip), AF_INET);
my Siplook = gethostbyname($name);
Siplook = inet_ntoa($iplook) if Siplook;
#
if (Siplook eq $ip and Ic Snamelook eq Ic $name){
return 0;
}
else {
return 1;

, , ,
. ,
, (. .
gethostbyaddr( ) ).
Received:, (hop). ,
, ?

, . , ,
-. , ,
.
, , , . ,
, (
),
, Received:,
.
,
,
.
sendmail, . sendmail -

324

8.
Berkeley DB 2. V
http://www.sleepycat.com.
'
(Paul Marquess) BerkeleyDB,
Berkeley 2.x/3.x. , DB_File, , Perl, 2./3.. DB_File
BerkeleyDB 2.x/3.x ( , --enable-compat185, API 1.x API). BerkeleyDB
Perl API 2./3..
sendmail Berkeley DB 2.x/3.x,
BerkeleyDB. ,
:
Sblacklist = "/etc/mail/blacklist. db";
use BerkeleyDB;
%blist , Berkeley DB
#
tie %blist, 'BerkeleyDB: : Hash' , -Filename => Sblacklist
or die " Sfilename: $! $BerkeleyDB: :Error\n" ;
tt ,
REJECT
while(($key,$value) = each %blist){
# "OK", "RELAY" .
next if (Svalue ne "REJECT");
print "$key\n";
, , , (
) . mailserver.spammer.com, ( mailserver.spammer.com, spammer.com
spammer), , .
Perl , - .
,
.
,
. ,
, Perl "

325

. , Perl
:
,

foreach $match (qw(alewife davis porter harvard central kendall park)){
Sstation =" /$match/ and print "found our station stop!";
,
,
. , , ,
.
,
:
use BerkeleyDB;
$blacklist = "/etc/mail/blacklist, db";
&loadblist;
#
,
if (defined &cneckblist($ARGV[0])){
print "*** Sfound \";
#
sub loadblist{
tie %blist, 'BerkeleyDB::Hash', -Filename => $blacklist
or die " Sfilename: $! $BerkeleyDB::Error\n"
while(my($key,$value) = each %blist){
# "OK", "RELAY" .
next if (lvalue ne "REJECT");
push(@blisttests, eval 'sub {$_[0] =' /\Q$key/o and $key}');

sub checkblist{
my($line) = shift;
foreach Ssubref (@blisttests){
return Sfound if ($found = &$subref(Sline));
return undef;

326

8.
, (Joseph Hall) Effective Perl Programming ( Perl)
(Addison Wesley). .
. , .
. ,
:
push(@blisttests, eval 'sub {$_[0] =" /\Q$key/o and $key}');
, spammer, , , , :
sub {
$_[0] =" /\Qspammer/o and "spammer";
}

\Q , ( .)
.
.
-
, :
return $found if ($found = &$subref($line));
, ,
- .
, ,
.
, , , Perl 5.005 . Perl 5.005 , , . , , :
sub loadblist{
tie %blist, 'BerkeleyDB::Hash', -Filename => Sblacklist
or die " $filename: $! SBerkeleyDB::Error\n" I
while(my($key,$value) = each %blist){
# "OK", "RELAY" .
next if ($value ne "REJECT");
push(@blisttests,[qr/\Q$key/,$key]);

327

sub checkblist{
my($line) = shift;
foreach my $test (@blisttests){
my($re,$key) = @{$test};
return $key if ($line =" /$re/);

return undef;

@blisttest.
- , qr//. .
. - ,
.

? , ,
. 1,
, .
- Realtime Blackhole List (RBL) Mail Abuse Prevention
System Open Relay Behaviour-modification System (ORBS). :
1. IP-. , 192. 168. 1 . 34 34. 1 . 168. 192.
2. . RBL 34.1. 168. 192. r b l . m a p s .
vix.com.
3. DNS- .
, ,
, , , .
http://www.maps.vix.com http://
www.orbs.org.

328

8.
(. . ), 0
, IP- .
Dial-up User List, ^
Mail Abuse Prevention System. IP-,
. , SMTP- - . ( )
, IP- -
:
sub checkaddr{
my($ip, $domain) = @_;
return undef unless (defined Sip);
my $lookupip = ]oin( '.', reverse split(/\./,$ip));
if (gethostbyname($lookupip. $domain)){
return $ip;
}
else {
return undef;

. ,
Received:,
,
. Net: :Whois, 6,
, .
, (name-to-domain information). , , , InterNIC.
IP- (IP address-to-domain information) WHOIS http://whois.arin.net (American Registry for Internet Numbers), http://whois.ripe.net (European IP Address Allocations) http'./l
whois.apnic.net (Asia Pacific Address Allocations). - , .
,
, , 1-&'
. , , . , ARIN -

329

, ,
. , ARIN
, APNIC.
, Net : : Telnet 6. -
10: : Socket. - , , , .
WHOIS 43 TCP, . WHOIS-
. , ( IP-) . , WHOIS-, :
sub getwhois{
my($ip) = shift;
my($info);
$cn = new Net : : Telnet (Host => $whoishost,
Port => 'whois' ,
Errmode => "return",
Timeout => 30)
or die " $whoishost
connection:$!\n";
unless ($cn->print($ip."\n")){
$cn->close;
die " $ip Swhoishost: ".$cn->errmsg. "\n";
while ($ret = $cn->get){
$info .=$ret;
$cn->close;
return $info;

}
,
, , , . http://whois.arin.net . ,
ARIN IP- . , :
% telnet whois.arin.net 43
Trying 192.149.252.22 . . .
Connected to whois.arin.net.
Escape character is '"] .

330

8.
210.161.92.226
Asia Pacific Network Information Center (NETBLK-APNIC-CIDR-BLK)
Level 1 - 33 Park Road
Milton, 4064
AU
Netname: APNIC-CIDR-BLK2
Netblock: 210.0.0.0 - 211.255.255.0
Coordinator:
Administrator, System (SA90-ARIN) sysadm@APNIC.NET
+61-7-3367-0490
Domain System inverse mapping provided by;
SVC01.APNIC.NET
NS.TELSTRA.NET
NS.KRNIC.NET
NS.RIPE.NET

202.12.28.131
203.50.0.137
202.30.64.21
193.0.0.193

*** please refer to whois.apnic.net for more information ***


** before contacting APNIC
***
*** use whois -h whois.apnic.net <object>
***
Record last updated on 04-Mar-99.
Database last updated on 19-Apr-99 16:14:16 EOT.
, http://
whois.apnic.net.
- WHOIS-,
. http://whois.geektools.com.1 , WHOIS- . ,
, ,
.
,
, ( ) .
. , "
:
use Mail::Header;
use Socket;
, WHOIS - GeekTools Perl.
http:
geektools.com.

331

use BerkeleyDB;
use Net::Telnet;
$neader = new Mail: .'Header \*STDIN;
$header ->unfold('Received');
received = $header->get('Received');
Srbldomain
Sorbsdomain
Sduldomain
$blacklist
Swhoishost

=
=
=
=
=

".rbl.maps.vix.com";
".relays.orbs.org";
".dul.maps.vix.com";
"/etc/mail/blacklist.db";
"whois.geektools.com";

&loadblist;
for (reverse @received){
chomp;
parseline($_);
if (! defined $ehelo and ! defined $validname and ! defined $validip){
print "$_\n";
}
else {
$flags = (&checkaddr($validip,$rbldomain) ? "R" : ""); RBL?
Sflags .= (&checkaddr($validip, Sorbsdomain) ? "0" : ""); # ORBS?
Sflags .= (&checkaddr($validip, Sduldomain) ? "0" : ""); DUL?
Sflags .= (&checkblist($_)
? "B" : ""); # ?
$flags .= (&checkrev($validip,$validname) ? "L" : ""); # rev-lookup?
push(@iplist, Svalidip);
write;

for (@iplist){
print "\nWHOIS info for $_:\n";
print &getwhois($_);
format STDOUT =
>< @< @< @
Sehelo, Svalidname, $validip, $f lags
( ):
login_0246.whynot.net
extreme
isiteinc.com

mx.whynot.net
206.212.231.88
host-209-214-9-150.mia 209.214.9.150
www.isiteinc.com
206.136.243.2

L
DB
OB

332

8.

WHOIS info for 206.212.231.88:


WHOIS info for 209.214.9.150:
BellSouth.net Inc. (NETBLK-BELLSNET-BLK4)
1100 Ashwood Parkway
Atlanta, GA 30338
Netname: BELLSNET-BLK4
Netblock: 209.214.0.0 - 209.215.255.255
Maintainer: BELL
Coordinator:...
WHOIS info for 206.136.243.2:
Brainsell Incorporated (NET-ISITEINC)
4105-R Laguna St.
Coral Gables, FL 33146

US
Netname: ISITEINC
Netnumber: 206.136.243.0
Coordinator:...
! :
HELO/EHLO.
, , ( , WHOIS).
, , .

ORBS .
, .
Perl .
, .
, , .

,
,
. , , :

333

, .

;
.
, , . 14
(, ), , .

,
.


. :
- , - .
.
, ,
.
, , . , .
,
, :
Date: Sat, 28 Sep 1996 12:27:35 -0400 (EOT)
From: Special User <userexample.com>
To: systems@example.com
Subject: [Req. #9531] printer help
something is wrong and I have know idea what
(- , , )
,
, , , ,
, . ,
.
:
From: Another user <user2@example.com>
Subject: [Req #14563] broken macine
To: systems@example.com
Date: Wed, 11 Mar 1998 10:59:42 -0500 (EST)
krakatoa.example.com -

334

8.
, ,
. ,
.

, , (. . ). . , ,
.

( , . .).
?
. , , . ?
;
, .
. , ,
: ,
?. ,
, . , , .
- , .
, . ,

, , . , , - . ,
, .
. ?
, Perl, . Perl . : ? ? ?. .
, suss,
. , .

335

, . - .
suss
(, ).
, , , Received:. , /etc /hosts, :
use Mail: .-Internet;
$localdomain = ".example.com";
/etc/hosts
open(HOSTS, "/etc/hosts") or die "He \";
while(defined($_ = <HOSTS>)){
next if /"/;

next if /"$/;
#
next if /monitor/i; ff

Smachine = lc((split)[1]);
$machine =" s/\Q$localdomain\E$//oi;
$machines{$machine}++ unless $machines{$machine};

Smessage = new Mail: : Internet \*STDIN;
$message->head->unf old( ) ;
#
my Ssubject = $message->head->get( 'Subject');
Ssubject =' s/[.,;?]//g;
for (split(/\s+/, Ssubject)) {
if (exists $machines{lc $_}) {
print "subject: $_\n";
$found++;
exit if $found;
ft
chomp(my @body = @{$message->body()});
my $body = join(" ",@body);
Sbody =" s/["\w\s]/ /g;
tt
@body{split(' ', lc $body)} = ();
for (keys %body) {
if (exists SmachinesUc $_}) {
print "body: $_\n";
$found++;

336

8.

exit if $found;
: Received: $ received =
(reverse $message->head->get(' Received' ))[0];
$received =" s/\Q$localdomain\E//g;
for (split(/\s+/,$received)) {
if (exists $machines{lc $_}) {
print "received: $_\n";

,
, monitor.
, ,
, , next if /monitor/i, , .

(@body{...}),
.
. ,
. -, split ()
( ).
%body . , .
Perl .
.
:
Received: from strontium.example.com (strontium.example.com [192.168.1.114])
by mailhub.example.com (8.8.4/8.7.3) with ESMTP id RAA27043
for <systems>; Thu, 27 Mar 1997 17:07:44 -0500 (EST)
From: User Person <user@example.com>
Received: (user@localhost)
by strontiura.example.com (8.8,4/8.6.4) id RAA10500
for systems; Thu, 27 Mar 1997 17:07:41 -0500 (EST)
Message-Id : <1 99703272207 . RAA10500@st rontium . example . com>
Subject: [Req 11509] Monitor
To: systems@example.com
Date: Thu, 27 Mar 1997 17:07:40 -0500 (EST)
Hi,
My monitor is flickering a little bit and it is tiresome
when working with it to much.
Is it possible to fix it or changing the monitor?

337

Thanks.
User.
Received: from example.com (user2@example.com [192.168.1.7])
by mailhost.example.com (8.8.4/8.7.3) with SMTP id SAA00732
for <systemsexample.com>; Thu, 27 Mar 1997 18:34:54 -0500 (EST)
Date: Thu, 27 Mar 1997 18:34:54 -0500 (EST)
From: Another User <user2@example.com>
To: systems@example.com
Subject: [Req #11510] problems with two computers
Message-Id: <Pine.SUN.3,95.970327183117.23440A-100000@example.com>
In Jenolen (in room 292), there is a piece of a disk stuck in it. In
intrepid, there is a disk with no cover (or whatever you call that silver
thing) stuck in it. We tried to turn off intrepid, but it wouldn't work. We
(the proctor on duty and I) tried to get the disk piece out, but it didn't
work. The proctor in charge decided to put signs on them saying 'out of
order'
AnotherUser
:
received: strontium
:

body: jenolen
body: intrepid
. , :
Received: from [192.168.1.118] (buggypeak.example.com [192.168.1.118])
by mailhost.example.com (8.8.6/8.8.6) with SMTP id JAA16638
for <systems>; Tue, 4 Aug 1998 09:07:15 -0400 (EDT)
Message-Id: <v02130502b1ecb78576a9@[192.168.1.118]>
Date: Tue, 4 Aug 1998 09:07:16 -0400
To: systems@example.com
From: user@example.com (Nice User)
Subject: [Req #15746] printer
Could someone please persuade my printer to behave and print like a nice
printer should? Thanks much :)
-Nice User.
, , , 30
. Perl - ,


338

8.
.
, , ^
. , , ,
.
-, , ,
, 5,
LDAP. ,
:
use Mail: -.Internet;
use DB_File;
$localdomain = ".example.com";
# printdb - Berkeley OB. - , -
Sprintdb
= "printdb";
(t
Smessage = new Mail: .'Internet VSTDIN;
$message->head->unf old( ) ;
ft
my Ssubject = $message->head->get(' Subject');
if ($subject =" /print(er|ing)?/i){
# - (,
Sendmail)
Sreceived = (reverse $message->head->get(' Received '))[0];
($host) =
Sreceived =" /"from \S+ \((?:\S+@)?(\S+)\Q$localdomain\E \[/;
tie %printdb, "DB_File",$printdb or die "
$printdb:$!\n";
print " $host " .
$printdb{$host> . ",\";
untie %printdb;
,
, Received:.

, . . , Received . ,
Berkeley DB. :
buggypeak hiroshige.

339

,
,
.
, .
, (,
, )? Perl , .

Mac::Glue
Win32 : : OLE ( ActiveState Perl)

CPAN
CNANDOR

JDB

1.11

GBARR
Mail : : Mailer ( MailTools)
T e x t : : W r a p ( Text-Tabs+Wrap, MUIR
Perl)
10: : Socket ( 10, , - GBARR
Perl)
Mail : : Internet ( MailTools)
GBARR
Mail : : Header ( MailTools)

GBARR

0.58
1.13

98.112902
1.20
1.13
1.13

Mail: : Folder: :Mbox ( Mail: : Folder) KJOHNSON


Socket ( Perl)

0.07

BerkeleyDB

PMQS

0.10

Net: :Telnet
OB_File ( Perl)

JROGERS
PMQS

3.01
1.72


Advanced Perl Programming, Sriram Srinivasan (O'Reilly, 1997)-
.
Effective Perl Programming, Joseph Hall, Randal Schwartz (Addison
Wesley, 1998) - ,
Perl.
http://www.cauce.org/ - Coalition Against Unsolicited Email ( ). , ; .
, ,
.

340

8. ,
http://www.eudora.com/developers/scripting.html -
Eudora AppleScri.pt.
http://www.microsoft.com http://msdn.microsoft.com -
MAPI, active messaging CDO. "
,
. Microsoft
( MSDN) , .
Perl Cookbook, Tom Christiansen, Nathan Torkington (O'Reilly, 199g)

.
RFC821 .-Simple Mail Transfer Protocol, J. Postel, 1982.
RFC822:Standard for the format of ARPA Internet text messages,
D. Crocker, 1982.
RFC954:NICNAME/WHOIS, K. Harrenstien, M. Stahl, E. Feinler,
1985.

, .
.
, , .
, , . Perl.

. . ,
Perl, .

, , .
- . , Apache (), INN ( Usenet) Sendmail
( )
. Unix- , , syslog. , syslog, .
Perl, error
:

342

9. ,
open(LOG,"logfile") or die " :$!\";
while(<LOG>){
print if /\berror\b/i;
}
close(LOG);
, Perl, .
. :
perl -ne 'print if /\berror\b/i' logfile


, .
, , , Perl. , Perl .
.
: wtmp
Unix NT/2000.
3 Unix. Unix wtmp.
(, ?), .
NT/2000 . , , , , . .
syslog Unix.
unpackQ
Perl u n p a c k ( ) , . , wtmp. wtmp
Unix.
wtmp SunOS 4.1.4 Digital Unix 4.0, '
.
wtmp SunOS 4.1.4:
0000000
0000020
0000040
0000060

~
\0
,
\0

\0 \0 \0 \0 \0 \0 \0 b t \0 \0
\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
/ ; 4 c o n s o l e \ O r o o t
\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0

'

343

0000100
0000120
0000140

\0 \0 \0 \0 , / ; 203 n s 1 \0
\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
\0 \0 \0 \0 \0 \0 \0 \0 , / < 230

, ASCII ( ) . ?
- , . ,
, . ,
; , .
,
wtmp,
, /usr/'include/utmp.h.
, .
struct utmp {, . ,
struct utmp {, .
/* text */.
, wtmp, utmp.h :
SunOS 4.1.4:
struct utmp {
char
char
char
long

ut_line[8];
ut_name[8];
ut_host[16];
ut_time;

tty name /
user id */
host name, if remote */
time on */

Digital Unix 4.0:


struct utmp {
char ut_user[32]; /
/char ut_id[14];
char ut_line[32]; h
short ut_type;
/'
pid_t ut_pid;
/<
struct exit_status {
short e_termination;
short e_exit;
} ut exit;
time_t ut_time;
char
ut_host[64];

User login name */


/etc/inittab id- IDENT_LEN in init */
device name (console, Inxx) */
type of entry */
process id */
/* Process termination status */
/* Process exit status */
/* The exit status of a process
marked as DEAD_PROCESS.
*/
/* time entry was made */
/* host name same as MAXHOSTNAMELEN */

344

9.
, unpack()
!
,
() , . u n p a c k ( )
, , , .
,
utmp.h SunOS. , -
pack() perl func . - ; , .
pstruct, Perl, .
. utmp.h (. 9.1).
9.1. utmp.h unpackf )

char ut_line[8];

unpack() /
ASCII ( )
8

char ut_name[8];

ASCII ( )
8
ASCII ( )
16

( long )

char ut_host[16]; A16


long ut_time;

, :
# , unpack()
Stemplate = "8 8 16 1";
ft pack(), ( )
$recordsize = length(pack($template, ));
ft
open(WTMP,"/var/adm/wtmp") or die " wtmp:$!\n";
ft
while (read(WTMP,Srecord, $recordsize)) {
# ,
($tty,$name,$host,$time)=unpack($template,Srecord);
ft (. )
if ($name and substr($name,0,1) ne "\0"){
print "$tty:$name:$host:" ,

345

'

scalar localtime($time), "\";


else {
print "$tty:(logout):(logout):",
scalar localtime($time),"\n";


close(WTMP);

:
~:reboot::Mon Nov 17 15:24:30 1997
:0:dnb::0:Mon Nov 17 15:35:08 1997
ttyp8:user:host.mcs.anl.go:Mon Nov
ttyp6:dnb:limbo-114.ccs.ne:Mon Nov
ttyp6:(logout):(logout):Mon Nov 17
ttyp1:dnb:traal-22.ccs.neu:Mon Nov
ttypl:(logout):(logout):Tue Nov 18

17 18:09:49 1997
17 19:03:44 1997
19:26:26 1997
17 23:47:18 1997
00:39:51 1997

:
SunOS 0 , :
if (Sname and substr($name,1,1) ne "\0"){

read() ,
.
32,
p a c k ( ) . ,
,
.
pack() :
Srecordsize = length(pack($template,()));


wtmp - ,
Unix last,
, .
, ,
:
dnb
drib
dnb
user

ttyp6
traal-22.ccs.neu Mon Nov 17 23:47 - 00:39 (00:52)
ttyp! traal-22. ccs. neu Mon Nov 17 23:47 - 00:39 (00:52)
ttyp6 limbo-114.ccs.ne Mon Nov 17 19:03 - 19:26 (00:22)
ttypS
host.ncs.anl.go Mon Nov 17 18:09 - crash (27+11:50)

dnb
:0
reboot
"

:0

Mon Nov 17 15:35 - 17:35 (4+02:00)


Mon Nov 17 15:24

346

9.
, last Perl.
,
wimp:
last
Slastexec = "/usr/ucb/last";
open(LAST,"Slastexecl") or die " $lastexec:$l\n";
while(<LAST>){
$user = (split)[0];
print "$user"."\n" unless exists $seen{$user};
$seen{$user}='';
}
close(LAST) or die " :$!\";
, unpack() ,
? - . , wtmp .
, wtmp,
, unpack()
.
, last, , ,
- . unpackQ

wtmp, .1
unpack() , .
unpack() .
last , split () :
user
user
user
reboot

console
Wed Oct 14 20:35 - 20:37 (00:01)
pts/12
208.243.191.21 Wed Oct 14 09:19 - 18:12 (08:53)
pts/17
208.243.191.21 Tue Oct 13 13:36 - 17:09 (03:33)
system boot
Tue Oct 6 14:13

, , , , "
. -
unpack(), ,
, .
- ,
, last '
, .

348

9.
%type = (1
2
4
8
16

=> "ERROR",
=> "WARNING",
=> "INFORMATION",
=> "AUDIT_SUCCESS",
=> "AUDIT_FAILURE");

# ,
Read()
$Win32: :EventLog: :GetMessageText = 1;
# System
$log = new Win32: :Eventl_og( "System")
or die " :$"\";
ft ,
while ($log->Read((EVENTLOG_SEQUENTIAL_READ|EVENTLOG_FORWARDS_READ),
1,$entry)){
print scalar localtime($entry->{TimeGenerated}). " ";
print $entry->{Computer}."[". ($entry->{EventID} &
Oxffff)."] ";
print $entry->{Source} . " : " . $type{$entry->{EventType} } ;
print $entry->{Message};
NT/2000 ,
, tost,
. .

, ,
, ,
. ,
, , ,
. , .
- Apache. -:
esnet-118.dynamic.rpi.edu - - [13/Dec/1998:00:04:20 -0500] "GET home/u1/tux/
tuxedo05.gif
HTTP/1.0" 200 18666 ppp-206-170-3-49.okld03.pacbell.net - - [13/Dec/
1998:00:04:21 -0500] "GET home/u2/news.htm
HTTP/1.0" 200 6748 ts007d39.ftl-fl.concentric.net - - [13/Dec/1998:00:04:22 0500] "GET home/u1/bgc.jpg HTTP/1.1" 304 :
14 12:58:46 warhol printer: cover/door open

ibie

349

14 12:58:58 warhol printer: error cleared


14 17:16:26 warhol printer: offline or intervention needed
14 17:16:43 warhol printer: error cleared
15 20:40:45 warhol printer: paper out
15 20:40:48 warhol printer: error cleared


. ,
, ,
.

sendmail:
Dec 13 05:28:27 mailhub sendmail[26690]: FAA26690:
from=<user@nas.a.godcomplex.com>, size=643, class=0, pri=30643, nrcpts=1,
msgid=<199812131032.CAA22824@has.a.godcomplex.com>, proto=ESMTP,
relay=user@has.a.godcomplex.com [216.32.32.176]
Dec 13 05:29:13 mailhub sendmail[26695]: FAA26695:
from=<root@host.ccs.neu.edu>, size=9600, class=0, pri=39600, nrcpts=1,
msgid=<199812131029.FAA15005@host.ccs.neu.edu>, proto=ESMTP,
relay=root@host.ccs.neu.edu [129.10.116. 69]
Dec 13 05:29:15 mailhub sendmail[26691]: FAA26690: to=<user@ccs.neu.edu>,
delay=00:00:02, xdelay=00:00:01, mailer=local, stat=Sent
Dec 13 05:29:19 mailhub sendmail[26696]: FAA26695: to="|IFS=' '&&exec /usr/
bin/procmail -f-||exit 75 tfuser", ctladdr=user (6603/104), delay=00:00:06,
xdelay=00:00:06, mailer=prog, stat=Sent
,
,
. 9.2.
"Dec 13 05:28:27 mailhub sendmail[26690]: 26690:
from=<user@has.a.godcomplex.com>, size=643, class=0,
pri=30643, nrcpts=l,
msgid=<l99812131032.CAA22824@has.a.godcomplex.com>,
proto=ESMTP, relay=user@has.a.godcomplex.com [216.32.32.176]
Dec 13 05:29:13 mailhub sendmail [26695] : PAA26695:
from=<root@host.ccs.neu.edu>, size=9600, class=0,pri=39600
nrcpts=l,msgid=<199812131092.FAA15005@host.ccs.neu.edu>,
proto=ESMTP, relay=root8host.ccs.neu.edu [129.10.116.69]
Dec 13 05:29:15 mailhub sendmail [26691] : FAA26690:
to=<user@ccs.neu.edu>, delay=00:00:02, xdelay=00:00:01,
mailer=local, stat=Sent
Dec 13 05:29:29 mailhub sendmail [26696] : FAA26695: to="IIFS='
'&&exec /usr/bin/procmail -f-llexit 75 #user", ctladdr=user
pri=30643, nrcpts=l,
(6603/104), delay=00:00:06, xdelay=00:00:06, mailer=prog,
sCat=Sent

. 9.2. sendmail

350

9.
,
.
,
,
.
,
.
. ,
, wtmp, . , ( ),
, . . , .
.
,
. IP- :
Jan 14 15:53:45 mailhub popper[20243]: Debugging turned on
Jan 14 15:53:45 mailhub popper[20243]: (v2.53) Servicing request from
"client" at 129.X.X.X
Jan 14 15:53:45 mailhub popper[20243]: +OK QPOP (version 2.53) at mailhub
starting.
Jan 14 15:53:45 mailhub popper[20243]: Received: "USER username"
Jan 14 15:53:45 mailhub popper[20243]: +OK Password required for username.
Jan 14 15:53:45 mailhub popper[20243]: Received: "pass xxxxxxxxx"
Jan 14 15:53:45 mailhub popper[20243]: +OK username has 1 message (26627
octets).
Jan 14 15:53:46 mailhub popper[20243]: Received: "LIST"
Jan 14 15:53:46 mailhub popper[20243]: +OK 1 messages (26627 octets)
Jan 14 15:53:46 mailhub popper[20243]: Received: "RETR 1"
Jan 14 15:53:46 mailhub popper[20243]: +OK 26627 octets
<message text appears here>
Jan 14 15:53:56 mailhub popper[20243]: Received: "DELE 1"
Jan 14 15:53:56 mailhub popper[20243]: Deleting message 1 at offset 0 of
length 26627
Jan 14 15:53:56 mailhub popper[20243]: +OK Message 1 has been deleted.
Jan 14 15:53:56 mailhub popper[20243]: Received: "QUIT"
Jan 14 15:53:56 mailhub popper[20243]: +OK Pop server at mailhub signing offJan 14 15:53:56 mailhub popper[20243]: (v2.53) Ending request from "user" at
(client) 129.X.X.X
(Servicing reQ'
uest from...) (Ending request from...), "
, .

.
POP- - , *
.

351

FTP- ,
. , , , ? ?
, ? .

, , , . ,
: Unix, MacOS Windows NT/2000. , ,
NT/2000 , . MacOS
, ,
, , .
. Unix
,
. , , ( ) .

- . (
). , , , , logfile.O. . ,
(logfile.O) ( logfile.J).
, . . (. 9.3).
.
Perl, (. 9.2).

352

9.

logfile

logfile.

logfile

logfile.0 logfile. 1

logfile

81
V
logfile. 0 logfile^

logfile.2

logfile

logfile. 0

logfile. 2

!
logfile^

|
logfile

logfile.Z

poraawra |*, |
logfile. 0

logfile. 1

logfile. 2

logfile.Z

logfile. n

Puc. 9.3.
. 9.2. Perl

Perl

, renameO &File: :Copy: :move() .


.
, , , ,
.

k i l l ( ) , , system() ' ( ),

.

& F i l e : : Copy , renameO, , ( &File: :Copy: :move()


, . ).
, - truncate() open (FILE, "> filename").
.
, - 2 .

.

- system ()

.
,
.

stat(),
, u n l i n k ( ) .

353

. , ,
. , . Logfile:: Rotate
(Paul Gampe).
L o g f i l e : : Rotate - . (. 9.3).
9.3. Logfile::Rotate


File
Count (, -
: 7)
Gzip (, : gzip
, Perl)
Signal

,
, 5 (. 9.2)

, :
use Logfile::Rotate;
Slogfile = new Logfile::Rotate(
File => "/var/adm/log/syslog",
Count => 5,
Gzip => "/usr/local/bin/gzip",
Signal =>

sub {
open PID, "/etc/syslog.pid" or
die " !-:$!\";
chomp($pid = <PID>);
close PID;
#
kill 'HUP', $pid;



. ,
:
$logfile->rotate();
undef $logfile;

354

9.
undef , , ( ,
).
, (, root), . -, Logf lie:: Rotate gzip,
. -, Signal .
, , /etc/syslog.pid, syslog.
,
4 , kill(). 1 .



,
. , .
: , .
, , , . , , . .
?
bigbuffy , , bigbuffy .
. ,
. - , bigbuffy . ,
.
,
, .
bigbuffy
( , 5
TCP/IP). ()
, bigbuffy 6
. , 0

355

(, ).
bigbuffy. , .
, :
Sbuffsize = 200; ft ( )
use Getopt::Long;
#
GetOptions("buffsize=i" => \$buffsize,
"dumpfile=s" => \$dumpfile);
#
&setup;
# -
while (<>){
. ,
# , .
it , ,
- .
$buffer[$whatline] = $_;
# ?
($whatline %= $buffsize)++;
it ,
if (Sdumpnow) {
&dodump();

sub setup {
die ": $0 [--buffsize=<lines>] dumpfile=<filename>"
unless (length($dumpfile));
$SIG{'USR1'} = \&dumpnow; tt
Swhatline = 1; tt
tt ,
tt , . perlipc(1)
sub dumpnow {
Sdumpnow = 1;
# , ,
#
sub dodump{
my($line);
n

356

9.
my($exists); # , ?
my(firststat,(9>secondstat); # Istats
Sdumpnow = 0; tt
$SIG{'USR1'} = \&durnpnow;
if (-e Sdumpfile and (! -f $dumpfile or -1 $dumpfile)) {
warn ":
, . \";
return undef;

. "if"
#
if (-e Sdumpfile) {
Sexists = 1;
unless(@firststat = Istat Sdumpfile) {
warn " Sdumpfile,
. \n";
return undef;
}
if ($firststat[3] != 1) {
warn "Sdumpfile - , . \n"
return undef;

unless (open(DUMPFILE, "$dumpfile")){


warn " Sdumpfile ,
. \";
return undef;
}
if (Sexists) {
unless (@secondstat = Istat DUMPFILE){
warn " Sdumpfile,
. \";
return undef;
}
if ($firststat[0] != $secondstat[0] or #
$firststat[1] != $secondstat[1] or inode
$firststat[7] != $secondstat[7]) 8
{
warn " : Istats ,
. \";
return undef;

Sline = Swhatline;
print DUMPFILE "-". scalar(localtime). f-"x50). "\n";
do {

357


last unless (defined $buffer[$line]);
print DUMPFILE $buffer[$line];
$line = ($line == $buffsize) ? 1 : $line+1;
} while ($line != $whatline);
close(DUMPFILE);
ft ,
#
Swhatline = 1;
Sbuffer = ();
return 1;
.

, bigbuffy. , , :
. , bigbuffy, , . ,
, , ,
.
:

bigbuffy, . . , .
.

bigbuffy,
. ,
. ,
.
- , .
- , .

, , ,
.

358

9.
,

, bigbuffy
, .
() ,
.
, .
, , - .
, , ,
, . , ,
- , /etc/passwd.
, , . :

, , .
, lstat(), .
.

,
lstat() ,
, , . (.. ),
.
, 1.
,
( )
.
Unix-, Unix .
, , NT4, . .
POSIX, MacOS,
.1
, NT, MacOS
. ,
,
(, OpenBSD).

359


.
, , . ,
.
,
Perl, .
Unix,
. . Unix- , , .
-
- .
, , . , , , wtmpx Solaris 2.:1
# wtmpx Solaris 2.6,
pack()
Stemplate = "32 4 32 1 s s2 x2 12 1 x20 s A257 x";
#
$recordsize = length(pack($template,()));

open(WTMP,"/var/adm/wtmpx") or die " wtmpx:$!\n";
#
while (read(WTMP,$record,$recordsize)) {
($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,
$ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen, $ut_host)=
unpack($template,$record);
if ($ut_line eq "system boot"){
print "rebooted ".scalar localtime($tv_sec)."\n";
$reboots++;
wtmpx - , u/wtmp.
, (, 16 ). Solaris
wtmp, wtpmx.

360 ^

9. |

close(WTMP);
print " : $reboots\n";
Event Log Windows NT. , NT .
Perl.

Win32.
NT
, .
, , , , , ( - ) . .
Unix, , . . , .
EventlD. , (.dll). .
. ,
Win32:: EventLog ( $Win32:: EventLog:: GetMessageText Win32:: Eventlog).

System, ,
, . , .
- Win32:: EventLog,
Perl
Win32. -,
. Perl , , . , , :
use Win32::EventLog;

my %event=('Length',NULL,
'RecordNumber',NULL,
'TimeGenerated', NULL,
'TimeWritten',NULL,

'

361
'EventlD'.NULL,
'EventType' ,NULL,
'Category',NULL,
'ClosingRecordNumber',NULL,
'Source',NULL,
'Computer',NULL,
'Strings',NULL,
'Data',NULL,);

# , 1 -- "Error",
2 -- "Warning" . .
@types = ("","Error","Warning","","Information");
- System. Open() EventLog $EventLog, :
Win32::EventLog;:Open($EventLog,'System','')
or die " System:$~E\n";
,
:
$EventLog->Win32:;EventLog;:GetNumber($numevents);
$EventLog->Win32::EventLog::Get01dest($oldestevent);
Read(), .
seek():
$EventLog->Win32::EventLog;:Read((EVENTLOG_SEEK_READ
EVENTLOG_FORWARDS_READ),
Snumevents + Soldestevent, Sevent);
. EVENTLOG_SEQUENTIAL_READ :
. EVENTLOG_FORWARDS_READ
1
. Read() , 0, , . , - (Source)
(EventType).
# ,
tf (Source) (EventTypes)
for ($i=0;$i<$numevents;$i++) {
,
Win32 , . , - .

362

___

9.

$EventLog->Read((EVENTLOG_SEQUENTIAL_READ |
EVENTLOG_FORWARDS_READ)
,
, $event);
$source{$event->{Source}}++;
$types{$event->{EventType}}++;

print "-->Event Log Source Totals:\n";
for (sort keys %source) {
print "$_: $source{$_}\n";
}
print "-"x30, "\n";
print "-->Event Log Type Totals:\n";
for (sort keys %types) {
print "$types[$_]: $types{$_}\n";
}
print "-"x30, "\n";
print "Total number of events: $numevents\n"
:
--> Event Log Source Totals:
Application Popup: 4
BROWSER: 228
DCOM: 12
Dhcp: 12
EventLog: 351
Mouclass: 6
Workstation: 2
Print: 27
Rdr: 12
RemoteAccess: 108
SNMP: 350
Serial: 175
Service Control Manager: 248
Sparrow: 5
Srv: 201
msbusmou: 162
msi8042: 3
msinport: 162
mssermou: 151
qic117: 2
--> Event Log Type Totals:
Error: 493
Warning: 714
Information: 1014
Total number of events: 2220
, , Zasi-*0
.

363

(Jesper Lauritsen), http://www.ibt.ku.dk/jesper/JespersNTtools.htm.


DumpEl NT Resource Kit:
Seldump = 'c:\bin\eldump'; ft ElDump
ft , (~),
# ()
$dumpflags = '-1 system - " -';
open(ELDUMP, "Seldump $dumpflags|") or die "
$eldump:$!\n";
print STDERR " .";
while(<ELDUMP>){
($date, $time, Ssource, $type, Scategory, $event, $user, {computer) =
splitC");
$$type{$source}++;
print STDERR ".";
}

print STDERR "done.\n";


Close(ELDUMP);
#
ft
foreach $type (qw(Error Warning Information
AuditSuccess AuditFailure)){
print "-" x 65, "\n";
print uc($type)."s by source:\n";
for (sort keys %$type){
print "$_ ($$type{$_})\n";
print "-" x 65, "\n";
:
ERRORS by source:
BROWSER (8)
Cdrom (2)
DCOM (15)
Dhcp (2524)
Disk (1)
EventLog (5)
RemoteAccess (30)
Serial (24)
Service Control Manager (100)
Sparrow (2)
atapi (2)
i8042prt (4)
WARNINGS by source:

364

9.
BROWSER (80)
Cdrom (22)
Dhcp (76)
Print (8)
Srv (82)


. ,
, .
, :

(
) seek( ) API-.

. , , last.

, . ,
, , - .
, , -
?.
, . . SunOS

, , :
Stemplate
= "8 8 16 1"; # SunOS 4.1.x
Srecordsize
= length(pack($template,()));
($user,$ignore) = @ARGV;
print "-- , $user --\n";
open(WTMP,"/var/adm/wtmp") or die " wtmp:$!\n";
while (read(WTMP,$record,Srecordsize)) {
(
($tty,$name,$host,$time)=unpack($template,$record);
if ($user eq $name){
next if (defined $ignore and $host =" /$ignore/o);
if (length(Shost) > 2 and !exists $contacts{$host}){
$connect = localtime($time);
$contacts{$host}=$time;
write;

365

print "-- --\";


die " wtmp:$!\n"
unless (seek(WTMP,0,0));
while (read(WTMP,$record,$recordsize)) {
($tty, $name, $host, $time)=unpack($template, $record);
ft
#
ft
if



** ,
(substr($name, 1, 1) ne "\0" and
exists $contacts{$host} and
$name ne $user){
Sconnect = localtime($time);
write;

close(WTMP);
ft , ,
#
format STDOUT =
@
@
$name, $host, Sconnect
wtmp . ,
,
.
, , . , , wtmp.
- .
. , , ( ), , .
, , ,
.
, :
. , ,

366

9.
. , , .

-
, ( ), .
.
: , FTP , .
FTP- wu-ftpd:
Sun Dec 27 05-18:57 1998 1 nic.funet.fi 11868 /net/ftp.funet.fi/CPAN/
MIRRORING.FROM a _ a cpan@perl.org ftp 0 *
Sun Dec 27 05:52:28 1998 25 kju.hc.congress.ccc.de 269273 /CPAN/doc/FAQs/FAQ/
PerlFAQ.html a _ a mozilla ftp 0 *
Sun Dec 27 06:15:04 1998 1 rising-sun.media.mit.edu 11868 //
MIRRORING.FROM b _ a root@rising-sun.media.mit. edu ftp 0 *
Sun Dec 27 06:15:05 1998 1 rising-sun.media.mit.edu 35993 /CPAN/RECENT.html b

root@rising-sun.media,mit.edu ftp 0 *
, (
xferlog(S)
wu-ftpd).

current-time ( )
1
transfer-time ( , )
2
remote-host ( )
3
4

5
6
7
8
9
10
11
12

filesize ( )
filename ( )
transfer-type ( )
special-action-flag ( )
direction ()
access-mode ( )
username ( )
service-name ( )
authentication-method ( )
authenticated-user-id (
)
.

367

, , :

;
-

$xferlog = "/Var/adm/log/xferlog";
open(XFERI_OG, Sxferlog) or die " $xferlog:$!\n";
while (<XFERLOG>){
$files{(split)[8]}++;
}
close(XFERLOG);
for (sort {$files{$b} <=> $files{$a}||$a crop $b} keys %files){
print "$_:$files{$_}\n";
}
,
, . ,
,
splitQ:
$files{(split)[8]}++;
, , (8), 8- xferlog, .
,
.
( split()), .
-
sort:
for (sort {$files{$b} <=> $files{$a}|]$a cmp $b} keys %files){
, $ $b . , sort
, . . . sort (| |$a cmp $b)
, .

, . ,
next unless /$ARGV[0]/o;
while(), .

368

9.
-

.
. .
.

-
.
, . , . ,

.
, , . (Jeffrey Friedl) Mastering Regular Expressions ( ) (O'Reilly).

Unix: Unix- .
,
( , Perl). .
, , - ,
syslog tcpwrappers,
, . , telnet, , tcpwrappers. , tcpwrappers
syslog
, (, ). , , , (
), tcpwrappers
DNS-
, , ,

369

. , , , ( , RFC931),
. tcpwrappers (Simson Garfinkel) (Gene
Spafford) Practical Unix & Internet Security (Unix
) (O'Reilly).
, tcpwrappers ( tcpdlog)
,
wtmp. ,
# tcpd
Stcpdlog
= "/ar/log/tcpd/tcpdlog";
Shostlen
= 16; # wtmp
print "-- tcpdlog --\n";
open(TCPDLOG, $tcpdlog) or die " $tcpdlog:$!\n";
while(<TCPDLOG>){
next if ! /connect from /; #
($connecto,$connectf rom) = /(.+):\s+connect from\s-K.+)/;
Sconnectfrom =" s/~.+@//;
# tcpwrappers ,
# N , wtmp.
# ,
# wtmp ,
$cormectfrom = substr($connectf rom, 0, Shostlen);
print if (exists $contacts{$connectfrom} and
$connectfrom /$ignore/o);
, :
-- , -user
host. ccs. neu Fri Apr 3 13:41:47
-- -user2
host. ccs. neu Thu Oct 9 17:06:49
user2
host. ccs. neu Thu Oct 9 17:44:31
user2
host. ccs. neu Fri Oct 10 22:00:41
user2
host. ccs. neu Wed Oct 15 07:32:50
user2
host. ccs. neu Wed Oct 22 16:24:12
-- tcpdlog -Jan 12 13:16:29 host2 in. rshd[866] : connect from user4@host.ccs.neu.edu
Jan 13 14:38:54 hosts in. rlogind[4761] : connect from user5@host.ccs.neu.edu
Jan 15 14:30:17 host4 in. ftpd[18799] : connect from user6@host.ccs.neu.edu
Jan 16 19:48:19 hosts in. ftpd[5131] : connect from user7@host.ccs.neu.edu
, , -

370

9.
. wtmp ,
3 22 , tcpwrappers
. ,
wtmp tcpwrappers .
, , , .
,
-, , .
wu-ftpd, wtmp
, xferlog
wu-ftpd. , FTP,
.
, .
FTP- .
. , :
Thu Mar 12 18:14:30 1998-Thu Mar 12 18:14:38 1998 pitpc.ccs.neu.ed
-> /home/dnb/makemod
Sat Mar 14 23:28:08 1998-Sat Mar 14 23:28:56 1998 traal-22.ccs.neu
<- /home/dnb/.emacs19
Sat Mar 14 23:14:05 1998-Sat Mar 14 23:34:28 1998 traal-22.ccs.neu
<- /home/dnb/lib/emacs19/cperl-mode.el
<- /home/dnb/lib/emacs19/filladapt.el
Wed Mar 25 21:21:15 1998-Wed Mar 25 21:36:15 1998 traal-22.ccs.neu
(no transfers in xferlog)
, . xferlog ,
, , .
wtmp 16'
. ,
-
. ,
:
->--1)1 ( )
use Time::Local;
Sxferlog = "/var/log/xferlog"; ft


-<;

371

$wtmp = "/var/adm/wtmp";
tt wtmp
Stemplate = "A8 A8 A16 1";
ft wtmp SunOS 4.1.4
$recordsize = length(pack($template, )); # wtmp
Shostlen = 16; # wtmp

%month = qw{Jan 0 Feb 1 Mar 2 Apr 3 May 4 Jun 5 Jul 6
Aug 7 Sep 8 Oct 9 Nov 10 Dec 11};
&ScanXferlog;
#
&ScanWtmp;
# wtmp
SShowTransfers; tt
, xferlog:
tt wu-ftpd
# %transfers
sub ScanXferlog {
local ($sec,$min, $hours, $mday, $mon,$year);
my($time, $rhost, Sfname, Sdirection) ;
print STDERR " Sxferlog. . . ";
open(XFERLOG,$xferlog) or
die " $xferlog:$!\n";
while (<XFERLOG>){
tt
($mon, $mday, $time, $year, $rhost, $fname, Sdirection) =
# ,
# 1 -
$fname = (Sdirection eq 'i' ? "-> " : "<- ") . Sfname;
# Unix
($hours,$min,$sec) = splitC : ',$time);
Sunixdate =
timelocal($sec, $min, $hours, $mday , $month{$mon} , $year);
tt :
push(@{$transfers{substr($rhost,0,$hostlen)}},
[Sunixdate, Sfname]);

}
close(XFERLOG);
print STDERR ". \n";
}

pushQ, , . , :
$transfers{hostname} =
([timel, filename!], [time2, filename2], [time3, filenames]...)

372

9.
%transfers , . , wtmp.
,
. , 1
. timelocal() Time: : Local . , ,
, .
wtmp :
wtmp sessions
ft ftp-
sub ScanWtmp {
my($record,$tty,$name,$host,$time,%connections);
print STOERR " $wtmp...\n";
open(WTMP,$wtmp) or die " $wtmp:$!\n";
while (read(WTMP,$record,$recordsize)) {
it ftp,
(unpack). :
ft wtmp
next if (substr($record,0,3) ne "ftp");
($tty,$name,$host,$time)=unpack($template,$record);
ft ,
ft .
.
if ($name and substr($name,0,1) ne "\0"){
push(@{$connections{$tty}},[$host,$time]);
}
# ,
ft ,
ft
else {
unless (exists $connections{$tty}){
warn " $tty."
scalar localtime($time)."\n";
next;
, . ,
Unix- - 00:00:00 (GMT) 1
1970 .

373


tt
#
# .
# , ,
# (hostname, login, logout)
push(@sessions,
[@{snift @{$connections{$tty}}}, $time]);
tt
# ,
delete $connections{$tty}
unless (@{$connections{$tty}});

close(WTMP);
print STDERR ". \n";
}

, .
wtmp. ftp,
, FTP. , ,
,
wtmp. tty , . ,
, unpack( ), .
, ftp, ,
, FTP-
. ,
%connections, , . %transfers ,
,
. - ,
, , .
? , wtmp
- - -. , wtmp (
, wtmp):
ftpd1833:dnb:ganges.ccs.neu.e:Fri Mar 27 14:04:47 1998
ttyp7: (logout): (logout) :Fri Mar 27 14:05:11 1998
ftpd1833:dnb:hotdiggitydog-he:Fri Mar 27 14:05:20 1998
ftpd1833:(logout):(logout):Fri Mar 27 14:06:20 1998
ftpd1833: (logout): (logout). -Fri Mar 27 14:06:43 1998
- (1- 3- ).

374

9.
, , .
, %connections.
, (host, login-time)
. , , .
:
push(sessions,[@{shift @{$connections{$tty}}},$time]);
, .
/
:
push(@sessions,[{shift @{$connections{$tty}}},$time]);
:
push(@sessions,[{shift @{$connections{$tty}}},$time]);
, (host, login-time)
. , , Perl
, .
(host, login-time, logout-time):
push(@sessions,[{shift @{$connections{$tty}}},$time]);
, (,
) FTP ,
sessions, :
push(@sessions, [{shift ie>{$connections{$tty}}},$time]);
.
&ScanWtmp, , , . . , . ,
; , :
delete $connections{$tty} unless (@{$connections($tty}});

. &ShowTransfers.
,
, , .

375

tt ,
tt
sub ShowTransfers {
local($session);
foreach $session (@sessions){

print scalar localtime($$session[1]) . "-" .
scalar localtime($$session[2]) .
" $$session[0]\n";

# ,
print &FindFiles(@{$session}), "\n";

, ,
:
# ,
sub FindFiles{
my($rhost, Slogin, $logout) = @_;
my (Stransfer, found);
tt ,
unless (exists $transfers{$rhost}){
return "\t(no transfers in xferlog)\n";
tt ,
#
if ($transfers{$rhost}->[0]->[0] > $logout){
return "\t(no transfers in xferlog)\n";
# ,
foreach Stransfer (@{$transfers{$rhost}}){
tt
next if ($$transfer[0] < Slogin);
tt
last if ($$transfer[0] > Slogout);
tt
next unless (defined $$transfer[1]);
push(@found, "\f'.$$transfer[1]. "\n");
undef $$transfer[i];

376

9.
(Sttfound > -1 ? @found : "\t(no transfers in xferlog)\n")
.
, ,
,
, .

; . * '-4 ;

, . , ,
, , . , - . ,
, , . , ,
? .
, ,
, :
#
next unless (defined $$transfer[1]);

, , .
, . , , -
. :
. undef .
, , .
.
, ,
, , . , .


Perl , ^
, -
.
, .
.
.

377

- SyslogScan
(Rolf Harold Nelson). ,
sendmail - . , .
SyslogScan , .
.
SyslogScan -,
:
use SyslogScan::DeliveryIterator;
# syslog
$maillogs = ["/var/log/mail/maillog"];
Siterator = new SyslogScan::DeliveryIterator(syslogList => Smaillogs);
new SyslogScan: :DeliveryIterator
(iterator), . . , . , ,
. n e x t ( ) , .
, . , :
while ($delivery = $iterator -> next()){
print $delivery->{Sender}." -> ".
(",",@{$delivery->{ReceiverList}}),"\n";
:
root@host.ccs.neu.edu -> user1cse.scu.edu
owner-freebsd-java-digest@freebsd.org -> user2@ccs.neu.edu
root@host.ccs.neu.edu -> user3@ccs.neu.edu
. SyslogScan new SyslogScan: :Summary, new next
.
,
.
SyslogScan . new SyslogScan: : ByGroup, bygroup,

______

378

9.

. , :
use SyslogScan: :DeliveryIterator;
use SyslogScan: -.Summary;
use SyslogScan: :ByGroup;
use SyslogScan: : Usage;
t maillog
Smaillogs = ["/var/log/mail/maillog"];

literator = new SyslogScan: :DeliveryIterator(syslogi_ist => Smaillogs);
# :: Summary, summary ()
$summary = new SyslogScan: :Summary($iterator);
# ::ByGroup stats-by-group
( )
$bygroup = new SyslogScan: :ByGroup($surnmary);
#
foreach $group (sort keys %$bygroup){
($bmesg,$bbytes)=@{$bygroup->{$group}->
{groupUsage}->getBroadcastVolume()K
($smesg,$sbytes)=@{$bygroup->{$group}->
{groupUsage} ->getSendVolume()};
($rmesg,$rbytes)=@{$bygroup->{$group}->
{groupUsage} ->getReceiveVolume( ) } ;
($rmesg,$rbytes)=@{$bygroup->{$group}->
{groupUsage} ->getReceiveVolume()};
write;
format STDOUTJTOP =
Name

Bmesg BByytes Smesg SBytes

Rmesg Rbytes

format STDOUT =
@<
$g roup, $bmesg, Sbbytes,$smesg,$sbytes,Srmesg,$ rbytes

,
. :
Hame
getreminded.com
gillette.com

Bmesg BByytes Smesg SBytes


1
1

3420
984

1
1

3420
984

Rmesg Rbytes

7812

gis.net
globalserve. net
globe.com

379

3
1
0

10830
1245
0

3
1
0

10830

1245
0

0
1

787
0
2040

, , , . - .
, . ,
.
1
, , Perl. , , , .

, . , ,
,
.

Perl. Perl.
Perl , Perl. ,
DBI, Perl ,
MySQL, Oracle MS-SQL.
.
, !
,
Perl.
.
.
, ?
- wtmp
. , -

NFS. ,
.
Perl Berkeley
DB. Perl ,
DB Perl, DB -

9.
(http://www.sleepycat.com)
Perl .
(. 9.4).
9.4. Perl

- - -

Unix


NT/2000 MacOS

dbm
Sdbm

1 ( -

dbm

Gdbm
DB

'

.
(http://www.roth.net).

Berkeley-DB,
.
, , . .
, .
.
last, pack() wtmp. , :
use DB_File;
use FreezeThaw qw(freeze thaw);
use Sys:'.Hostname; (t
use Fcntl;
ft
0_CREAT 0_RDWR
# last
(- "/bin/last" and Slastex = "/bin/last") or
(-x "/usr/ucb/last" and Slastex = "/usr/ucb/last");
Suserdb
= "userdata"; tt
Sconnectdb = "connectdata"; #
$thishost = &hostname;
ope'n(LAST, "$lastex|") or
die " Slastex:$!\n";

-,

381

# last
while (<LAST>){
next if /~reboot\s/ or /~shutdown\s/ or
/~ftp\s/
or /"wtmp\s/;
($user,$tty,$host,$day,$mon,$date,$time) = split;
next if $tty =" /~:0/ or $tty =" /~console$/;
next if (length($host) < 4);
$when = $mon." ",$date." ",$time;
tt
push(@{$users{$user}}, [$thishost,$host,$when]);
push(@{$connects{$host}}, [$thishost,$user,$when]);
closed-AST) ;
# ( );
# , re: $DB_BTREE
tie %userdb, "DB_File",$userdb,0_CREAT|0_RDWR, 0600, $DB_BTREE
or die " Suserdb /:$!\"

freeze
foreach $user (keys %users){
if (exists $userdb{$user}){
(Suserinfo) = thaw($userdb{$user});
push(@{$userinfo},@{$users{$user}});
$userdb{$user}=freeze Suserinfo;
}
else {
Suserdb {$user}=f reeze $users{$user};
untie %userdb;
#
tie %connectdb, "DB_File",$connectdb,0_CREAT|0_RDWR,
0600, $DB_BTREE
or die " Sconnectdb / :$!\"
foreach $connect (keys %connects){
if (exists $connectdb{$connect}){
(Sconnectinfo) = thaw($connectdb{$connect});
push(@{$connectinfo},@{$connects{$connect}});
$connectdb{$connect}=f reeze($connectinfo);
} .
else {
$connectdb{$connect}=f reeze($connects{$connect});
untie %connectdb;

382

9.

last :
1. .
2. ,
:
$users{username} =
[[current host, connecting host, connect time],
[current host, connecting host, connect time]
$connects{host} =
[[current host, usernamel, connect time],
[current host, username2, connect time],

3. .
, . %userdb %connectdb .1
, Perl
. . ?
FreezeThaw ,
. FreezeThaw Perl . , ,
Data: : Dumper (Gurusamy Sarathy) (
Perl) Storable (Raphael Manfredi). FreezeThaw
, .
,
, , .
, . , '

. , 10
DB_File
BTREE, , ,
.

, DB_HASH 1.85, #
BTREE, , .
DB .

383

, ,
.
,
,
.

- wtmp.
, ,
( , ), . , , , . , NFS
, ,
.
, , , :
use DB_File;
use FreezeThaw qw(freeze thaw);
use Fcntl;
# , ,

($user,$ignore) = @ARGV;
# ,
$userdb
="userdata";
$connectdb ="connectdata";
tie %userdb, "DB_File",$userdb,0_RDONLY,666,$DB_BTREE
or die " Suserdb :$!\";
tie %connectdb, "DB_File",$connectdb,0_RDONLY,666,$DB_BTREE
or die " $connectdb :$!\";
, ,
. :
,
#
unless (exists $userdb{$user}){
print " .,\";
untie %userdb;
untie %connectdb;
exit;

384

9.
>

(Suserinfo) = thaw($userdb{$user});
print " first host contacts from $user --\n";
foreach Scontact (@{$userinfo}){
next if (defined Signore and $contact->[1] =" /$ignore/o);
print $contact->[1] . " -> " . $contact->[0] .
" on ".$contact->[2]."\n";
$otherhosts{$contact->[1]}='';
: , thaw().
, . ,
, , %otherhosts.
. , , , ,
.
, , ,
(. . ) .
, . , , , %userseen:
print "-- other connects from source machines --\n";
foreach $host (keys %otherhosts){
next if (defined Signore and $host =~ /$ignore/o);
next unless (exists $connectdb{$host});
(Sconnectinfo) = thaw($connectdb{$host});
foreach $connect (@{$connectinfo}){
next if (defined Signore and $connect->[0] =" /$ignore/o);
$userseen{$connect->[1]}='';

'
, '
, '
:
foreach $user (sort keys %userseen){

385

next unless (exists $userdb{$user});


(Suserinfo) = thaw($userdb{$user});
foreach Scontact (@{$userinfo}){
next if (defined Signore and $contact->[1] =" /$ignore/o);
write if (exists $otherhosts{$contact->[1]});

:
untie %userdb;
untie %connectdb;
format STDOUT =
@ @< -> (>< on @<'
$user. " : ", $contact->[1], $contact->[0], $contact->[2]
( , ):
-- first host contacts from baduser -badhostl.exampl -> machine1.ccs.neu.edu on Jan 18 09:55
badhost2.exampl -> machine2.ccs.neu.edu on Jan 19 11:53
-- other connects from source machines -baduser2: badhostl.exampl -> machine2.ccs. neu.e on Dec 15 13:26
baduser2: badhost2. exampl -> machine2.ccs. neu.e on Dec 11 12:45
baduserS: badhostl.exampl -> machine1.ccs.neu.ed on Jul 13 16:20
baduser4: badhostl.exampl -> machine1.ccs.neu.ed on Jun 9 11:53
baduser: badhostl.exampl -> machine1.ccs.neu.ed on Jan 18 09:55
baduser: badhost2. exampl -> machine2.ccs. neu.e on Jan 19 11:53
,
, . ,
(thaw()) , ,
(freeze()) .
. , .
SQL
.
SQL ( )
, SQL. , SQL, D SQL, .

386

__

9.

:
use DBI;

use Sys: : Hostname;

$db = "dnb"; 8
8 last
(- "/bin/last" and $lastex = "/bin/last") or
(-x "/usr/ucb/last" and Slastex = "/usr/ucb/last");
8 Sybase "dnb",
8
$dbh = DBI->connect('dbi:Sybase: ', 'dnb 1 ,$ARGV[0]);
die " : $DBI: : errstr\n"
unless (defined $dbh);
,
$dbh->do("use $db") or
die " $db: ".$dbh->errstr. "\n";
ft lastinfo,
unless ($dbh->selectrow_array(
q{SELECT name from sysobjects WHERE name="lastinfo"})){
$dbh->do(q{create table lastinfo (username char(8),
localhost char(40),
otherhost varchar(75),
when char(18))}) or
die " lastinfo: ".$dbh->errstr. "\n";
Sthishost = &hostname;
$sth = $dbh->prepare(
qq{INSERT INTO lastinfo(username, localhost, otherhost.when)
1
VALUES (?, ' Sthishost , ?, ?)}) or
die " insert: ".$dbh->errstr."\n";
open(LAST, "$lastex|") or die " $lastex:$!\r>
while (<LAST>){
next if /~reboot\s/ or /~shutdown\s/ or
/~ftp\s/
or /"wtmp\s/;
($user,$tty,$host,$day,$mon,$date, Stime) = split;
next if $tty =" /~:0/ or $tty =" /"consoles/;
next if (length(Shost) < 4);
Swhen = Smon." ",$date." ".Stime;
$sth->execute($user, $host, Swhen);

387

close(LAST);
$dbh->disconnect;
lastinfo username, localhost,
otherhost when. last,
.
.
SQL-, Perl
DBI ODBC,
7 SQL:
-- ?
select count (*) from lastinfo;

10068
-- ?
select count (distinct username) from lastinfo;

237
-- ?
select count (distinct otherhost) from lastinfo;

1000
-- "dnb"?
select distinct localhost from lastinfo where username = "dnb";
localhost
hostl
host2
,
, .
. ,
.
- . ,
- .

388

9.

CPAN

Win32: : EventLog ( ActivePerl)


Logfile: : Rotate
Getopt : : Long ( Perl)

0.062

PAULG

1.03
2.20

Time : : Local ( Perl)


SyslogScan

RHNELSON

0.32

DB_File ( Perl)
FreezeThaw

PMQS
ILYAZ

1.72

1.01

Sys : : Hostname ( Perl)


Fcntl ( Perl)
DBI

0.3

1.03

TIMB

1.13


Essential System Administration, (2nd Edition), Eleen Frisch (O'Reilly, 1995). , syslog.
http://www.heysoft.de/index.htm -
(Frank Heyne) - , Win32. Event Log.
http://www.le-berre.com/ - (Philippe Le Berre); W i n 3 2 : :
EventLog Win32.
Managing NT Event Logs with Perl for Win32, Bob Wells, Windows
NT Magazine, February/March 1998.
Practical Unix & Internet Security, (2nd Edition), Simson Garfinkel,
Gene Spafford (O'Reilly, 1996). ( ) syslog,
tcpwrappers.
Windows NT Event Logging, James D. Murray (O'Reilly, 1998).



SNMP






10

.
,
:
1. . ,
, ,
( ),
( ), (),
() . .
- .
2. , - , , , - . ,
, - ; - , , , - . .
3. , - . ,
, . ,
, ,

390

10.
( ), . , D.

.
, , , ,
.
, . , .
, , , ? -, ? "}
, ,
, .
- . , ;
,
, , . . , , , .
,
- .
,
, ,
, . -
- , , ,
. Perl.



. , -
.
, ,
, -
.
. -
-

I.

391

/bin/login, msgina.dll Finder, , , , .



- , .
, ,
,
( /etc/passwd msgina.dll). ,
, .
, . , . , ,
( ). , ,
.
, -
stat() lstat(). .

, Unix, . lstat() , , . , lstat(), ,
stat().
stat() IstatQ :
@information = stat("filename");
3 ,
File: :Stat ,
, - .
, statQ IstatQ,
, stat () Istat () Unix, Perl-
, Unix. (. 10.1).
, stat()
Windows NT/2000 MacOS. Unix.

392

10.

10.1. , statf)
MacOS
Unix
NT/2000
( - ( vRef Num)
0

)
1

Inode

( 0)

( f ilelD/dirlD)

(
)

( 777
, 666 ,
444
)

() ( NTFS)

( 1)

- ( 0)

( 0)

- ( 0)

( 0)

( ( null)
-
(
)
)

( (
- )

(
66 , Unix,
1/1/1904,
, 9)
(
9 -
1/1/1904 ,
8)

10 - ( - (
1/1/1904, inode - )

)

11

/

( null)

12

( null)

, MacOS
, UTC. MacOS
-
,
-0500, , time( )
, .

393

, , He-Unix- Perl stat() lstat() . , Perl: :GetFileInfo() Win32: :FileSecurity: :Get(), 2


.
stat( ) ,

. , , -
. , lstat( ) . 8- ( ),
.
- filename, IstatO , - filename,
lstat( ) , filename.
use Getopt: :Std;
#
# &printchanged()
@statnames = qw(dev ino mode nlink uid gid rdev
size mtime ctime blksize blocks);
getopt('p:c: ');
die ": $0 [-p <filename>|-c <filename>]\n"
unless ($opt_p or $opt_c);
if ($opt_p){
die " $opt_p:$!\n"
unless (-e $opt_p);
print $opt_p, "|", joinC , (lstat($opt_p))[0. .7,9. .12]), "\n";
exit;
if ($opt_c){
open(CFILE,$opt_c) or
die " $opt_c:$!\n";
while(<CFILE>){
chomp;
@savedstats = split( ' \ l ');
die " ,
$savedstats[0]\n"
unless ($#savedstats == 12);
(Scurrentstats = (lstat($savedstats[0]))[0. .7, 9. . 12];

# , -
&printchanged(\@savedstats,\@currentstats)
if ("@savedstats[1..13]" ne "@currentstats");

10.

close(CFILE);
#
sub printchangedf
my($saved,$current)= @>_;
it ,
# ,
print shift @{$saved}, ":\n";
for (my $i=0; $i < ${$saved} ;$!++){
if ($saved->[$i] ne $current->[$i]){
print "\t".$statnames[$i]. " is now ".$current->[$i];
print " (should be ".$saved->[$i]. ")\n";

checkfile -p /etc/
passwd checksumfile. checksumfile
, :
/etc/passwd | 1792 | 11427 | 33060 | 1 | 0 | 0 | 24959 | 607 | 921016509 | 921016509 | 8192 | 2
, . checkfile - checksumfile . , /etc/passwd, , :
/etc/passwd:
size is now 606 (should be 607)
mtime is now 921020731 (should be 921016509)
ctime is now 921020731 (should be 921016509)
,
, . 6'
( ):
if ("@savedstats[1. . 12]" ne "@currentstats");
Perl ,
:
join(" ",@savedstats[1. . 12]))
.
,
. &

395

, perlfaq, Perl.1
, , .
, , -
, . , , . Perl u t i m e ( ) ,
. .
- , - (message-digest algorithms ). (Ron Rivest)
RSA Data Security, Inc. MD5 Message-Digest Algorithm RFC1321:
(message digest fingerprint) 128 . ,
,
; , .
, MD5,
. , , ,
.
Perl - D i g e s t : : MD5
Digest.
Digest: :MD5 . Digest:: MD5,
add addf ile(),
.
MD5
Unix:
use Digest:;MD5 qw(md5);
$md5 = new Digest::MD5;
open(PASSWD,"/etc/passwd") or die " passwd:$!\n";
$md5->addfile(PASSWD);
close(PASSWD);
print $md5->hexdigest."\n";
Digest:: MD5 , . ,
:
perlfaql.pod, perlfaq2.pod ... perlfaq[N].pod. - . ..

396

10.
use Digest: :MD5 qw(md5);
open(PASSWD, "/etc/passwd") or die " passwd:$!\n";
print Digest: :MD5->new->addfile(PASSWD)->hexdigest, "\n";
close(PASSWD);
:
a6f905e6b45a65a7e03d0809448b501c
, . ,
:
335679c4c97a3815230a4331a06df3e7
.
MD5:
use Getopt: :Std;
use Digest: :MD5 qw(md5);
@statnames =
qw(dev ino mode nlink uid gid rdev size mtime ctime blksize blocks md5);
getopt('p:c: ');
die ": $0 [-p <filename>|-c <filename>]\n"
unless ($opt_p or $opt_c);
if ($opt_p){
die " $opt_p:$!\n"
unless (-e $opt_p);
open(F, $opt_p) or die " $opt_p:$!\n";
Sdigest = Digest: :MD5->new->addfile(F)->hexdigest;
close(F);
print $opt_p, T'.JoinC , (lstat($opt_p))[0. .7,9. .12]),
"I Sdigest", "\n";
exit;
if ($opt_c){
open(CFILE,$opt_c) or
die " $opt_c:$!\n";
while (<CFILE>){
chomp;
@savedstats = split('\l');
die " \'$savedstats[0]\' line.\n"
unless ($#savedstats == 13);

397

@currentstats = (lstat($savedstats[0]))[0. .7,9. . 12];


open(F, $savedstats[0]) or die " $opt_c:$!\n"
push(@currentstats, Digest: :MD5->new->addfile(F)->hexdigest);
close(F);
&printchanged(\@savedstats,\@currentstats)
if ("@savedstats[1. .13]" ne "@currentstats");
}
close(CFILE);

sub printchanged {
my($saved,$current)= @_;
print shift @{$saved}, ":\n";
for (my $i=0; $i <= $ft{$saved};$i++){
if ($saved->[$i] ne $current->[$i]){
print " ".$statnames[$i]. " is now ".$current->[$i];
print " (".$saved->[$i].")\n";


, . ,
, ? NIS DNS 5 TCP/IP.
. , (. . )
, , , DNS- ,
:
use Net::DNS;
: -
# , , -
ft
Sserver = new Net::DNS::Resolver;
$server->nameservers($ARGV[0]);
print STDERR " ...";
@zone = $server->axfr($ARGV[1]);
die $server->errorstring unless (defined @zone);
print STDERR ".\n";

398

10.

for $record (@zone){


$record->print;
MD5.
, :
use Net: :DNS;
use FreezeThaw qw(freeze);
use Digest: :MD5 qw(md5);

Sserver = new Net: : DNS: : Resolve r;


$server->nameservers($ARGV[0] ) ;
print STDERR " ...";
teone = $server->axfr($ARGV[1]);
die $server->errorstring unless (defined @zone);
print STDERR ". \n";
$zone = join('',sort map(freeze($_),@zone));
print "MD5 fingerprint for this zone transfer is: ";
print Digest: :MD5->new->add($zone)->hexdigest, "\n";
MD5 (), , @zone. :
$zone = join('',sort map(f reeze($_),@zone));
@zone
FreezeThaw,
9 .
, . ,
.
- , , ,
. 5.
,
.
, ,
. , :
- MD5

?

399

- ,
?

- - MD5 ?
, , , - Perl,
?
( ): , ( , , Perl . .) , .
- .
-, .


,
. . -
. ,
.


,
. , ,
. , , Perl .

. ( ), ,
,
, , . .

. ,
, -,
. , , - .

402

10.
$__<_0>.
, :
use Getopt: :Std;
#
getopts( 'ihf :l:m:u: ' ); tt ,
&usage if (defined $opt_h);

Smaxdomains = (defined $opt_m) ? $opt_m : 3;
, ( ) - 9.
.
, , unpack(),
:
Slastex = (defined $opt_l) ? $opt_l : "/usr/ucb/last";
open(LAST, "$lastex| ") j| die " $lastex:$!\n";
, ,
,
last. , - , .
, :
Suserinfo { laf } = [ 'ccs.neu.edu', 'xerox.com', 'foobar.edu' ]
, laf ccs.neu.edu, xerox.com foobar.edu.
, last. :
cindy
michael
david
deborah
barbara
jerry

pts/10
pts/3
pts/5
pts/5
pts/3
pts/3

sinai. ccs. neu.ed


regulus.ccs.neu.
fruity-pebbles.
grape-nuts. ccs. n
152.148.23.66
nat16. aspentec.c

Fri
Fri
Fri
Fri
Fri
Fri

Mar
Mar
Mar
Mar
Mar
Mar

27
27
27
27
27

13:51
13::51
13 :48
11: 43 10.48 27 09 :24 -

still
still
still
11 53
13 :20
09 :26

logged in
logged in
logged in
(00 :09)
(02 :31)
(00 :01)

, ( 3- ) last
. 9 ,
.
, '
.

403

while ,
, . ,
- (, split( )) - . ,
:
while (<LAST>){
#
next if /~reboot\sl"shutdown\srftp\s/;
-
8 , ,
it ( $opt_u getopts).
next if (defined $opt_u && !/"$opt_u\s/);
# X
next if Y:0\s+:0/;
# ,
($user, $tty,$host) = split;
# , ""
8
next if (length(Suser) < 2);
# ,
next if $host /\./\
tt (. )
$dn = &domain($host);
ft ,
next if (length ($dn) < 2);
ft , ,
-f
next if (defined $opt_f && ($dn =" /~$opt_f/));
,
ft
#
unless (exists $userinfo{$user}){
$userinfo{$user> = [$dn];
}
ft ;
8 .
else {
&AddToInfo($user,$dn);
closed-AST) ;

404

10.
,
.
&domain() , . .
, . , :
1. .
IP-. ,
-i, , IP- -
, .
,
. 192.168.1.10 192.168.1.12
. , ,
, , ( ). -i, IP .
2. , . , , grape-nuts, ccs. n nat16.aspentec.c. , ,
. &AddToInfo() ,
. .
:
#
ft
sub domain!
IP-

if ($_[0] =- /-\d+V\d+V\d+V\d+$/) {
-1,
# IP-
unless (defined $opt_i){
return $_[0];
,
else {
$_[0] =- /(.*)V\d+$/;
return $1;

# IP-
else {

405

# ,

$_[0] =

$_[0] =- /.]. (.*)/;
return $1;


. &AddToInf ( ) -.
,
.
,
:
ccs. neu.edu
ccs. neu.ed
ccs. n
, ,
:
1 . -, ?
2. ?
3.
?
- , , , . 3, , , , . ,
,
.
, . , ,
:
sub AddToInfof
my($user, $dn) = @_;
for (@{$userinfo{$user}}){

406

10.
# 1- 2- :
# ?
return if (index($_,$dn) > -1);
3- , ,

if (index($dn,$J > -1){
$_ = $dn; tt

return;

# ,
push @{$userinfo{$user}}, $dn;
@{$userinfo{$user}} , .
, , $dn. ,
, . .
.
, 3. , , . ,
, .
, . , f f reach Perl. $_
f , Perl . . ,
. ,
.
,
. ,
, '
(. .
). , ,
, :
for (sort keys %userinfo){
if ($#{$userinfo{$_}} > $maxdomains){
print "\n\n$_ c:\n";
print join("\n", sort @{$userinfo{$_}});
}
}
print "\n";

SNMP

407

, , , , . , :
username :
38.254.131
bu.edu
ccs.neu.ed
dac.neu.ed
hials.no
ipt.a
tntl.bosl
tntl.bost
tntl.dia
tnt2.bos
tntS.bos
tnt4.bo
toronto4.di
,
. toronto4.di
, hials.no . !
,
, ,
tcpwrappers. , .
SNMP

. . (SNMP) ,
. SNMP,
( ) .
, -
. . SNMP, SNMP.
SNMP Perl
SNMP Perl - , , UCD-SNMP, . -

408

10.
,
. ,
.
: , SNMPvl SNMPv2C,
, (community name) .
, , ,
.
, ,
, .
.
.
SNMP- Perl, SNMP.
: N e t : : SNMP . (David M. Town), SNMP_Session.pm, (Simon Leinen) SNMP Extension Module v3.1.0 for the
UCD SNMPvS Library ( SNMP vS.l.O UCD SNMPvS, SNMP - ) . . (G.S. Marzot). SNMPvl. Net: :SNMP SNMP SNMPv2.
SNMP SNMPvS.
SNMP,
. (Net.: SNMP SNMPJSession.pm) Perl, a SNMP UCD-SNMP.
SNMP - ( , UCD-SNMP
).
UCD-SNMP ,
. , SNMP

(Management Information Base, MIB) SNMP-na, . ( S N M P : : M I B .
Compiler (Fabien Tassin) 1)>
, , SNMP .
Perl.
,
interfaces. ifNumber. MO
Net: : SNMP :

SNMP

409

use Net::SNMP;
it
($session,$error) = Net::SNMP->session(Hostname => $ARGV[0],
Community => $ARGV[1]);
die " : $error" unless (Ssession);
tt iso.org. dod. internet, mgmt.mib-2. interfaces. ifNumber.O =
1.3.6.1.2.1.2.1.0
$result = $session->get_request("1.3.6.1.2.1.2.1.0");
die " : ",$session->error unless (defined $result);
$session->close;
print " : ".$result->{"1.3.6.1.2.1.2.1.0"}."\n";
Ethernet, : : 2;

Ethernet , : 3; : 7.

(Object Identifiers, OID) . N e t : : S N M P ,
SNMP_Session.pm
SNMP. -
, SNMP, , SNMP MIB.
,
SNMP: :MIB: :118/_. (Mike Mitchell) SNMP_Session. pm ( SNMP: : lit il
(Wayne Marquette),
SNMP).
,
,
, SNMP, MIB. ARP (Address Resolution Protocol, )
:
use SNMP;
#
Ssession = new SNMP::Session(DestHost => $ARGV[0], Community => $ARGV[1],
UseSprintValue => 1);

410

10.
die " : $SNMP: :Session: :ErrorStr" unless
(defined $session);
getnext
$vars = new SNMP: :VarList(['ipNetToMediaNetAddress'],
[ 'ipNetToMediaPhysAddress' ]);
tt
($ip,$mac) = $session->getnext($vars);
die $session->{ErrorStr} if ($session->{ErrorStr});
#
while (!$session->{ErrorStr} and
$$vars[0]->tag eq "ipNetToMediaNetAddress"){
print "Sip -> $mac\n";
($ip,$mac) = $session->getnext($vars);
};
:
192.168.1.70 -> 8:0:20:21:40:51
192.168.1.74 -> 8:0:20:76:7:85
192.168.1.98 -> 0::95::5:1
,
Net : : SNMP. :
use SNMP;
Ssession = new SNMP: :Session(DestHost => $ARGV[0], Community => $ARGV[1],
UseSprintValue => 1);
SNMP ,
Net: :SNMP. U s e S p r i n t V a l u e => 1 , . , Ethernet- .
# getnext
$vars = new SNMP: :Varl_ist([ 'ipNetToMediaNetAddress' ],
[ 'ipNetToMediaPhysAddress' ]);
SNMP , sysDescr. , ,
Varbind. ^
, . , 6
g e t - n e x t - r e q u e s t
getnextO,
. , SNMP
bind, .

SNMP

411

, Varbind getnext, .
Varbind - Perl-,
: obj, iid, val type. o b j lid.
, o b j - , , obj
.
leaf identifier, . . , . IpNetToMediaNetAddress - :
.iso.org.dod.internet.mgmt.mib2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaNetAddress
Varbind- iid,
(instance identifier).
( system. sysDescr. 0), ,
. , iid
, . ,
Ethernet-. get
Varbind- o b j iid. getnext iid , . . .
V a r L i s t ( ) ,
Varbind,
o b j . getnext ():
#
($ip,$mac) = $session->getnext($vars);
die $session->{ErrorStr} if ($session->{ErrorStr});
getnextQ , , Varbind.
g e t n e x t ( ) , :
while (!$session->{ErrorStr} and
$$vars[0]->tag eq "ipNetToMediaNetAddress"){
print "Sip -> $mac\n";
($ip,$mac) = $session->getnext($vars);
};
,
SNMP. , , ,
, .
: Ethernet (switched Ethernet network)
. , ,
Ethernet- , .

412

10.
Ethernet-, (
, 5, ), ,
,
- ,
,
Cisco Catalyst 5500;
MIB. , ,
. , . .
,
MIB.
Cisco, , :
vlanTable, enterprises.Cisco.workgroup.ciscoStackMIB.vlanGrp CISCO-STACK-MIB.
dotldTpFdbTable ( ),
dotldBridge. dotldTp RFC1493 BRIDGEMIB.

dotldBasePortTable, d o t l d B r i d g e . d o t l d B a s e
RFC.

ifXTable, RFC1573IF-MIB ().


? -
, ,
. VLAN (Virtual Local Area
Networks, ),
. Cisco ,

. .
Ethernet-
(bridgeport) , . , '
,
. , . .
Ether
net-, .
, (bridge port)
, ( ), dotldBasePortTabl

SNMP

413

. , i f X T a b l e
.
, (. 10.1).
,
:
use SNMP;
MIB, ,
,
$ENV{'MIBFILES'}=
"CISCO-SMI. my :FDDI-SMT73-MIB. my :CISCO-STACK-MIB. my :BRIDGE-MIB. my";
#
#
Ssession = new SNMP: : Session (DestHost => $ARGV[0],
Community => $ARGV[1]);
die " : $SNMP: :Session: :ErrorStr" unless
(defined $session);
n enterprises. Cisco. workgroup. ciscoStackMIB. vlanGrp. vlanTable. vlanEntry
CISCO-STACK-MIB
$vars = new SNMP: :Varl_ist([ 'vlanlndex' ]);
$vlan = $session->getnext($vars);
die $session->{ErrorStr} if ($session->{ErrorStr});
while (!$session->{ErrorStr} and $$vars[0]->tag eq "vlanlnuex"){
Ha CISCO CATALYST 5XXX 1000
( , ,
# )
push(@vlans,$vlan) if $vlan < 1000;
$vlan = $session->getnext($vars);
undef $session,$vars;
#
# , , #
foreach $vlan (@vlans){
# "
"
$session = new SNMP: :Session(DestHost => $ARGV[0],
Community => $ARGV[1]. "@". $vlan,

414

10.

'

vlanTable
vtanindex
'*

;lanindex
in i |
I

>

' -JU-u-i
4-

dotldTpFdbTable

. . . 1 |^4- dotldTpFdb&rtry

^^
,-.,--._.__-.-,.-,-,

__.__-. **"****
,_|tfTpfdbAiidress 1 ^IcTT^WMt

^^
*
dotldTpFdbAddress
doHdTpWbPori
> ~J"~l"

<

vfanlndex

1
r

...

l i1

dottdBasePortTable

\
U-!- jotldBasePortEntry
1 '

**
dotidSas*rtidex,<pOTt>

1,<>
444_*^-,^"
7'1
ifXTable

11
I!

"
4

,_.

*
n

ffltene.<i!num>
...
ifNatne,<tom>

,.

,'
. 10.1. SNMP-,
Cisco 5000

SNMP

415
UseSprintValue => 1);

die " : $SNMP: -.Session: :ErrorStr"


unless (defined Ssession);

dotldBridge. dotldTp. dotldTpFdbTable. dotldTpFdbEntry
# RFC1493 BRIDGE-MIB

$vars = new SNMP: :VarList([ 'dotldTpFdbAddress'], [ 'dotldTpFdbPort' ]);


(Smacaddr, Sportnum) = $session->getnext($vars);
die $session->{ErrorStr} if ($session->{ErrorStr});
while (! $session->{ErrorStr} and
$$vars[0]->tag eq "dotldTpFdbAddress")!
# dot1dBridQe.dot1dBase.dot1dBasePort_Table.dot1dBasePortEntry
ft RFC1493 BRIDGE-MIB
$ifnum =
(exists $ifnum{$portnum}) ? $ifnum{$portnum} :
($ifnum{$portnum} =
$session->get("dot1dBasePortIf!ndex\.$portnum"));
# ifMIB.ifMIBObjects.ifXTable.ifXEntry RFC1573 IF-MIB
Sportname =
(exists $portname{$ifnum ? $portnaffte{$ifnum} :
($portname{$ifnum}=$session->get("ifName\.$ifnum"));
print "$macaddr $vlan $portname\n";
($macaddr, Sportnum) = $session->getnext($vars);
1

undef $session, $vars, %ifnum. %portname ;

}
,
.
:
$ENV{'MIBFILES'}=

"CISCO-SMI. my :FDDI-SMT73-MIB. my :CISCO-STACK-MIB. my: BRIDGE-MIB. my";

-w, , Perl , ,
. , undef Ssession, $vars, M i f n u m , %portname;
: (undef Ssession), $vars, %ifnum, %portname;.
undef (Ssession, $vars, %ifnum, %portname); ,
: undef Ssession, undef $vars, undef %ifnuffl, undef %portname;. -. ..

416

10.
MIBFILES UCD-SNMP. , MIB. MIB - FDDI-SMT73-MIB.my. QH
- , CISCO-STACK-MIB.my ;
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, Integer32, IpAddress, TimeTicks,
Counter32, Counter64, NOTIFICATION-TYPE
FROM SNMPv2-SMI
DisplayString, RowStatus
FROM SNMPv2-TC
fddimibPORTSMTIndex, fddimibPORTIndex
FROM FDDI-SMT73-MIB
OwnerString
FROM IF-MIB
MODULE-COMPLIANCE, OBJECT-GROUP
FROM SNMPv2-CONF
workgroup
FROM CISCO-SMI;
, fddimibPORTSMTIndex fddimibPORTIndex, ()
, MIB .
MIB IMPORTS , . MIB IMPORTS MIB .
, :
Ssession = new SNMP::Session(DestHost => $ARGV[0],
Community => $ARGV[1]."@".$vlan,
UseSprintValue => 1);
, , ^LAN-NUMBER.
Cisco . '
Cisco
MIB, . &

, :
$ifnum =
(exists $ifnum{$portnum ? $ifnum{$portnum} :
($ifnum{$portnum} =
$session->get("dotldBasePortlfIndex\.Sportnum"));

417

. -, g e t ( ) .
- Varbind-:
($ifnum{$portnum}=$session->get([' dot "IdBasePort If Index', $portnum]));
-, , . get(), (%if num), , . , , . 1
(undef %ifnum) ,

.
SNMP . ,

. , , ,
.
:
"00
"00
"08
"08
"08

10
10
00
00
00

1F
1F
36
36
36

2D
2D
8

D1

F8
F8
9
16

FB
FD
03
03
03

"
"
"
"
"

1 1/1
1 1/1
115 2/18
115 2/3
115 2/15

.
. : , . .
, ,
, , . ,
, .

SNMP ( ,
, undef . 415, , . - . . .

418

10.
SNMP- (traps)), ,
- , .
, ,
SNMP .

Perl
, ,
Perl. , , , ,
, , - .
- , .
.
.
, - , .
. , , , . , , . .

netstat.
netstat , . . :
tcp
tcp
tcp
tcp

0
0
0
0

0
0
0
0

mailhub.3322
mailhub.3320
mailhub.1723
mailhub.1709

mail.mel.aone.ne.smtp ESTABLISHED
edunet.edunet.dk.smtp CLOSEJJAIT
kraken.mvnet.wne.smtp ESTABLISHED
plover.net.bridg.smtp CLOSEJJAIT

:
tcp
tcp
tcp
tcp

0
0
0
0

0
0
0
0

mailhub.3322
mailhub.3320
mailhub.1723
mailhub.1709

mail.mel.aone.ne'. smtp
edunet.edunet.dk.smtp
kraken.mvnet.wne.smtp
plover.net.bridg.smtp

SYN_RCVD
SYN_RCVD
SYN_RCVD
CLOSEJJAIT

,
(Denial of Service), SYN Flood,
SYN-ACK.
, TCP/IP, ,
.

419

TCP/IP- . , . ,
SYN ( SYNchronize - ).
, SYN-ACK,
( ACKnowledgment) ,
, . SYN-ACK , , SYN-ACK
. , .
, . SYN Flood, SYN,
.
SYN - S Y N . ,
. , ,
. netstat.
netstat ,
- . ,
- ,

. , .

. ping traceroute
, netstat, , . .
. Perl.
, , , , .
, .
: , ? ,
, |?
(Brian Mitchell), ftp://coast.cs.purdue.edu/pub/mirrors/ftp.saturn.net/clog. TCP-, . . SYN, clog libpcap Lawrence Berkeley National Laboratory's Network Re-

420

10.
search Group.
tcpdump. libpcapc ftp://ftp.ee.lbl.gov/libpcap.tar.Z Linux. libpcap
NT/2000 http://netgroup-serv.polito.it/windump/ http://
www.ntop.org/libpcap.html,
MacOS.
clog SYN :
02 11:21|192.168.1.51|1074|192.168.1.104|113
02 11:21|192.168.1.51|1094|192.168.1.104|23
,
192.168.1.51 192.168.1.104. -
113 (ident), - 23 (telnet).
clog , . ,
. fping .
III (Roland J. Schemers III). fping,
http://www.stanford.edu/~schemers/docs/fping/fping.html, -
ping Unix .
,
Perl:
Sclogex = "/usr/local/bin/clog"; ft / clog
$fpingex = "/usr/local/bin/fping -rl"; # / fping
Slocalnet = "192.168.1";

ft

open CLOG, "$clogex|" or die " clog:$!\n";


while(<CLOG>){
($date,$orighost,$origport,$desthost,$destport) = split(/\|/);
next if ($orighost =" /~$localnet/);
next if (exists $cache{$orighost});
print '$fpingex Sorighost';
$cache{$orighost}=1;
}
clog 6ecKOj
. ,
.
, ,
. -
ping, 14
, . -rl fpin&


fping ( ).

421

, . . clog, fping . :
199.174.175.99 is unreachable
128.148.157.143 is unreachable
204.241.60.5 is alive
199.2.26.116 is unreachable
199.172.62.5 is unreachable
130.111.39.100 is alive
207.70.7.25 is unreachable
198.214.63.11 is alive
129.186.1.10 is alive
, . , - ?
, ,
. -
. ping Perl
. ,
.
Net: : Ping (Russell Mosemann),
Perl, .
Net: : Ping ping : ICMP, TCP UDP. ICMP- (Internet Control
Message Protocol)- ping,
, ping.
:
1. , clog/fping,
Net: :Ping, ICMP, .
2. Perl MacOS ICMP. , ,
.
Net: :Ping - TCP UDP.
echo .
, , ICMP. ICMP
TCP/IP, echo.
, ICMP ,
ICMP- ,
.
Net: : P i n g - ,
ping:

422

10.
use Net::Ping;
$ = new Net::Ping("icmp");
:
if ($p->ping("host")){
print "ping succeeded.\n";
else{
print "ping failed\n";

clog. ,
MacOS. Perl, , libpcap,
, , Unix , .
, , - libpcap. tcpdump.
UCD-SNMP, tcpdump
libpcap , Perl,
, .
libpcap, Net: :Pcap,
(Peter Lister), (Tim Potter).
libpcap. ,
SYN, clog.
/ :
use Net: :Pcap;
,
$dev = Net: :Pcap: :lookupdev(\$err) ;
die " : $err\n" unless $dev;

die " :$\"
if (Net: :Pcap: :lookupnet($dev,\$netnum,\$netmask,\$err));
libpcap , , 0 -1 "
, , Net : : , die if . . . . () , .
,
( , 03

423

). Net: :Pcap: :open_live


, :
# ""
Sdescript = Net::Pcap::open_live($dev,100,1,1000,\$) ;
die " :$\" unless Sdescript;
libpcap ,
,
.
, , . SYN.
SYN? , , TCP-.
RFC973, TCP- (. 10.2).
0
0

1
1

1 2 3 4 5 6 7 8 9 0 1 ? 3 4 5 6
1

7 8 9 0 1 i2 i3 i4 5 6
i
i

7; 8 9 0

i E

1 1 |

I I I '

4- i t-

R S F
R S S I
G N

i l l ; ) | ||,

1 [ (

. 10.2. TCP-
S Y N - ,
SYN ( . 10.2). libpcap
, , , . , .
, , . 10.3.
, 13-
00000010 ( 2).
tcp[13] = 2. ,

10.
1
2
3
0
9 0 1 2 3 4 5 6 7 8 9_
0 1 2 3 4 5 6 7 8 9 n 1
0 1 I7 3 4 I 5 6 7 8 |

_
I I-I'-4- (
2
1
3
0
__
,.
I I "I t- 1 . _| 1_
6
7
5
4
i
, |
i
i
l
1 i 1 f
10
9
11
8
I
j
j
,. L -J f <
,..),.,(._
i ! !
s F

Y I
13
12
N N
,
f
, ,
i
i i i


i i
L
J <l< l .<

~~

. 10.3. TCP-
SYN,
tcp[13] & 2 != 0.
:
$prog = "tcp[13] = 2";
# " "
die " $prog\n"
if (Net::Pcap::compile($descript ,\$compprog,$prog,0,$netmask)) ;
die " \"
if (Net::Pcap::setfilter($descript,$compprog));
- libpcap. , . , , . :
1. ,
.
2. , (
.).
3. .
,
:

425

sub printpacketlength {
print length($_[2]),"\n";
}
, SYN:
die " : ".Net::Pcap::geterr($descript)."\n"
if (Net::Pcap::loop($descript,-1,\&printpacketlength, ''));
die " \"
if (Net::Pcap::close($descript));
-1 N e t : : :: 1( ) , .
.
SYN
, , . , SYN
(ping) . ; , SYN-.
5, DNS,
. (RFC) unpack(). (Tim
Potter) NetPacket: NetPacket: .'Ethernet, NetPacket: :IP, NetPacket: :TCP, NetPacket: :ICMP
. . : s t r i p ( ) decodeQ.
s t r i p ( ) , ,
. , TCP/IP- Ethernet - ,
, TCP, IP, ,
, Ethernet. $pkt TCP/IP-, NetPacket: .'Ethernet: :strip($pkt) IP- (
Ethernet). TCP- $pkt, NetPacket::IP::strip(NetPacket::Ethernet: :strip($packet))
IP-, Ethernet-.
decode() .
,
. :
NetPacket::TCP->decode(
NetPacket::IP::strip(NetPacket::Ethernet::strip($packet)))
:

src_port

TCP-

dest_port

TCP-

426

10.

Seqnum
Acknum
Hlen

Reserved

- TCP-
URG, , PSH, RST, SYN FIN

Flags
Winsize

Urg

TCP-

Options
Data

TCP-

Cksum

(. 10.2).
, :
$pt = NetPacket::TCP->decode(
NetPacket::IP::strip(
NetPacket::Ethernet::strip($packet)))->{dest_port};
- .
N e t : :
N e t : : PcapUtils.
, .
, , :
use Net::PcapUtils;
use NetPacket::Ethernet;
use NetPacket::IP;
use Net::Ping;
#
Slocalnet = "192.168.1";
SYN-
$prog = "tcp[13] = 2 and src net not $localnet";
$| = V, 8 STDIO
ping,
$ = new Net::Ping("icmp");
die " :".Net::Pcap::geterr($descript)."\n"
if (Net:-.PcapUtils: :open_live(\&grab_ip_and_ping, FILTER => $prog));
tt IP- , (
)

427

sub grab_ip_and_ping{
my ($arg,$hdr,$pkt) = @_ ;

IP-
$src_ip = NetPacket::IP->decode(
NetPacket: :Ethernet: :strip($pkt))->{src_ip>;
print "$src_ip is ".(($p->ping($src_ip)) ?
"alive" : "unreachable")."\n"
unless $cache{$src_ip}++;

1
, Perl
( , Perl-
) , , .

. Linux
. ,
. , , ,
. , , , . ,
, , , - , .
,
,
. , , .
N e t : : ,
N e t : : PcapUtils NetPacket:: * . !
, .

, , . , :
,
.

428

10.
,
. ,
, ,
.
, ,
. -
, ,
. -
, John the Ripper
(Solar Designer, ), LOphtCrack (Mudge, Weld
Pond, ) Crack (Alec Muffett, )).
,
, - .
, . Unix (
NT, MacOS) - libcrack, . Crack , , Crack,
, .
: FascistCheck(). :
,
Libcrack. NULL, , , , , . ,

Perl, 1,
, ,
. ,
, .
- libcrack http://www.users.dircon.co.uk/~crypto/.
. :
, , . , , -
ftp://ftp.ox.ac.uk/pub/wordlists. , libcrack , npasswd
( http://www.utexas.edu/cc/unix/software/npasswd/), Unix passwd, (Clyde Hoover).

429

( sort utils/mkdict),
.
, libcrack
, Perl. , Perl
gcc, gcc
libcrack. ,
.
libcrack.a , FascistCheck() Perl.
: XS SWIG. XS, . . , Perl.
Advanced
Perl Programming ( Perl)
(Sriram Srinivasan) (O'Reilly).
XS -
h2xs :
$ h2xs -A -n Cracklib
Writing Cracklib/Cracklib.pm
Writing Cracklib/Cracklib.xs
Writing Cracklib/Makefile.PL
Writing Cracklib/test.pl
Writing Cracklib/Changes
Writing Cracklib/MANIFEST
, (. 10.2).
10.2. , h2xs -A -n Cracklib

Cracklib /Cracklib.pm
Cracklib/ racklib.xs
Cracklib/Makefile.PL
Cracklib/test.pl
Cracklib / Changes
Cracklib /MANIFEST



Perl Makefile


,

,
. : .
libcrack:
char *FascistCheck(char *pw, char d i c t p a t h ) ;
Cracklib/Cracklib.xs :
PROTOTYPES: ENABLE

430

10.
char *
FascistCheck(pw,dictpath)
char *pw
char dictpath
PROTOTYPES Perl-
. , , ,

.
, :
CODE:
RETVAL = (char *)FascistCheck(pw,dictpath);
OUTPUT:
RETVAL
RETVAL - . Perl.
Perl, , FascistCheck(),
(.. OUTPUT) Perl- Cracklib: :FascistCheck(). .
, ,
. WriteMakef i l e ( ) Makefile.PL, , Perl libcrack.a. :
'LIBS'
=>[''], , '-1'
'MYEXTLIB' => '/usr/local/lib/libcrack$(LIB_EXT)' # cracklib
'DEFINE'
=>",
# , '-DHAVE_SOMETHING'
, . :
perl Makefile.PL

make

make install

:
use Cracklib;
use Term::ReadKey;
#
Sdictpath = "/usr/local/etc/cracklib/pw_dict";
print " : ";
ReadMode 2;

chomp($pw = ReadLine);S
ReadMode 0;
ft

print "\";

'

431

$result = Cracklib::FascistCheck($pw,Sdictpath);
if (defined $result){
print " , $result.\n";
}
else {
print " , !\n";
}
. ,
, .
-, , , .
- , .
. ,
10 , 1. .10. ok, not ok .
.
h2xs , . t ( ,
) test.pl t/cracklib.t.
Perl, t/'cracklib.t :

Sdictpath = "/usr/local/etc/pw_dict";
cracklib
%test =
("happy"
=> "it is too short",
"a"
=> "it's WAY too short",
"asdfasdf"
=> "it does not contain enough DIFFERENT characters",
"minicomputer" => "it is based on a dictionary word",
"1ftm2tgr3fts" => "");
8 , ,
# cracklib . , "ok",
-- "not ok"
Stestnum = 2;
foreach $pw (keys %test){
my (Sresult) = Cracklib:;FascistCheck($pw,Sdictpath);
if ((defined Sresult and $result eq $test{$pw}) or
('.defined Sresult and $test{$pw} eq "")){
print "ok ",$testnum++,"\n";
}
else {
print "not ok ",$testnum++,"\n";

10.

432

( %test ), , t/cracklib.t :
BEGIN {$|=1; print "1..1\n"; }

:
BEGIN { $| = 1; print "1..6\n"; }
make test Makefile
, , .
, ,
, ,
. Cracklib.pm
Changes, .
README INSTALL, ,
, , libernek,
. . test.pl MANIFEST, .
, , .
C r a c k l i b : : FascistCheck() , . ,
.

Getopt : : Std ( Perl)


Digest: :MD5
Met: : DNS

FreezeThaw
File : : Find ( Perl)
Net: :SNMP
SNMP
Net : : Ping ( Perl)
Net: :Pcap
Net: :PcapUtils
NetPacket
Term: :ReadKey

CPAN

1.01

GAAS
MFUHR
ILYAZ

0.3

DTOWN

3.01

GSM

3.10

RMOSE
TIMPOTTER
TIMPOTTER
TIMPOTTER
KJALB

2.02

2.09
0.12

0.03
0.01
0.01
2.14

433



http://www.securityfocus.com - , . ,
. auditing, file integrity
tripwire- .
MacPerl:Power and Ease, (Vicki Brown)
(Chris Nandor) (Prime Time Freeware, 1998).
noperlport
stat () .
RFC 132 l:TheMD5 Message-Digest Algorithm, R. Rivest, 1992.
http://www.tripwire.com/tripwire - . , - .
SNMP
60 RFC SNMP ( 100, SNMP ). RFC,
.
RFC1157:A Simple Network Management Protocol (SNMP), J. Case,
M. Fedor, M. Schoffstall, J. Davin, 1990.
RFC 1213:Management Information Base for Network Management of
TCP/IP-based internets:MIB-II, K. McCloghrie, M. Rose, 1991.
RFC1493:Definitions of Managed Objects for Bridges, E. Decker,
P. Langille, A. Rijsinghani, K. McCloghrie, 1993.
RFC1573:Evolution of the Interfaces Group ofMIB-II, K. McCloghrie,
F. Kastenholz, 1994.
RFC 1905:Protocol Operations for Version 2 of the Simple Network Management Protocol (SNMPv2), J. Case, K. McCloghrie, M. Rose,
S. Waldbusser, 1996.
RFC 1907-.Management Information Base for Version 2 of the Simple
Network Management Protocol (SNMPv2), J. Case, K. McCloghrie,
M. Rose, S. Waldbusser, 1996.
RFC2011:SNMPv2 Management Information Base for the Internet Protocol using SMIv2, K. McCloghrie, 1996.
RFC2012:SNMPu2 Management Information Base for the Transmission Control Protocol using SMIv2, K. McCloghrie, 1996.

434

10.
RFC2013:SNMPv2 Management Information Base for the User Datagram Protocol using SMIv2, K. McCloghrie, 1996.
RFC2274:User-based Security Model (USM) for version 3 of the Simple
Network Management Protocol (SNMPvS), U. Blumenthal, B. Wijnen,1998.
RFC2275:View-based Access Control Model (VACM) for the Simple Network Management Protocol (SNMP), B. Wijnen, R. Presuhn, K. McCloghrie, 1998.
RFC2578:Structure of Management Information Version 2 (SMIv2),
K. McCloghrie, D. Perkins, J. Schoenwaelder, 1999.
SNMP:
http://ucd-snmp.ucdavis.edu - UCD-SNMP.
http://www.cisco.com/public/sw-center/netmgmt/cmtk/mibs.shtml
MIB- Cisco.
.
http://www.snmpinfo.com - SNMPinf
( SNMP, comp.protocols.snmp, Understanding SNMP MIBs).
http://www.ibr.cs.tu-bs.de/ietf/snmpv3/ SNMP Version 3.

http://www.mrtg.org http://www.munitions.com/~jra/cricket/ - Multi Router Traffic Grapher (MRTG) Cricket ( Perl!). SNMP .
Understanding SNMP MIBs, David Perkins, Evan McGinnis (Prentice-Hall, 1996).
http://www.snmp.org - SNMP Research.
SNMP Framework
,
.protocols, snmp.

Advanced Perl Programming, Sriram Srinivasan (O'Reilly, 1997).
.
http://www.bb4.com http://www.kernel.org/software/mon/ - BigBrother , ,

(
MRTG Cricket).
http://www.tcpdump.org - libpcap tcpdump.
RFC793:Transmission Control Protocol, J. Postel, 1981.


RCS
, (Revision Control System, RCS)
. RCS, , , .
RCS- .

. ,
.
( ) , , ,
. ,
,
, , , . RCS.
RCS - . , RCS (. . ),
(check in) :
$ ci - filename
ci - check in, - ,
, . (. . ), RCS
, ,
RCS:
1. ,
RCS. filename.v