File Coverage

blib/lib/Net/EasyTCP.pm
Criterion Covered Total %
statement 592 1117 53.0
branch 238 560 42.5
condition 64 251 25.5
subroutine 35 51 68.6
pod 22 22 100.0
total 951 2001 47.5


line stmt bran cond sub pod time code
1             package Net::EasyTCP;
2              
3             #
4             # $Header: /cvsroot/Net::EasyTCP/EasyTCP.pm,v 1.144 2004/03/17 14:14:31 mina Exp $
5             #
6              
7 2     2   2514 use strict;
  2         4  
  2         88  
8 2     2   8 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $_SERIAL %_COMPRESS_AVAILABLE %_ENCRYPT_AVAILABLE %_MISC_AVAILABLE $PACKETSIZE);
  2         4  
  2         426  
9              
10 2     2   2224 use IO::Socket;
  2         162038  
  2         10  
11 2     2   3226 use IO::Select;
  2         3884  
  2         106  
12 2     2   2112 use Storable qw(nfreeze thaw);
  2         8530  
  2         1506  
13              
14             #
15             # This block's purpose is to:
16             # Put the list of available modules in %_COMPRESS_AVAILABLE and %_ENCRYPT_AVAILABLE and %_MISC_AVAILABLE
17             #
18             BEGIN {
19 2     2   6 my $version;
20             my $hasCBC;
21 2         10 my @_compress_modules = (
22              
23             #
24             # MAKE SURE WE DO NOT EVER ASSIGN THE SAME KEY TO MORE THAN ONE MODULE, EVEN OLD ONES NO LONGER IN THE LIST
25             #
26             # HIGHEST EVER USED: 2
27             #
28             [ '1', 'Compress::Zlib' ],
29             [ '2', 'Compress::LZF' ],
30             );
31 2         34 my @_encrypt_modules = (
32              
33             #
34             # MAKE SURE WE DO NOT EVER ASSIGN THE SAME KEY TO MORE THAN ONE MODULE, EVEN OLD ONES NO LONGER IN THE LIST
35             #
36             # HIGHEST EVER USED: E
37             #
38             [ 'B', 'Crypt::RSA', 0, 0 ],
39             [ '3', 'Crypt::CBC', 0, 0 ],
40             [ 'A', 'Crypt::Rijndael', 1, 1 ],
41             [ '9', 'Crypt::RC6', 1, 1 ],
42             [ '4', 'Crypt::Blowfish', 1, 1 ],
43             [ '6', 'Crypt::DES_EDE3', 1, 1 ],
44             [ '5', 'Crypt::DES', 1, 1 ],
45             [ 'C', 'Crypt::Twofish2', 1, 1 ],
46             [ 'D', 'Crypt::Twofish', 1, 1 ],
47             [ 'E', 'Crypt::TEA', 1, 1 ],
48             [ '2', 'Crypt::CipherSaber', 0, 1 ],
49             );
50 2         8 my @_misc_modules = (
51              
52             #
53             # MAKE SURE WE DO NOT EVER ASSIGN THE SAME KEY TO MORE THAN ONE MODULE, EVEN OLD ONES NO LONGER IN THE LIST
54             # (this is not as necessary as compress and encrypt since it's not transmitted to peers, but just in case...)
55             #
56             # HIGHEST EVER USED: 1
57             #
58             [ '1', 'Crypt::Random' ],
59             );
60              
61             #
62             # Let's reset some variables:
63             #
64 2         4 $hasCBC = 0;
65 2         4 $_COMPRESS_AVAILABLE{_order} = [];
66 2         6 $_ENCRYPT_AVAILABLE{_order} = [];
67 2         4 $_MISC_AVAILABLE{_order} = [];
68              
69             #
70             # Now we check the compress array for existing modules
71             #
72 2         4 foreach (@_compress_modules) {
73 4         8 $@ = undef;
74 4         6 eval {
75 4 100       248 eval("require $_->[1];") || die "$_->[1] not found\n";
76 2   50     219702 $version = eval("\$$_->[1]::VERSION;") || die "Failed to determine version for $_->[1]\n";
77             };
78 4 100       18 if (!$@) {
79 2         4 push(@{ $_COMPRESS_AVAILABLE{_order} }, $_->[0]);
  2         10  
80 2         12 $_COMPRESS_AVAILABLE{ $_->[0] }{name} = $_->[1];
81 2         6 $_COMPRESS_AVAILABLE{ $_->[0] }{version} = $version;
82             }
83             }
84              
85             #
86             # Now we check the encrypt array for existing modules
87             #
88 2         6 foreach (@_encrypt_modules) {
89 22         90 $@ = undef;
90 22         28 eval {
91 22 50       1144 eval("require $_->[1];") || die "$_->[1] not found\n";
92 0   0     0 $version = eval("\$$_->[1]::VERSION;") || die "Failed to determine version for $_->[1]\n";
93             };
94 22 50       142 if (!$@) {
95 0 0 0     0 if ($_->[1] eq 'Crypt::CBC') {
    0 0        
96 0         0 $hasCBC = 1;
97             }
98             elsif (($hasCBC && $_->[2]) || !$_->[2]) {
99 0         0 push(@{ $_ENCRYPT_AVAILABLE{_order} }, $_->[0]);
  0         0  
100 0         0 $_ENCRYPT_AVAILABLE{ $_->[0] }{name} = $_->[1];
101 0         0 $_ENCRYPT_AVAILABLE{ $_->[0] }{cbc} = $_->[2];
102 0         0 $_ENCRYPT_AVAILABLE{ $_->[0] }{mergewithpassword} = $_->[3];
103 0         0 $_ENCRYPT_AVAILABLE{ $_->[0] }{version} = $version;
104             }
105             }
106             }
107              
108             #
109             # Now we check the misc array for existing modules
110             #
111 2         4 foreach (@_misc_modules) {
112 2         4 $@ = undef;
113 2         2 eval {
114 2 50       134 eval("require $_->[1];") || die "$_->[1] not found\n";
115 0   0     0 $version = eval("\$$_->[1]::VERSION;") || die "Failed to determine version for $_->[1]\n";
116             };
117 2 50       24658 if (!$@) {
118 0         0 push(@{ $_MISC_AVAILABLE{_order} }, $_->[0]);
  0         0  
119 0         0 $_MISC_AVAILABLE{ $_->[0] }{name} = $_->[1];
120 0         0 $_MISC_AVAILABLE{ $_->[0] }{version} = $version;
121             }
122             }
123             }
124              
125             require Exporter;
126              
127             @ISA = qw(Exporter);
128             @EXPORT = qw();
129             $VERSION = '0.26';
130             $PACKETSIZE = 4096;
131              
132             #
133             # POD DOCUMENTATION:
134             #
135              
136             =head1 NAME
137              
138             Net::EasyTCP - Easily create secure, bandwidth-friendly TCP/IP clients and servers
139              
140             =head1 FEATURES
141              
142             =over 4
143              
144             =item *
145              
146             One easy module to create both clients and servers
147              
148             =item *
149              
150             Object Oriented interface
151              
152             =item *
153              
154             Event-based callbacks in server mode
155              
156             =item *
157              
158             Internal protocol to take care of all the common transport problems
159              
160             =item *
161              
162             Transparent encryption
163              
164             =item *
165              
166             Transparent compression
167              
168             =back
169              
170             =head1 SYNOPSIS
171              
172             =over 4
173              
174             =item SERVER EXAMPLE:
175              
176             use Net::EasyTCP;
177              
178             #
179             # Create the server object
180             #
181             $server = new Net::EasyTCP(
182             mode => "server",
183             port => 2345,
184             )
185             || die "ERROR CREATING SERVER: $@\n";
186              
187             #
188             # Tell it about the callbacks to call
189             # on known events
190             #
191             $server->setcallback(
192             data => \&gotdata,
193             connect => \&connected,
194             disconnect => \&disconnected,
195             )
196             || die "ERROR SETTING CALLBACKS: $@\n";
197              
198             #
199             # Start the server
200             #
201             $server->start() || die "ERROR STARTING SERVER: $@\n";
202              
203             #
204             # This sub gets called when a client sends us data
205             #
206             sub gotdata {
207             my $client = shift;
208             my $serial = $client->serial();
209             my $data = $client->data();
210             print "Client $serial sent me some data, sending it right back to them again\n";
211             $client->send($data) || die "ERROR SENDING TO CLIENT: $@\n";
212             if ($data eq "QUIT") {
213             $client->close() || die "ERROR CLOSING CLIENT: $@\n";
214             }
215             elsif ($data eq "DIE") {
216             $server->stop() || die "ERROR STOPPING SERVER: $@\n";
217             }
218             }
219              
220             #
221             # This sub gets called when a new client connects
222             #
223             sub connected {
224             my $client = shift;
225             my $serial = $client->serial();
226             print "Client $serial just connected\n";
227             }
228              
229             #
230             # This sub gets called when an existing client disconnects
231             #
232             sub disconnected {
233             my $client = shift;
234             my $serial = $client->serial();
235             print "Client $serial just disconnected\n";
236             }
237              
238             =item CLIENT EXAMPLE:
239              
240             use Net::EasyTCP;
241              
242             #
243             # Create a new client and connect to a server
244             #
245             $client = new Net::EasyTCP(
246             mode => "client",
247             host => 'localhost',
248             port => 2345,
249             )
250             || die "ERROR CREATING CLIENT: $@\n";
251              
252             #
253             # Send and receive a simple string
254             #
255             $client->send("HELLO THERE") || die "ERROR SENDING: $@\n";
256             $reply = $client->receive() || die "ERROR RECEIVING: $@\n";
257              
258             #
259             # Send and receive complex objects/strings/arrays/hashes by reference
260             #
261             %hash = ("to be or" => "not to be" , "just another" => "perl hacker");
262             $client->send(\%hash) || die "ERROR SENDING: $@\n";
263             $reply = $client->receive() || die "ERROR RECEIVING: $@\n";
264             foreach (keys %{$reply}) {
265             print "Received key: $_ = $reply->{$_}\n";
266             }
267              
268             #
269             # Send and receive large binary data
270             #
271             for (1..8192) {
272             for (0..255) {
273             $largedata .= chr($_);
274             }
275             }
276             $client->send($largedata) || die "ERROR SENDING: $@\n";
277             $reply = $client->receive() || die "ERROR RECEIVING: $@\n";
278              
279             #
280             # Cleanly disconnect from the server
281             #
282             $client->close();
283              
284             =back
285              
286             =head1 DESCRIPTION
287              
288             This class allows you to easily create TCP/IP clients and servers and provides an OO interface to manage the connection(s). This allows you to concentrate on the application rather than on the transport.
289              
290             You still have to engineer your high-level protocol. For example, if you're writing an SMTP client-server pair, you will have to teach your client to send "HELO" when it connects, and you will have to teach your server what to do once it receives the "HELO" command, and so forth.
291              
292             What you won't have to do is worry about how the command will get there, about line termination, about binary data, complex-structure serialization, encryption, compression, or about fragmented packets on the received end. All of these will be taken care of by this class.
293              
294             =head1 CONSTRUCTOR
295              
296             =over 4
297              
298             =item new(%hash)
299              
300             Constructs and returns a new Net::EasyTCP object. Such an object behaves in one of two modes (that needs to be supplied to new() on creation time). You can create either a server object (which accepts connections from several clients) or a client object (which initiates a connection to a server).
301              
302             new() expects to be passed a hash. The following keys are accepted:
303              
304             =over 4
305              
306             =item donotcheckversion
307              
308             Set to 1 to force a client to continue connecting even if an encryption/compression/Storable module version mismatch is detected. (Using this is highly unrecommended, you should upgrade the module in question to the same version on both ends)
309             Note that as of Net::EasyTCP version 0.20, this parameter is fairly useless since that version (and higher) do not require external modules to have the same version anymore, but instead determine compatability between different versions dynamically. See the accompanying Changes file for more details.
310             (Optional and acceptable when mode is "client")
311              
312             =item donotcompress
313              
314             Set to 1 to forcefully disable L even if the appropriate module(s) are found.
315             (Optional)
316              
317             =item donotcompresswith
318              
319             Set to a scalar or an arrayref of compression module(s) you'd like to avoid compressing with. For example, if you do not want to use Compress::LZF, you can do so by utilizing this option.
320             (Optional)
321              
322             =item donotencrypt
323              
324             Set to 1 to forcefully disable L even if the appropriate module(s) are found.
325             (Optional)
326              
327             =item donotencryptwith
328              
329             Set to a scalar or an arrayref of encryption module(s) you'd like to avoid encrypting with. For example, Crypt::RSA takes a long time to initialize keys and encrypt/decrypt, so you can avoid using it by utilizing this option.
330             (Optional)
331              
332             =item host
333              
334             Must be set to the hostname/IP address to connect to.
335             (Mandatory when mode is "client")
336              
337             =item mode
338              
339             Must be set to either "client" or "server" according to the type of object you want returned.
340             (Mandatory)
341              
342             =item password
343              
344             Defines a password to use for the connection. When mode is "server" this password will be required from clients before the full connection is accepted . When mode is "client" this is the password that the server connecting to requires.
345              
346             Also, when encryption using a symmetric encryption module is used, this password is included as part of the secret "key" for encrypting the data.
347             (Optional)
348              
349             =item port
350              
351             Must be set to the port the client connects to (if mode is "client") or to the port to listen to (if mode is "server"). If you're writing a client+server pair, they must both use the same port number.
352             (Mandatory)
353              
354             =item timeout
355              
356             Set to an integer (seconds) that a client attempting to establish a TCP/IP connection to a server will timeout after. If not supplied, the default is 30 seconds. (Optional and acceptable only when mode is "client")
357              
358             =item welcome
359              
360             If someone uses an interactive telnet program to telnet to the server, they will see this welcome message.
361             (Optional and acceptable only when mode is "server")
362              
363             =back
364              
365             =back
366              
367             =head1 METHODS
368              
369             B<[C] = Available to objects created as mode "client">
370              
371             B<[H] = Available to "hybrid" client objects, as in "the server-side client objects created when a new client connects". These are the objects passed to your server's callbacks. Such hybrid clients behave almost exactly like a normal "client" object you create yourself, except for a slight difference in the available methods to retrieve data.>
372              
373             B<[S] = Available to objects created as mode "server">
374              
375             =over 4
376              
377             =item addclientip(@array)
378              
379             B<[S]> Adds an IP address (or IP addresses) to the list of allowed clients to a server. If this is done, the server will not accept connections from clients not in it's list.
380              
381             The compliment of this function is deleteclientip() .
382              
383             =item callback(%hash)
384              
385             See setcallback()
386              
387             =item clients()
388              
389             B<[S]> Returns all the clients currently connected to the server. If called in array context will return an array of client objects. If called in scalar context will return the number of clients connected.
390              
391             =item close()
392              
393             B<[C][H]> Instructs a client object to close it's connection with a server.
394              
395             =item compression()
396              
397             B<[C][H]> Returns the name of the module used as the compression module for this connection, undef if no compression occurs.
398              
399             =item data()
400              
401             B<[H]> Retrieves the previously-retrieved data associated with a hybrid client object. This method is typically used from inside the callback sub associated with the "data" event, since the callback sub is passed nothing more than a client object.
402              
403             =item deleteclientip(@array)
404              
405             B<[S]> Deletes an IP address (or IP addresses) from the list of allowed clients to a server. The IP address (or IP addresses) supplied will no longer be able to connect to the server.
406              
407             The compliment of this function is addclientip() .
408              
409             =item disconnect()
410              
411             See close()
412              
413             =item do_one_loop()
414              
415             B<[S]> Instructs a server object to "do one loop" and return ASAP. This method needs to be called VERY frequently for a server object to function as expected (either through some sort of loop inside your program if you need to do other things beside serve clients, or via the start() method if your entire program is dedicated to serving clients). Each one loop will help the server do it's job, including accepting new clients, receiving data from them, firing off the appropriate callbacks etc.
416              
417             =item encryption()
418              
419             B<[C][H]> Returns the name of the module used as the encryption module for this connection, undef if no encryption occurs.
420              
421             =item mode()
422              
423             B<[C][H][S]> Identifies the mode of the object. Returns either "client" or "server"
424              
425             =item receive($timeout)
426              
427             B<[C]> Receives data sent to the client by a server and returns it. It will block until data is received or until a certain timeout of inactivity (no data transferring) has occurred.
428              
429             It accepts an optional parameter, a timeout value in seconds. If none is supplied it will default to 300.
430              
431             =item remoteip()
432              
433             B<[C][H]> Returns the IP address of the host on the other end of the connection.
434              
435             =item remoteport()
436              
437             B<[C][H]> Returns the port of the host on the other end of the connection.
438              
439             =item running()
440              
441             B<[S]> Returns true if the server is running (started), false if it is not.
442              
443             =item send($data)
444              
445             B<[C][H]> Sends data to a server. It can be used on client objects you create with the new() constructor, clients objects returned by the clients() method, or with client objects passed to your callback subs by a running server.
446              
447             It accepts one parameter, and that is the data to send. The data can be a simple scalar or a reference to something more complex.
448              
449             =item serial()
450              
451             B<[H]> Retrieves the serial number of a client object, This is a simple integer that allows your callback subs to easily differentiate between different clients.
452              
453             =item setcallback(%hash)
454              
455             B<[S]> Tells the server which subroutines to call when specific events happen. For example when a client sends the server data, the server calls the "data" callback sub.
456              
457             setcallback() expects to be passed a hash. Each key in the hash is the callback type identifier, and the value is a reference to a sub to call once that callback type event occurs.
458              
459             Valid keys in that hash are:
460              
461             =over 4
462              
463             =item connect
464              
465             Called when a new client connects to the server
466              
467             =item data
468              
469             Called when an existing client sends data to the server
470              
471             =item disconnect
472              
473             Called when an existing client disconnects
474              
475             =back
476              
477             Whenever a callback sub is called, it is passed a single parameter, a CLIENT OBJECT. The callback code may then use any of the methods available to client objects to do whatever it wants to do (Read data sent from the client, reply to the client, close the client connection etc...)
478              
479              
480             =item socket()
481              
482             B<[C][H]> Returns the handle of the socket (actually an L object) associated with the supplied object. This is useful if you're interested in using L or select() and want to add a client object's socket handle to the select list.
483              
484             Note that eventhough there's nothing stopping you from reading and writing directly to the socket handle you retrieve via this method, you should never do this since doing so would definately corrupt the internal protocol and may render your connection useless. Instead you should use the send() and receive() methods.
485              
486             =item start(subref)
487              
488             B<[S]> Starts a server and does NOT return until the server is stopped via the stop() method. This method is a simple while() wrapper around the do_one_loop() method and should be used if your entire program is dedicated to being a server, and does not need to do anything else concurrently.
489              
490             If you need to concurrently do other things when the server is running, then you can supply to start() the optional reference to a subroutine (very similar to the callback() method). If that is supplied, it will be called every loop. This is very similar to the callback subs, except that the called sub will be passed the server object that the start() method was called on (unlike normal client callbacks which are passed a client object). The other alternative to performing other tasks concurrently is to not use the start() method at all and directly call do_one_loop() repeatedly in your own program.
491              
492             =item stop()
493              
494             B<[S]> Instructs a running server to stop and returns immediately (does not wait for the server to actually stop, which may be a few seconds later). To check if the server is still running or not use the running() method.
495              
496             =back
497              
498             =head1 COMPRESSION AND ENCRYPTION
499              
500             Clients and servers written using this class will automatically compress and/or encrypt the transferred data if the appropriate modules are found.
501              
502             Compression will be automatically enabled if one (or more) of: L or L are installed on both the client and the server.
503              
504             As-symmetric encryption will be automatically enabled if L is installed on both the client and the server.
505              
506             Symmetric encryption will be automatically enabled if one (or more) of: L* or L* or L* or L* or L* or L* or L* or L* or L are installed on both the client and the server.
507              
508             Strong randomization will be automatically enabled if L is installed; otherwise perl's internal rand() is used to generate random keys.
509              
510             Preference to the compression/encryption method used is determind by availablity checking following the order in which they are presented in the above lists.
511              
512             Note that during the negotiation upon connection, servers and clients written using Net::EasyTCP version lower than 0.20 communicated the version of the selected encryption/compression modules. If a version mismatch is found, the client reported a connection failure stating the reason (module version mismatch). This behavior was necessary since it was observed that different versions of the same module could produce incompatible output. If this is encountered, it is strongly recommended you upgrade the module in question to the same version on both ends, or more preferrably, Net::EasyTCP on both ends to the latest version, at a minimum 0.20. However, if you wish to forcefully connect overlooking a version mismatch (risking instability/random problems/data corruption) you may supply the "donotcheckversion" key to the new() constructor of the client object. This is no longer a requirement of Net::EasyTCP version 0.20 or higher since these newer versions have the ability to use different-version modules as long as their data was compatible, which was automatically determined at negotiation time.
513              
514             To find out which module(s) have been negotiated for use you can use the compression() and encryption() methods.
515              
516             * Note that for this class's purposes, L is a requirement to use any of the encryption modules with a * next to it's name in the above list. So eventhough you may have these modules installed on both the client and the server, they will not be used unless L is also installed on both ends.
517              
518             * Note that the nature of symmetric cryptography dictates sharing the secret keys somehow. It is therefore highly recommend to use an As-symmetric cryptography module (such as Crypt::RSA) for serious encryption needs; as a determined hacker might find it trivial to decrypt your data with other symmetric modules.
519              
520             * Note that if symmetric cryptography is used, then it is highly recommended to also use the "password" feature on your servers and clients; since then the "password" will, aside from authentication, be also used in the "secret key" to encrypt the data. Without a password, the secret key has to be transmitted to the other side during the handshake, significantly lowering the overall security of the data.
521              
522             If the above modules are installed but you want to forcefully disable compression or encryption, supply the "donotcompress" and/or "donotencrypt" keys to the new() constructor. If you would like to forcefully disable the use of only some modules, supply the "donotcompresswith" and/or "donotencryptwith" keys to the new() constructor. This could be used for example to disable the use of Crypt::RSA if you cannot afford the time it takes to generate it's keypairs etc...
523              
524             =head1 RETURN VALUES AND ERRORS
525              
526             The constructor and all methods return something that evaluates to true when successful, and to false when not successful.
527              
528             There are a couple of exceptions to the above rule and they are the following methods:
529              
530             =over 4
531              
532             =item *
533              
534             clients()
535              
536             =item *
537              
538             data()
539              
540             =back
541              
542             The above methods may return something that evaluates to false (such as an empty string, an empty array, or the string "0") eventhough there was no error. In that case check if the returned value is defined or not, using the defined() Perl function.
543              
544             If not successful, the variable $@ will contain a description of the error that occurred.
545              
546             =head1 NOTES
547              
548             =over 4
549              
550             =item Incompatability with Net::EasyTCP version 0.01
551              
552             Version 0.02 and later have had their internal protocol modified to a fairly large degree. This has made compatability with version 0.01 impossible. If you're going to use version 0.02 or later (highly recommended), then you will need to make sure that none of the clients/servers are still using version 0.01. It is highly recommended to use the same version of this module on both sides.
553              
554             =item Internal Protocol
555              
556             This class implements a miniature protocol when it sends and receives data between it's clients and servers. This means that a server created using this class cannot properly communicate with a normal client of any protocol (pop3/smtp/etc..) unless that client was also written using this class. It also means that a client written with this class will not properly communicate with a different server (telnet/smtp/pop3 server for example, unless that server is implemented using this class also). This limitation will not change in future releases due to the plethora of advantages the internal protocol gives us.
557              
558             In other words, if you write a server using this class, write the client using this class also, and vice versa.
559              
560             =item Delays
561              
562             This class does not use the fork() method whatsoever. This means that all it's input/output and multi-socket handling is done via select().
563              
564             This leads to the following limitation: When a server calls one of your callback subs, it waits for it to return and therefore cannot do anything else. If your callback sub takes 5 minutes to return, then the server will not be able to do anything for 5 minutes, such as acknowledge new clients, or process input from other clients.
565              
566             In other words, make the code in your callbacks' subs' minimal and strive to make it return as fast as possible.
567              
568             =item Deadlocks
569              
570             As with any client-server scenario, make sure you engineer how they're going to talk to each other, and the order they're going to talk to each other in, quite carefully. If both ends of the connection are waiting for the other end to say something, you've got a deadlock.
571              
572             =back
573              
574             =head1 AUTHOR
575              
576             Mina Naguib
577             http://www.topfx.com
578             mnaguib@cpan.org
579              
580             =head1 SEE ALSO
581              
582             Perl(1), L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, defined(), rand()
583              
584             =head1 COPYRIGHT
585              
586             Copyright (C) 2001-2003 Mina Naguib. All rights reserved. Use is subject to the Perl license.
587              
588             =cut
589              
590             #
591             # The main constructor. This calls either _new_client or _new_server depending on the supplied mode
592             #
593             sub new {
594 3     3 1 2386 my $class = shift;
595 3         53 my %para = @_;
596              
597             # Let's lowercase all keys in %para
598 3         315 foreach (keys %para) {
599 10 50       51 if ($_ ne lc($_)) {
600 0         0 $para{ lc($_) } = $para{$_};
601 0         0 delete $para{$_};
602             }
603             }
604 3 100       95 if ($para{mode} =~ /^c/i) {
    50          
605 1         41 return _new_client($class, %para);
606             }
607             elsif ($para{mode} =~ /^s/i) {
608 2         10 return _new_server($class, %para);
609             }
610             else {
611 0         0 $@ = "Supplied mode '$para{mode}' unacceptable. Must be either 'client' or 'server'";
612 0         0 return undef;
613             }
614             }
615              
616             #
617             # Make callback() a synonim to setcallback()
618             #
619              
620             sub callback {
621 0     0 1 0 return setcallback(@_);
622             }
623              
624             #
625             # This method adds an ip address(es) to the list of valid IPs a server can accept connections
626             # from.
627             #
628             sub addclientip {
629 0     0 1 0 my $self = shift;
630 0         0 my @ips = @_;
631 0 0       0 if ($self->{_mode} ne "server") {
632 0         0 $@ = "$self->{_mode} cannot use method addclientip()";
633 0         0 return undef;
634             }
635 0         0 foreach (@ips) {
636 0         0 $self->{_clientip}{$_} = 1;
637             }
638 0         0 return 1;
639             }
640              
641             #
642             # This method does the opposite of addclient(), it removes an ip address(es) from the list
643             # of valid IPs a server can accept connections from.
644             #
645             sub deleteclientip {
646 0     0 1 0 my $self = shift;
647 0         0 my @ips = @_;
648 0 0       0 if ($self->{_mode} ne "server") {
649 0         0 $@ = "$self->{_mode} cannot use method deleteclientip()";
650 0         0 return undef;
651             }
652 0         0 foreach (@ips) {
653 0         0 delete $self->{_clientip}{$_};
654             }
655 0         0 return 1;
656             }
657              
658             #
659             #
660             # This method modifies the _callback_XYZ in a server object. These are the routines
661             # the server calls when an event (data, connect, disconnect) happens
662             #
663             sub setcallback {
664 2     2 1 88 my $self = shift;
665 2         8 my %para = @_;
666 2 50       10 if ($self->{_mode} ne "server") {
667 0         0 $@ = "$self->{_mode} cannot use method setcallback()";
668 0         0 return undef;
669             }
670 2         6 foreach (keys %para) {
671 6 50       18 if (ref($para{$_}) ne "CODE") {
672 0         0 $@ = "Callback $_ $para{$_} does not exist";
673 0         0 return 0;
674             }
675 6         16 $self->{_callbacks}->{$_} = $para{$_};
676             }
677 2         6 return 1;
678             }
679              
680             #
681             # This method starts the server and does not return until stop() is called.
682             # All other behavior is delegated to do_one_loop()
683             #
684             sub start {
685 1     1 1 1484 my $self = shift;
686 1         26 my $callback = shift;
687 1 50       48 if ($self->{_mode} ne "server") {
688 0         0 $@ = "$self->{_mode} cannot use method start()";
689 0         0 return undef;
690             }
691 1         28 $self->{_running} = 1;
692 1         16 $self->{_requeststop} = 0;
693              
694             #
695             # Let's loop until we're stopped:
696             #
697 1         19 while (!$self->{_requeststop}) {
698 13 50       59 $self->do_one_loop() || return undef;
699 12 50 33     54 if ($callback && ref($callback) eq "CODE") {
700 0         0 &{$callback}($self);
  0         0  
701             }
702             }
703              
704             #
705             # If we reach here the server's been stopped
706             #
707 0         0 $self->{_running} = 0;
708 0         0 $self->{_requeststop} = 0;
709 0         0 return 1;
710             }
711              
712             #
713             # This method does "one loop" of server work and returns ASAP
714             # It should be called very frequently, either through a while() loop in the program
715             # or through the start() method
716             #
717             # It accepts new clients, accepts data from them, and fires off any callback events as necessary
718             #
719             sub do_one_loop {
720 13     13 1 17 my $self = shift;
721 13         17 my @ready;
722             my $clientsock;
723 0         0 my $tempdata;
724 0         0 my $serverclient;
725 0         0 my $realdata;
726 0         0 my $result;
727 13         23 my $negotiatingtimeout = 45;
728 13         50 my $peername;
729             my $remoteport;
730 0         0 my $remoteip;
731              
732 13 50       45 if ($self->{_mode} ne "server") {
733 0         0 $@ = "$self->{_mode} cannot use method do_one_loop()";
734 0         0 return undef;
735             }
736 13   66     76 $self->{_lastglobalkeygentime} ||= time;
737 13         98 @ready = $self->{_selector}->can_read(0.01);
738 13         26229 foreach (@ready) {
739 13 100       157 if ($_ == $self->{_sock}) {
740              
741             #
742             # The SERVER SOCKET is ready for accepting a new client
743             #
744 1         88 $clientsock = $self->{_sock}->accept();
745 1 50       637 if (!$clientsock) {
746 0         0 $@ = "Error while accepting new connection: $!";
747 0         0 return undef;
748             }
749              
750             #
751             # We get remote IP and port, we'll need them to see if client is allowed or not
752             #
753 1 50       17 $peername = getpeername($clientsock) or next;
754 1 50       18 ($remoteport, $remoteip) = sockaddr_in($peername) or next;
755 1 50       42 $remoteip = inet_ntoa($remoteip) or next;
756              
757             #
758             # We create a new client object and
759             # We see if client is allowed to connect to us
760             #
761 1 50 33     6 if (scalar(keys %{ $self->{_clientip} }) && !$self->{_clientip}{$remoteip}) {
  1         9  
762              
763             #
764             # Client's IP is not allowed to connect to us
765             #
766 0         0 close($clientsock);
767             }
768             else {
769              
770             #
771             # We add it to our SELECTOR pool :
772             #
773 1         22 $self->{_selector}->add($clientsock);
774              
775             #
776             # We create a new client object:
777             #
778 1         105 $self->{_clients}->{$clientsock} = _new_client(
779             $self,
780             "_sock" => $clientsock,
781             "_remoteport" => $remoteport,
782             "_remoteip" => $remoteip
783             );
784              
785             #
786             # We initialize some client variables:
787             #
788 1         9 $self->{_clients}->{$clientsock}->{_serial} = ++$_SERIAL;
789 1         11 $self->{_clients}->{$clientsock}->{_compatabilityscalar} = _genrandstring(129);
790 1         30 $self->{_clients}->{$clientsock}->{_compatabilityreference} = _gencompatabilityreference($self->{_clients}->{$clientsock}->{_compatabilityscalar});
791              
792             #
793             # And we make it inherit some stuff from the server :
794             #
795 1         5 $self->{_clients}->{$clientsock}->{_donotencrypt} = $self->{_donotencrypt};
796 1         5 $self->{_clients}->{$clientsock}->{_donotencryptwith} = $self->{_donotencryptwith};
797 1         4 $self->{_clients}->{$clientsock}->{_donotcompress} = $self->{_donotcompress};
798 1         4 $self->{_clients}->{$clientsock}->{_donotcompresswith} = $self->{_donotcompresswith};
799 1         7 $self->{_clients}->{$clientsock}->{_password} = $self->{_password};
800 1         8 $self->{_clients}->{$clientsock}->{_callbacks} = $self->{_callbacks};
801 1         4 $self->{_clients}->{$clientsock}->{_welcome} = $self->{_welcome};
802 1         7 $self->{_clients}->{$clientsock}->{_selector} = $self->{_selector};
803             }
804             }
805             else {
806              
807             #
808             # One of the CLIENT sockets are ready
809             #
810 12         133 $result = sysread($_, $tempdata, $PACKETSIZE);
811 12         44 $serverclient = $self->{_clients}->{$_};
812 12 50       65 if (!defined $result) {
    100          
813              
814             #
815             # Error somewhere during reading from that client
816             #
817 0         0 _callback($serverclient, "disconnect");
818 0         0 $serverclient->close();
819 0         0 delete $self->{_clients}->{$_};
820             }
821             elsif ($result == 0) {
822              
823             #
824             # Client closed connection
825             #
826 1         4 _callback($serverclient, "disconnect");
827 0         0 $serverclient->close();
828 0         0 delete $self->{_clients}->{$_};
829             }
830             else {
831              
832             #
833             # Client sent us some good data (not necessarily a full packet)
834             #
835 11         32 $serverclient->{_databuffer} .= $tempdata;
836              
837             #
838             # Extract as many data buckets as possible out of the buffer
839             #
840 11         36 _extractdata($serverclient);
841              
842             #
843             # Process all this client's data buckets
844             #
845 11         11 foreach (@{ $serverclient->{_databucket} }) {
  11         25  
846 11 100       35 if ($_->{realdata}) {
847              
848             #
849             # This bucket is normal data
850             #
851 1         5 _callback($serverclient, "data");
852             }
853             else {
854              
855             #
856             # This bucket is internal data
857             #
858 10         26 _parseinternaldata($serverclient);
859             }
860             }
861             }
862             }
863             }
864              
865             #
866             # Now we check on all the serverclients still negotiating and help them finish negotiating
867             # or weed out the ones timing out
868             #
869 12         114 foreach (keys %{ $self->{_clients} }) {
  12         46  
870 12         24 $serverclient = $self->{_clients}->{$_};
871 12 100       39 if ($serverclient->{_negotiating}) {
872 10 50       30 if (_serverclient_negotiate($serverclient)) {
    50          
873 0         0 _callback($serverclient, "connect");
874             }
875             elsif ((time - $serverclient->{_negotiating}) > $negotiatingtimeout) {
876 0         0 $serverclient->close();
877 0         0 delete $self->{_clients}->{$_};
878             }
879             }
880             }
881              
882             #
883             # Now we re-generate the RSA keys if it's been over an hour
884             #
885 12 50 33     269 if (!$self->{_donotencrypt} && !$self->{_donotencryptwith}{"B"} && ((time - $self->{_lastglobalkeygentime}) >= 3600)) {
      33        
886 0 0       0 if (!_generateglobalkeypair('Crypt::RSA')) {
887 0         0 $@ = "Could not generate global Crypt::RSA keypairs. $@";
888 0         0 return undef;
889             }
890 0         0 $self->{_lastglobalkeygentime} = time;
891             }
892 12         44 return 1;
893             }
894              
895             #
896             # This method stops the server and makes it return.
897             # Note: It doesn't stop the server immediately, it sets a flag
898             # and the flag should in a few seconds cause the infinite loop in start() method to stop
899             #
900             sub stop {
901 0     0 1 0 my $self = shift;
902 0 0       0 if ($self->{_mode} ne "server") {
903 0         0 $@ = "$self->{_mode} cannot call method stop()";
904 0         0 return undef;
905             }
906 0         0 $self->{_requeststop} = 1;
907 0         0 return 1;
908             }
909              
910             #
911             # This method sends data to the socket associated with the object
912             #
913             sub send {
914 2     2 1 200 my $self = shift;
915 2         6 my $data = shift;
916 2 50 66     28 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
917 0         0 $@ = "$self->{_mode} cannot use method send()";
918 0         0 return undef;
919             }
920 2         14 return _send($self, $data);
921             }
922              
923             #
924             # This method returns the serial number associated with the object
925             #
926             sub serial {
927 0     0 1 0 my $self = shift;
928 0 0       0 if (!$self->{_serial}) {
929 0         0 $self->{_serial} = ++$_SERIAL;
930             }
931 0         0 return $self->{_serial};
932             }
933              
934             #
935             # Takes nothing, returns the oldest entry from the data bucket for a client/serverclient
936             # In array context returns data and realdata flag, otherwise just data
937             # (typically the code in the callback assigned to callback_data would access this method)
938             #
939             sub data {
940 34     34 1 51 my $self = shift;
941 34         37 my $data;
942 34 50 66     160 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
943 0         0 $@ = "$self->{_mode} cannot use method data()";
944 0         0 return undef;
945             }
946              
947 34         40 $data = shift(@{ $self->{_databucket} });
  34         145  
948              
949 34 100       223 return wantarray ? ($data->{data}, $data->{realdata}) : $data->{data};
950             }
951              
952             #
953             # This method reads data from the socket associated with the object and returns it
954             # Accepts an optional timeout as a first parameter, otherwise defaults to timeout
955             # Returns the data if successful, undef if not
956             #
957             sub receive {
958 12     12 1 32 my $self = shift;
959 12   100     230 my $timeout = shift || 0;
960 12   100     34 my $returninternaldata = shift || 0;
961 12         16 my $temp;
962             my $realdata;
963 0         0 my $result;
964 12         14 my $lastactivity = time;
965 12         13 my $selector;
966             my @ready;
967 0         0 my $fatalerror;
968              
969 12 50 33     42 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
970 0         0 $@ = "$self->{_mode} cannot use method receive()";
971 0         0 return undef;
972             }
973              
974 12         64 $selector = new IO::Select;
975 12         190 $selector->add($self->{_sock});
976              
977             #
978             # Let's try to read from the socket
979             #
980 12 100       473 while ($timeout ? ((time - $lastactivity) < $timeout) : 1) {
981 12         188 @ready = $selector->can_read($timeout);
982 12 100       25969 if (!@ready) {
983              
984             #
985             # Socket is not ready for reading
986             #
987 1 50       7 if (!$!) {
    0          
988              
989             #
990             # Because of timeout
991             #
992 1 50       3 if (!$timeout) {
993              
994             #
995             # We're doing an initial reading without blocking
996             #
997 1         2 last;
998             }
999             else {
1000              
1001             #
1002             # We're blocking - let the while look take care of timeout
1003             #
1004 0         0 next;
1005             }
1006             }
1007             elsif ($! =~ /interrupt/i) {
1008              
1009             #
1010             # Because of select() interrupted - ignore that
1011             #
1012 0         0 next;
1013             }
1014             else {
1015              
1016             #
1017             # Because of some unknown error
1018             #
1019 0         0 last;
1020             }
1021             }
1022             else {
1023              
1024             #
1025             # Socket is ready for reading
1026             #
1027 11         216 $result = sysread($self->{_sock}, $temp, $PACKETSIZE);
1028 11 50       43 if (!defined $result) {
    50          
1029              
1030             #
1031             # Error reading from socket
1032             #
1033 0         0 $fatalerror = "Failed to read from socket: $!";
1034 0 0       0 if (!$timeout) {
1035              
1036             #
1037             # However we won't crap out right away, as we're doing a cursory, no-timeout read
1038             #
1039 0         0 last;
1040             }
1041             else {
1042 0         0 $@ = $fatalerror;
1043 0         0 return undef;
1044             }
1045             }
1046             elsif ($result == 0) {
1047              
1048             #
1049             # Socket closed while reading
1050             #
1051 0         0 $fatalerror = "Socket closed when attempted reading";
1052 0 0       0 if (!$timeout) {
1053              
1054             # However we won't crap out right away, as we're doing a cursory, no-timeout read
1055 0         0 last;
1056             }
1057             else {
1058 0         0 $@ = $fatalerror;
1059 0         0 return undef;
1060             }
1061             }
1062             else {
1063              
1064             #
1065             # Read good data - add it to the databuffer
1066             #
1067 11         35 $self->{_databuffer} .= $temp;
1068 11         21 $lastactivity = time;
1069              
1070 11 50 33     149 if ($timeout && $result != $PACKETSIZE && _extractdata($self)) {
      33        
1071              
1072             #
1073             # We're doing blocking reads, we extracted something into the bucket, and there's probably nothing else at the end of the socket
1074             # No point looping to block again
1075             #
1076 11         18 last;
1077             }
1078             }
1079             }
1080             }
1081              
1082             #
1083             # Now there's nothing waiting to be received
1084             # Try to extract all possible data buckets out of the data buffer
1085             #
1086 12         27 _extractdata($self);
1087              
1088             #
1089             # Now the databuffer has no full packets. If there's any data to be returned it's in the data buckets
1090             #
1091 12   66     36 while ((($result, $realdata) = $self->data()) && defined $result) {
1092              
1093             #
1094             # We got something from the bucket
1095             #
1096 11 100       24 if ($realdata) {
1097              
1098             #
1099             # And it's real data - return it
1100             #
1101 1         35 return $result;
1102             }
1103             else {
1104              
1105             #
1106             # It's internal data
1107             #
1108 10 50       18 if ($returninternaldata) {
1109              
1110             #
1111             # But we've been asked to return it
1112             #
1113 10         52 return $result;
1114             }
1115             else {
1116              
1117             #
1118             # Don't know what to do with the internal data
1119             #
1120 0         0 _parseinternaldata($self, $result);
1121             }
1122             }
1123             }
1124 1 50       4 if (defined($result = $self->data())) {
1125              
1126             #
1127             # We have good data to return
1128             #
1129 0         0 return $result;
1130             }
1131              
1132             #
1133             # If we've reached here we have no data to return
1134             #
1135 1 50       10 if (!$timeout) {
1136              
1137             #
1138             # We were doing a quick no-block read
1139             #
1140 1 50       3 if ($fatalerror) {
1141              
1142             #
1143             # And we have a fatal error - don't attempt a blocking read
1144             #
1145 0         0 $@ = $fatalerror;
1146 0         0 return undef;
1147             }
1148             else {
1149              
1150             #
1151             # Attempt a blocking read
1152             #
1153 1         13 return $self->receive(300);
1154             }
1155             }
1156             else {
1157              
1158             #
1159             # We did a blocking read
1160             #
1161 0         0 $@ = "Timed out waiting to receive data";
1162 0         0 return undef;
1163             }
1164             }
1165              
1166             #
1167             # This method is a synonym for close()
1168             #
1169             sub disconnect {
1170 0     0 1 0 return close(@_);
1171             }
1172              
1173             #
1174             # This method closes the socket associated with the object
1175             #
1176             sub close {
1177 1     1 1 17 my $self = shift;
1178 1 50 33     8 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
1179 0         0 $@ = "$self->{_mode} cannot use method close()";
1180 0         0 return undef;
1181             }
1182 1 50 33     7 if ($self->{_selector} && $self->{_selector}->exists($self->{_sock})) {
1183              
1184             # If the server selector reads this, let's make it not...
1185 0         0 $self->{_selector}->remove($self->{_sock});
1186             }
1187 1 50       31 $self->{_sock}->close() if defined $self->{_sock};
1188 1         71 $self->{_sock} = undef;
1189 1         6 $self->{_databucket} = [];
1190 1         4 $self->{_databuffer} = undef;
1191 1         3 return 1;
1192             }
1193              
1194             #
1195             # This method returns true or false, depending on if the server is running or not
1196             #
1197             sub running {
1198 0     0 1 0 my $self = shift;
1199 0 0       0 if ($self->{_mode} ne "server") {
1200 0         0 $@ = "$self->{_mode} cannot use method running()";
1201 0         0 return undef;
1202             }
1203 0         0 return $self->{_running};
1204             }
1205              
1206             #
1207             # This replies saying what type of object it's passed
1208             #
1209             sub mode {
1210 0     0 1 0 my $self = shift;
1211 0 0       0 my $mode = ($self->{_mode} eq "server") ? "server" : "client";
1212 0         0 return $mode;
1213             }
1214              
1215             #
1216             # This method replies saying what type of encryption is used, undef if none
1217             #
1218             sub encryption {
1219 0     0 1 0 my $self = shift;
1220 0         0 my $modulekey = $self->{_encrypt};
1221 0 0 0     0 if ($self->{_donotencrypt} || !$modulekey) {
1222 0         0 return undef;
1223             }
1224 0   0     0 return $_ENCRYPT_AVAILABLE{$modulekey}{name} || "Unknown module name for modulekey [$modulekey]";
1225             }
1226              
1227             #
1228             # This method replies saying what type of compression is used, undef if none
1229             #
1230             sub compression {
1231 0     0 1 0 my $self = shift;
1232 0         0 my $modulekey = $self->{_compress};
1233 0 0 0     0 if ($self->{_donotcompress} || !$modulekey) {
1234 0         0 return undef;
1235             }
1236 0   0     0 return $_COMPRESS_AVAILABLE{$modulekey}{name} || "Unknown module name for modulekey [$modulekey]";
1237             }
1238              
1239             #
1240             # This returns the IO::Socket object associated with a connection
1241             #
1242             sub socket {
1243 0     0 1 0 my $self = shift;
1244 0 0 0     0 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
1245 0         0 $@ = "$self->{_mode} cannot use method socket()";
1246 0         0 return undef;
1247             }
1248 0   0     0 return ($self->{_sock} || undef);
1249             }
1250              
1251             #
1252             # This returns an array of all the clients connected to a server in array context
1253             # or the number of clients in scalar context
1254             # or undef if there are no clients or error
1255             #
1256             sub clients {
1257 0     0 1 0 my $self = shift;
1258 0         0 my @clients;
1259 0 0       0 if ($self->{_mode} ne "server") {
1260 0         0 $@ = "$self->{_mode} cannot use method clients()";
1261 0         0 return undef;
1262             }
1263 0         0 foreach (values %{ $self->{_clients} }) {
  0         0  
1264 0 0       0 if (!$_->{_negotiating}) {
1265 0         0 push(@clients, $_);
1266             }
1267             }
1268 0 0       0 if (@clients) {
1269 0 0       0 return wantarray ? @clients : scalar @clients;
1270             }
1271             else {
1272 0         0 return undef;
1273             }
1274             }
1275              
1276             #
1277             # This takes a client object and returns the IP address of the remote connection
1278             #
1279             sub remoteip {
1280 0     0 1 0 my $self = shift;
1281 0         0 my $temp;
1282 0 0 0     0 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
1283 0         0 $@ = "$self->{_mode} cannot use method remoteip()";
1284 0         0 return undef;
1285             }
1286 0         0 return $self->{_remoteip};
1287             }
1288              
1289             #
1290             # This takes a client object and returns the PORT of the remote connection
1291             #
1292             sub remoteport {
1293 0     0 1 0 my $self = shift;
1294 0         0 my $temp;
1295 0 0 0     0 if ($self->{_mode} ne "client" && $self->{_mode} ne "serverclient") {
1296 0         0 $@ = "$self->{_mode} cannot use method remoteport()";
1297 0         0 return undef;
1298             }
1299 0         0 return $self->{_remoteport};
1300             }
1301              
1302             ###########################################################
1303             ###########################################################
1304             ###########################################################
1305             #
1306             # The following are private functions (not object methods)
1307             #
1308              
1309             #
1310             # This takes 2 items (references to simple structures, or simple scalars)
1311             # And returns true if they're the same, false if they're not
1312             # It does NOT work for blessed objects. only scalars, hashrefs and arrayrefs
1313             #
1314             sub _comparereferences {
1315 18     18   33 my $item1 = shift;
1316 18         22 my $item2 = shift;
1317 18         33 my $ref1 = ref($item1);
1318 18         26 my $ref2 = ref($item2);
1319 18         18 my $num1;
1320             my $num2;
1321 0         0 my @keys1;
1322 0         0 my @keys2;
1323 0         0 my $temp;
1324              
1325 18 50 66     136 if ($ref1 ne $ref2) {
    50          
    100          
    100          
    50          
1326 0         0 $@ = "References not same type [$ref1] [$ref2]";
1327 0         0 return 0;
1328             }
1329             elsif (!$ref1 && $item1 ne $item2) {
1330              
1331             #Scalars - do not match
1332 0         0 $@ = "Values of two scalar values not same";
1333 0         0 return 0;
1334             }
1335             elsif ($ref1 eq "ARRAY") {
1336 4         6 $num1 = scalar @{$item1};
  4         8  
1337 4         6 $num2 = scalar @{$item2};
  4         9  
1338 4 50       16 if ($num1 != $num2) {
1339              
1340             # Not same # of elements
1341 0         0 $@ = "Number of array elements not equal";
1342 0         0 return 0;
1343             }
1344             else {
1345 4         23 for $temp (0 .. $num1 - 1) {
1346 12 50       146 if (!_comparereferences($item1->[$temp], $item2->[$temp])) {
1347 0         0 return 0;
1348             }
1349             }
1350             }
1351             }
1352             elsif ($ref1 eq "HASH") {
1353 4         7 @keys1 = sort keys %{$item1};
  4         27  
1354 4         7 @keys2 = sort keys %{$item2};
  4         13  
1355 4 50       12 if (scalar @keys1 != scalar @keys2) {
1356              
1357             # Not same # of elements
1358 0         0 $@ = "Number of hash keys not equal";
1359 0         0 return 0;
1360             }
1361             else {
1362 4         22 for $temp (0 .. $#keys1) {
1363 4 50       14 if ($keys1[$temp] ne $keys2[$temp]) {
1364 0         0 $@ = "Hash key names not equal";
1365 0         0 return 0;
1366             }
1367 4 50       28 if (!_comparereferences($item1->{ $keys1[$temp] }, $item2->{ $keys2[$temp] })) {
1368 0         0 return 0;
1369             }
1370             }
1371             }
1372             }
1373             elsif ($ref1) {
1374              
1375             # Unknown reference
1376 0         0 $@ = "Unknown reference type [$ref1] [$ref2] [$item1] [$item2]";
1377 0         0 return 0;
1378             }
1379              
1380             #
1381             # Everything's good
1382             #
1383 18         1027 return 1;
1384             }
1385              
1386             #
1387             # This generates a global keypair and stores it globally
1388             # Takes the name of a module, returns true or false
1389             #
1390             sub _generateglobalkeypair {
1391 2   50 2   10 my $module = shift || return undef;
1392 2         6 foreach (keys %_ENCRYPT_AVAILABLE) {
1393 2 50 33     10 if ($_ ne "_order" && $_ENCRYPT_AVAILABLE{$_}{name} eq $module) {
1394 0         0 ($_ENCRYPT_AVAILABLE{$_}{localpublickey}, $_ENCRYPT_AVAILABLE{$_}{localprivatekey}) = ();
1395 0 0       0 ($_ENCRYPT_AVAILABLE{$_}{localpublickey}, $_ENCRYPT_AVAILABLE{$_}{localprivatekey}) = _genkey($_) or return undef;
1396 0         0 last;
1397             }
1398             }
1399 2         24 return 1;
1400             }
1401              
1402             #
1403             # This takes any string and returns it in ascii format
1404             #
1405             sub _bin2asc {
1406 4     4   297 my $data = shift;
1407 4         34 $data =~ s/(.)/ '%' . sprintf('%02x',ord($1)) /ges;
  2158         5945  
1408 4         44 $data = uc($data);
1409 4         37 return $data;
1410             }
1411              
1412             #
1413             # This does the opposite of _bin2asc
1414             #
1415             sub _asc2bin {
1416 5     5   12 my $data = shift;
1417 5         60 $data =~ s/\%([0-9A-F]{2})/ sprintf("%c",hex($1)) /ges;
  2287         8521  
1418 5         65 return $data;
1419             }
1420              
1421             #
1422             # This does very very primitive 2-way encryption & decryption (kinda like ROT13.. works both ways)
1423             # Takes a client and a string, returns the enc/dec/rypted string
1424             #
1425             # This encryption is used to protect the encrypted password and the public key transmitted over the wire
1426             # It's a last resort of security in case none of the encryption modules were found
1427             #
1428             sub _munge {
1429 6   50 6   28 my $client = shift || return undef;
1430 6         12 my $data = shift;
1431 6         10 my ($c, $t);
1432              
1433             #
1434             # Munge's tricky because is existed on and off in different versions
1435             #
1436 6 100 33     94 if (defined $data && ($client->{_version} == 0.07 || $client->{_version} == 0.08 || $client->{_version} >= 0.15)) {
      66        
1437              
1438             #
1439             # Peer supports munge
1440             #
1441 4         12 for (0 .. length($data) - 1) {
1442 26         37 $c = substr($data, $_, 1);
1443 26         106 $t = vec($c, 0, 4);
1444 26         122 vec($c, 0, 4) = vec($c, 1, 4);
1445 26         42 vec($c, 1, 4) = $t;
1446 26         39 substr($data, $_, 1) = $c;
1447             }
1448 4         14 $data = reverse($data);
1449             }
1450             else {
1451              
1452             # Our peer doesn't munge, so we won't either
1453             }
1454 6         886 return $data;
1455             }
1456              
1457             #
1458             # This takes a client object and a callback keyword and calls back the associated sub if possible
1459             #
1460             sub _callback {
1461 3     3   8 my $client = shift;
1462 3         22 my $type = shift;
1463 3 50 33     38 if (!$client->{_negotiating} && $client->{_callbacks}->{$type}) {
1464 3         4 &{ $client->{_callbacks}->{$type} }($client);
  3         21  
1465             }
1466             }
1467              
1468             #
1469             # This sub takes a scalar key
1470             # Returns a reference to a compatability compex object made up of repeating
1471             # the scalar in different combinations
1472             #
1473             sub _gencompatabilityreference {
1474 2     2   7 my $key = shift;
1475             return [
1476 2         47 $key,
1477             {
1478             $key => $key,
1479             $key => $key,
1480             },
1481             [ $key, { $key => $key, }, $key, ],
1482             ];
1483             }
1484              
1485             #
1486             # This takes in an encryption key id and an optional "forcompat" boolean flag
1487             # Generates a keypair (public, private) and returns them according to the type of encryption specified
1488             # Returns undef on error
1489             # The 2 returned keys are guaranteed to be: 1. Scalars and 2. Null-character-free. weather by their nature, or serialization or asci-fi-cation
1490             # If "forcompat" is not specified and there are already a keypair for the specified module stored globally,
1491             # it will return that instead of generating new ones.
1492             # If "forcompat" is supplied, you're guaranteed to receive a new key that wasn't given out in the past to
1493             # non-compat requests. It may be a repeat of a previous "forcompat" pair. However, the strength of that key
1494             # could be possibly reduced. Such keys are safe to reveal the private portion of publicly, as during the
1495             # compatability negotiation phase, however such keys must NEVER be used to encrypt any real data, as they
1496             # are no longer secret.
1497             #
1498             sub _genkey {
1499 0     0   0 my $modulekey = shift;
1500 0         0 my $forcompat = shift;
1501 0         0 my $module = $_ENCRYPT_AVAILABLE{$modulekey}{name};
1502 0         0 my $key1 = undef;
1503 0         0 my $key2 = undef;
1504 0         0 my $temp;
1505 0         0 $@ = undef;
1506 0 0 0     0 if (!$forcompat && $_ENCRYPT_AVAILABLE{$modulekey}{localpublickey} && $_ENCRYPT_AVAILABLE{$modulekey}{localprivatekey}) {
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1507 0         0 $key1 = $_ENCRYPT_AVAILABLE{$modulekey}{localpublickey};
1508 0         0 $key2 = $_ENCRYPT_AVAILABLE{$modulekey}{localprivatekey};
1509             }
1510             elsif ($forcompat && $_ENCRYPT_AVAILABLE{$modulekey}{localcompatpublickey} && $_ENCRYPT_AVAILABLE{$modulekey}{localcompatprivatekey}) {
1511 0         0 $key1 = $_ENCRYPT_AVAILABLE{$modulekey}{localcompatpublickey};
1512 0         0 $key2 = $_ENCRYPT_AVAILABLE{$modulekey}{localcompatprivatekey};
1513             }
1514             elsif ($module eq 'Crypt::RSA') {
1515 0         0 eval {
1516 0   0     0 $temp = Crypt::RSA->new() || die "Failed to create new Crypt::RSA object for key generation: $! $@\n";
1517 0 0       0 ($key1, $key2) = $temp->keygen(
1518             Size => 512,
1519             Verbosity => 0,
1520             )
1521             or die "Failed to create RSA keypair: " . $temp->errstr() . "\n";
1522             };
1523 0 0 0     0 if ($key1 && $key2) {
1524 0         0 $key1 = _bin2asc(nfreeze($key1));
1525              
1526             # RSA private keys are NOT serializable with the Serialize module - we MUST use Crypt::RSA::Key::Private's undocumented serialize() method:
1527 0         0 $key2 = $key2->serialize();
1528 0 0       0 if ($forcompat) {
1529 0         0 $_ENCRYPT_AVAILABLE{$modulekey}{localcompatpublickey} = $key1;
1530 0         0 $_ENCRYPT_AVAILABLE{$modulekey}{localcompatprivatekey} = $key2;
1531             }
1532             }
1533             }
1534             elsif ($module eq 'Crypt::Rijndael') {
1535 0         0 $key1 = _genrandstring(32);
1536 0         0 $key2 = $key1;
1537             }
1538             elsif ($module eq 'Crypt::RC6') {
1539 0         0 $key1 = _genrandstring(32);
1540 0         0 $key2 = $key1;
1541             }
1542             elsif ($module eq 'Crypt::Blowfish') {
1543 0         0 $key1 = _genrandstring(56);
1544 0         0 $key2 = $key1;
1545             }
1546             elsif ($module eq 'Crypt::DES_EDE3') {
1547 0         0 $key1 = _genrandstring(24);
1548 0         0 $key2 = $key1;
1549             }
1550             elsif ($module eq 'Crypt::DES') {
1551 0         0 $key1 = _genrandstring(8);
1552 0         0 $key2 = $key1;
1553             }
1554             elsif ($module eq 'Crypt::Twofish2') {
1555 0         0 $key1 = _genrandstring(32);
1556 0         0 $key2 = $key1;
1557             }
1558             elsif ($module eq 'Crypt::Twofish') {
1559 0         0 $key1 = _genrandstring(32);
1560 0         0 $key2 = $key1;
1561             }
1562             elsif ($module eq 'Crypt::TEA') {
1563 0         0 $key1 = _genrandstring(16);
1564 0         0 $key2 = $key1;
1565             }
1566             elsif ($module eq 'Crypt::CipherSaber') {
1567 0         0 $key1 = _genrandstring(32);
1568 0         0 $key2 = $key1;
1569             }
1570             else {
1571 0         0 $@ = "Unknown encryption module [$module] modulekey [$modulekey]";
1572             }
1573              
1574 0 0 0     0 if (!$key1 || !$key2) {
1575 0         0 $@ = "Could not generate encryption keys. $@";
1576 0         0 return undef;
1577             }
1578             else {
1579 0         0 return ($key1, $key2);
1580             }
1581              
1582             }
1583              
1584             #
1585             # This takes client object, and a reference to a scalar
1586             # And if it can, compresses scalar, modifying the original, via the specified module in the client object
1587             # Returns true if successful, false if not
1588             #
1589             sub _compress {
1590 23     23   37 my $client = shift;
1591 23         24 my $rdata = shift;
1592 23   100     87 my $modulekey = $client->{_compress} || return undef;
1593 7         27 my $module = $_COMPRESS_AVAILABLE{$modulekey}{name};
1594 7         11 my $newdata;
1595              
1596             #
1597             # Compress the data
1598             #
1599 7 50       21 if ($module eq 'Compress::Zlib') {
    0          
1600 7         57 $newdata = Compress::Zlib::compress($$rdata);
1601             }
1602             elsif ($module eq 'Compress::LZF') {
1603 0         0 $newdata = Compress::LZF::compress($$rdata);
1604             }
1605             else {
1606 0         0 $@ = "Unknown compression module [$module] modulekey [$modulekey]";
1607             }
1608              
1609             #
1610             # Finally, override reference if compression succeeded
1611             #
1612 7 50       3293 if ($newdata) {
1613 7         13 $$rdata = $newdata;
1614 7         25 return 1;
1615             }
1616             else {
1617 0         0 return undef;
1618             }
1619              
1620             }
1621              
1622             #
1623             # This does the opposite of _compress()
1624             #
1625             sub _decompress {
1626 7     7   13 my $client = shift;
1627 7         11 my $rdata = shift;
1628 7         13 my $modulekey = $client->{_compress};
1629 7         26 my $module = $_COMPRESS_AVAILABLE{$modulekey}{name};
1630 7         10 my $newdata;
1631              
1632 7 100       23 if ($module eq 'Compress::Zlib') {
    50          
1633 6         52 $newdata = Compress::Zlib::uncompress($$rdata);
1634             }
1635             elsif ($module eq 'Compress::LZF') {
1636 0         0 $newdata = Compress::LZF::decompress($$rdata);
1637             }
1638             else {
1639 1         5 $@ = "Unknown decompression module [$module] modulekey [$modulekey]";
1640             }
1641              
1642             #
1643             # Finally, override reference if decompression succeeded
1644             #
1645 7 100       1394 if ($newdata) {
1646 6         14 $$rdata = $newdata;
1647 6         24 return 1;
1648             }
1649             else {
1650 1         10 return undef;
1651             }
1652              
1653             }
1654              
1655             #
1656             # This takes client object, and a reference to a scalar
1657             # And if it can, encrypts scalar, modifying the original, via the specified module in the client object
1658             # Returns true if successful, false if not
1659             #
1660             sub _encrypt {
1661 22     22   36 my $client = shift;
1662 22         24 my $rdata = shift;
1663 22   50     70 my $modulekey = $client->{_encrypt} || return undef;
1664 0         0 my $module = $_ENCRYPT_AVAILABLE{$modulekey}{name};
1665 0         0 my $cbc = $_ENCRYPT_AVAILABLE{$modulekey}{cbc};
1666 0         0 my $mergewithpassword = $_ENCRYPT_AVAILABLE{$modulekey}{mergewithpassword};
1667 0         0 my $newdata;
1668             my $temp;
1669 0   0     0 my $publickey = $client->{_remotepublickey} || return undef;
1670 0         0 my $cleanpassword;
1671              
1672 0 0       0 if (defined $client->{_password}) {
1673 0         0 $cleanpassword = $client->{_password};
1674 0         0 $cleanpassword =~ s/[^a-z0-9]//gi;
1675             }
1676             else {
1677 0         0 $cleanpassword = undef;
1678             }
1679              
1680             #
1681             # If there is a password for the connection, and we're using Symmetric encryption, we include the password
1682             # in the encryption key used
1683             #
1684 0 0 0     0 if ($mergewithpassword && defined $cleanpassword && length($cleanpassword) && $client->{_authenticated} && !$client->{_negotiating} && $client->{_version} >= 0.15) {
      0        
      0        
      0        
      0        
1685 0 0       0 if (length($cleanpassword) <= length($publickey)) {
    0          
1686 0         0 substr($publickey, 0, length($cleanpassword)) = $cleanpassword;
1687             }
1688             elsif (length($cleanpassword) > length($publickey)) {
1689 0         0 $publickey = substr($cleanpassword, 0, length($publickey));
1690             }
1691             else {
1692 0         0 $@ = "Failed to merge password with symmetric encryption key";
1693 0         0 return undef;
1694             }
1695             }
1696 0 0       0 if ($publickey =~ /^(\%[0-9A-F]{2})+$/) {
1697              
1698             #
1699             # In the case of binary keys (such as RSA's) they're ascii-armored, we need to decrypt them
1700             #
1701 0   0     0 $publickey = thaw(_asc2bin($publickey)) || return undef;
1702 0         0 $client->{_remotepublickey} = $publickey;
1703             }
1704              
1705             #
1706             # Encrypt the data into $newdata if possible
1707             #
1708 0 0       0 if ($module eq 'Crypt::RSA') {
    0          
    0          
1709 0         0 eval {
1710 0   0     0 $temp = Crypt::RSA->new() || die "Failed to create new Crypt::RSA object for encryption: $! $@\n";
1711 0 0       0 $newdata = $temp->encrypt(
1712             Message => $$rdata,
1713             Key => $publickey,
1714             Armour => 0,
1715             )
1716             or die "Failed to encrypt data with Crypt::RSA: " . $temp->errstr() . "\n";
1717             };
1718             }
1719             elsif ($module eq 'Crypt::CipherSaber') {
1720 0         0 $temp = Crypt::CipherSaber->new($publickey);
1721 0         0 $newdata = $temp->encrypt($$rdata);
1722             }
1723             elsif ($cbc) {
1724 0         0 $temp = Crypt::CBC->new($publickey, $module);
1725 0         0 $newdata = $temp->encrypt($$rdata);
1726             }
1727             else {
1728 0         0 $@ = "Unknown encryption module [$module] modulekey [$modulekey]";
1729             }
1730              
1731             #
1732             # Finally, override reference if encryption succeeded
1733             #
1734 0 0       0 if ($newdata) {
1735 0         0 $$rdata = $newdata;
1736 0         0 return 1;
1737             }
1738             else {
1739 0         0 return undef;
1740             }
1741              
1742             }
1743              
1744             #
1745             # Does the opposite of _encrypt();
1746             #
1747             sub _decrypt {
1748 0     0   0 my $client = shift;
1749 0         0 my $rdata = shift;
1750 0   0     0 my $modulekey = $client->{_encrypt} || return undef;
1751 0         0 my $module = $_ENCRYPT_AVAILABLE{$modulekey}{name};
1752 0         0 my $cbc = $_ENCRYPT_AVAILABLE{$modulekey}{cbc};
1753 0         0 my $mergewithpassword = $_ENCRYPT_AVAILABLE{$modulekey}{mergewithpassword};
1754 0         0 my $newdata;
1755             my $temp;
1756 0   0     0 my $privatekey = $client->{_localprivatekey} || return undef;
1757 0         0 my $cleanpassword;
1758              
1759 0 0       0 if (defined $client->{_password}) {
1760 0         0 $cleanpassword = $client->{_password};
1761 0         0 $cleanpassword =~ s/[^a-z0-9]//gi;
1762             }
1763             else {
1764 0         0 $cleanpassword = undef;
1765             }
1766              
1767             #
1768             # If there is a password for the connection, and we're using Symmetric encryption, we include the password
1769             # in the decryption key used
1770             #
1771 0 0 0     0 if ($mergewithpassword && defined $cleanpassword && length($cleanpassword) && $client->{_authenticated} && !$client->{_negotiating} && $client->{_version} >= 0.15) {
      0        
      0        
      0        
      0        
1772 0 0       0 if (length($cleanpassword) <= length($privatekey)) {
    0          
1773 0         0 substr($privatekey, 0, length($cleanpassword)) = $cleanpassword;
1774             }
1775             elsif (length($cleanpassword) > length($privatekey)) {
1776 0         0 $privatekey = substr($cleanpassword, 0, length($privatekey));
1777             }
1778             else {
1779 0         0 $@ = "Failed to merge password with symmetric encryption key";
1780 0         0 return undef;
1781             }
1782             }
1783 0 0       0 if ($privatekey =~ /^(\%[0-9A-F]{2})+$/) {
1784              
1785             #
1786             # In the case of binary keys (such as RSA's) they're ascii-armored, we need to decrypt them
1787             #
1788 0         0 $privatekey = _asc2bin($privatekey);
1789             }
1790              
1791             #
1792             # Decrypt the data
1793             #
1794 0 0       0 if ($module eq 'Crypt::RSA') {
    0          
    0          
1795 0         0 eval {
1796 0 0       0 if (!ref($privatekey)) {
1797 0 0       0 if ($privatekey =~ /bless/) {
1798              
1799             # We need to deserialize the private key with Crypt::RSA::Key::Private's undocumented deserialize function
1800 0 0       0 $temp = Crypt::RSA::Key::Private->new() or die "Failed to initialize empty Crypt::RSA::Key::Private object\n";
1801 0 0       0 $privatekey = $temp->deserialize(String => [$privatekey]) or die "Failed to deserialize Crypt::RSA private key\n";
1802             }
1803             else {
1804 0         0 die "The Crypt::RSA private key is absolutely unusable\n";
1805             }
1806             }
1807 0   0     0 $temp = Crypt::RSA->new() || die "Failed to create new Crypt::RSA object for decryption: $! $@\n";
1808 0 0       0 $newdata = $temp->decrypt(
1809             Cyphertext => $$rdata,
1810             Key => $privatekey,
1811             Armour => 0,
1812             )
1813             or die "Failed to decrypt data with Crypt::RSA : " . $temp->errstr() . "\n";
1814             };
1815             }
1816             elsif ($module eq 'Crypt::CipherSaber') {
1817 0         0 $temp = Crypt::CipherSaber->new($privatekey);
1818 0         0 $newdata = $temp->decrypt($$rdata);
1819             }
1820             elsif ($cbc) {
1821 0         0 $temp = Crypt::CBC->new($privatekey, $module);
1822 0         0 $newdata = $temp->decrypt($$rdata);
1823             }
1824             else {
1825 0         0 $@ = "Unknown encryption module [$module] modulekey [$modulekey]";
1826             }
1827              
1828             #
1829             # Finally, override reference if decryption succeeded
1830             #
1831 0 0       0 if ($newdata) {
1832 0         0 $$rdata = $newdata;
1833 0         0 return 1;
1834             }
1835             else {
1836 0         0 return undef;
1837             }
1838              
1839             }
1840              
1841             #
1842             # This sub returns a random string
1843             # Expects an integer (length)
1844             # Accepts optional boolean that defines whether string should be made up of letters only or not
1845             #
1846             sub _genrandstring {
1847 2     2   5 my $l = shift;
1848 2         4 my $lettersonly = shift;
1849 2         3 my ($minord, $maxord);
1850 0         0 my $key;
1851 0         0 my $avoid;
1852 0         0 my $module;
1853 0         0 my $version;
1854              
1855 2 100       6 if ($lettersonly) {
1856 1         2 $minord = 97;
1857 1         2 $maxord = 122;
1858             }
1859             else {
1860 1         2 $minord = 33;
1861 1         3 $maxord = 126;
1862             }
1863              
1864             #
1865             # First, we try one of the fancy randomness modules possibly in %_MISC_AVAILABLE
1866             #
1867 2         9 foreach (@{ $_MISC_AVAILABLE{_order} }) {
  2         13  
1868 0         0 $module = $_MISC_AVAILABLE{$_}{name};
1869 0         0 $version = $_MISC_AVAILABLE{$_}{version};
1870              
1871             #
1872             # Note that Crypt::Random has the makerandom_octet function ONLY in 0.34 and higher
1873             #
1874 0 0 0     0 if ($module eq "Crypt::Random" && $version >= 0.34) {
1875 0         0 for (0 .. $minord - 1, $maxord + 1 .. 255) {
1876 0         0 $avoid .= chr($_);
1877             }
1878 0         0 $key = Crypt::Random::makerandom_octet(
1879             Length => $l,
1880             Skip => $avoid,
1881             );
1882 0         0 return $key;
1883             }
1884             }
1885              
1886             #
1887             # If we've reached here, then no modules were found. We'll use perl's builtin rand() to generate
1888             # the string
1889             #
1890 2         7 for (1 .. $l) {
1891 131         261 $key .= chr(int(rand($maxord - $minord)) + $minord);
1892             }
1893 2         13 return $key;
1894             }
1895              
1896             #
1897             # Once a new client is connected it calls this to negotiate basics with the server
1898             # This must return true once all negotiations succeed or false if not
1899             #
1900             sub _client_negotiate {
1901 1     1   10 my $client = shift;
1902 1         3 my $reply;
1903 1         2 my $timeout = 90;
1904 1         3 my @P;
1905             my $command;
1906 0         0 my $data;
1907 0         0 my $temp;
1908 0         0 my $temp2;
1909 0         0 my ($temppublic, $tempprivate, $tempscalar);
1910 0         0 my $version;
1911 0         0 my $evl;
1912 1         2 my $starttime = time;
1913              
1914 1         7 while ((time - $starttime) < $timeout) {
1915 10         195 $reply = $client->receive($timeout, 1);
1916 10 50       26 if (!defined $reply) {
1917 0         0 last;
1918             }
1919 10         57 @P = split(/\x00/, $reply);
1920 10         17 $command = shift(@P);
1921 10         16 $evl = undef;
1922 10         13 $data = undef;
1923 10 50       22 if (!$command) {
1924 0         0 $@ = "Error negotiating with server. No command received.";
1925 0         0 return undef;
1926             }
1927 10 50 33     170 if ($command eq "PF") {
    100 33        
    50 33        
    50          
    50          
    100          
    100          
    100          
    50          
    100          
    100          
    50          
    50          
    100          
    100          
    50          
    100          
1928              
1929             #
1930             # Password Failure
1931             #
1932 0         0 $client->{_authenticated} = 0;
1933 0         0 $@ = "Server rejected supplied password";
1934 0         0 return undef;
1935             }
1936             elsif ($command eq "COS") {
1937              
1938             #
1939             # Compatability Scalar
1940             #
1941 1         10 $client->{_compatabilityscalar} = _asc2bin($P[0]);
1942 1         7 $client->{_compatabilityreference} = _gencompatabilityreference($client->{_compatabilityscalar});
1943 1         3 $data = "COS\x00" . $P[0];
1944             }
1945             elsif ($command eq "COF") {
1946              
1947             #
1948             # Compatability failure
1949             #
1950 0         0 $@ = "Compatability failure: The client and server could not negotiate compatability regarding: $P[0]";
1951 0         0 return undef;
1952             }
1953             elsif ($command eq "CVF" && !$client->{_donotcheckversion}) {
1954              
1955             #
1956             # Compression Version Failure
1957             #
1958 0         0 $temp = $_COMPRESS_AVAILABLE{ $client->{_compress} }{name};
1959 0         0 $version = $_COMPRESS_AVAILABLE{ $client->{_compress} }{version};
1960 0         0 $@ = "Compression version mismatch for $temp : Local version $version remote version $P[0] : Upgrade both to same version or read the documentation of this module for how to forcefully ignore this problem";
1961 0         0 return undef;
1962             }
1963             elsif ($command eq "EVF" && !$client->{_donotcheckversion}) {
1964              
1965             #
1966             # Encryption Version Failure
1967             #
1968 0         0 $temp = $_ENCRYPT_AVAILABLE{ $client->{_encrypt} }{name};
1969 0         0 $version = $_ENCRYPT_AVAILABLE{ $client->{_encrypt} }{version};
1970 0         0 $@ = "Encryption version mismatch for $temp : Local version $version remote version $P[0] : Upgrade both to same version or read the documentation of this module for how to forcefully ignore this problem";
1971 0         0 return undef;
1972             }
1973             elsif ($command eq "EN") {
1974              
1975             #
1976             # End of negotiation
1977             #
1978 1         3 $data = "EN";
1979 1         3 $evl = 'return("RETURN1");';
1980             }
1981             elsif ($command eq "VE") {
1982              
1983             #
1984             # Version of module
1985             #
1986 1         49 $client->{_version} = $P[0];
1987 1         3 $data = "VE\x00$VERSION";
1988             }
1989             elsif ($command eq "SVE") {
1990              
1991             #
1992             # Version of the Storable module
1993             #
1994 1         6 $client->{_storableversion} = $P[0];
1995 1 50       5 if ($P[1]) {
1996              
1997             #
1998             # New compatability method
1999             #
2000 1         4 eval { $temp = thaw(_asc2bin($P[1])); };
  1         6  
2001 1 50 33     219 if (!$temp || $@) {
2002 0         0 $@ = "Error thawing compatability reference: $! $@ -- This may be because you're using binary-image-incompatible versions of the Storable module. Please update the Storable module on both ends othe the connection to the same latest stable version.";
2003 0         0 return undef;
2004             }
2005 1 50       17 if (!_comparereferences($temp, $client->{_compatabilityreference})) {
2006 0         0 $@ = "Incompatible version mismatch for the Storable module: Local version " . $Storable::VERSION . " remote version $P[0] : Upgrade both to compatible (preferrably same) versions : $@";
2007 0         0 return undef;
2008             }
2009             }
2010 1         3 $data = "SVE\x00" . $Storable::VERSION;
2011 1 50       7 if ($client->{_compatabilityreference}) {
2012 1         13 $data .= "\x00" . _bin2asc(nfreeze($client->{_compatabilityreference}));
2013             }
2014             }
2015             elsif ($command eq "SVF" && !$client->{_donotcheckversion}) {
2016              
2017             #
2018             # Storable Module Version Failure
2019             #
2020 0         0 $version = $Storable::VERSION;
2021 0         0 $@ = "Version mismatch for the Storable module : Local version $version remote version $P[0] : Upgrade both to same version or read the documentation of this module for how to forcefully ignore this problem";
2022 0         0 return undef;
2023             }
2024             elsif ($command eq "CS") {
2025              
2026             #
2027             # Crypt Salt
2028             #
2029             # We assume that we've authenticated successfully
2030 1         7 $client->{_authenticated} = 1;
2031 1         648 $temp = _munge($client, crypt($client->{_password}, $P[0]));
2032 1         8 $data = "CP\x00$temp";
2033             }
2034             elsif ($command eq "EK") {
2035              
2036             #
2037             # Encryption key
2038             #
2039 1         6 $client->{_remotepublickey} = _munge($client, $P[0]);
2040 1         4 $data = "EK\x00";
2041 1         4 $data .= _munge($client, $client->{_localpublickey});
2042             }
2043             elsif ($command eq "EM") {
2044              
2045             #
2046             # Encryption module
2047             #
2048 0 0       0 if ($client->{_donotencryptwith}{ $P[0] }) {
    0          
2049 0         0 $data = "NO\x00I do not encrypt with this module";
2050             }
2051             elsif (!$client->{_donotencrypt}) {
2052              
2053             #
2054             # Let's see if we can handle decrypting this module
2055             #
2056 0         0 $tempprivate = _asc2bin($P[2]);
2057 0         0 $tempscalar = _asc2bin($P[3]);
2058              
2059             #
2060             # Sometimes the tempprivate is frozen. If we can thaw it, let's do it:
2061             #
2062 0         0 eval { $temp = thaw $tempprivate };
  0         0  
2063 0 0       0 if (!$@) {
2064 0         0 $tempprivate = $temp;
2065             }
2066 0         0 $client->{_encrypt} = $P[0];
2067 0         0 $client->{_localprivatekey} = $tempprivate;
2068 0 0 0     0 if (_decrypt($client, \$tempscalar) && $tempscalar eq $client->{_compatabilityscalar}) {
2069              
2070             #
2071             # This is a viable module that we can decrypt.
2072             #
2073 0         0 ($temppublic, $tempprivate) = _genkey($P[0], 1);
2074 0 0 0     0 if ($temppublic && $tempprivate) {
2075              
2076             #
2077             # I created a keypair with that module type successfully
2078             #
2079 0         0 $client->{_remotepublickey} = $temppublic;
2080 0 0       0 if (_encrypt($client, \$tempscalar)) {
2081 0 0       0 $data = "EM\x00$P[0]\x00" . $_ENCRYPT_AVAILABLE{ $P[0] }{version} . "\x00" . _bin2asc(ref($tempprivate) ? nfreeze $tempprivate : $tempprivate) . "\x00" . _bin2asc($tempscalar);
2082             }
2083 0         0 delete $client->{_remotepublickey};
2084             }
2085             else {
2086              
2087             #
2088             # Failed to create a keypair - no way I could encrypt with that
2089             #
2090 0         0 $data = "NO\x00$@";
2091             }
2092             }
2093             else {
2094              
2095             #
2096             # Failed to decrypt message from server
2097             #
2098 0         0 $data = "NO\x00$@";
2099             }
2100 0         0 delete $client->{_encrypt};
2101 0         0 delete $client->{_localprivatekey};
2102             }
2103             else {
2104              
2105             #
2106             # I was told not to encrypt
2107             #
2108 0         0 $data = "NO\x00I do not encrypt";
2109              
2110             }
2111             }
2112             elsif ($command eq "EU") {
2113              
2114             #
2115             # Encryption Use
2116             #
2117 0 0       0 if ($client->{_donotencryptwith}{ $P[0] }) {
    0          
2118 0         0 $data = "NO\x00I do not encrypt with this module";
2119             }
2120             elsif (!$client->{_donotencrypt}) {
2121 0         0 $temp2 = $P[0];
2122 0         0 $data = "EU\x00$temp2";
2123 0         0 $evl = '$client->{_encrypt} = $temp2;';
2124 0         0 $evl .= '($client->{_localpublickey},$client->{_localprivatekey}) =';
2125 0         0 $evl .= ' _genkey($client->{_encrypt}) or ';
2126 0         0 $evl .= ' return("RETURN0"); ';
2127             }
2128             else {
2129 0         0 $data = "NO\x00I do not encrypt";
2130             }
2131             }
2132             elsif ($command eq "EA") {
2133              
2134             #
2135             # Encryption available
2136             #
2137 1         8 $temp2 = "";
2138 1         3 $version = "";
2139 1 50       6 if (!$client->{_donotencrypt}) {
2140 1         4 foreach (@P) {
2141 0 0       0 if ($_ENCRYPT_AVAILABLE{$_}) {
2142 0         0 $temp2 = $_;
2143 0         0 $version = $_ENCRYPT_AVAILABLE{$_}{version};
2144 0         0 last;
2145             }
2146             }
2147 1   50     61 $temp2 ||= "";
2148 1   50     13 $version ||= "";
2149             }
2150 1         3 $data = "EU\x00$temp2\x00$version";
2151 1 50       4 if ($temp2) {
2152 0         0 $evl = '$client->{_encrypt} = $temp2;';
2153 0         0 $evl .= '($client->{_localpublickey},$client->{_localprivatekey}) =';
2154 0         0 $evl .= ' _genkey($client->{_encrypt}) or ';
2155 0         0 $evl .= ' return("RETURN0"); ';
2156             }
2157             }
2158             elsif ($command eq "CM") {
2159              
2160             #
2161             # Compression module
2162             #
2163 1 50       10 if ($client->{_donotcompresswith}{ $P[0] }) {
    50          
2164 0         0 $data = "NO\x00I do not compress with this module";
2165             }
2166             elsif (!$client->{_donotcompress}) {
2167              
2168             #
2169             # Let's see if we can decompress this
2170             #
2171 1         6 $tempscalar = _asc2bin($P[2]);
2172 1         8 $client->{_compress} = $P[0];
2173 1 50 33     8 if (_decompress($client, \$tempscalar) && $tempscalar eq $client->{_compatabilityscalar}) {
2174              
2175             #
2176             # This is a viable module that we can decompress.
2177             #
2178 0 0       0 if (_compress($client, \$tempscalar)) {
2179 0         0 $data = "CM\x00$P[0]\x00" . $_COMPRESS_AVAILABLE{ $P[0] }{version} . "\x00" . _bin2asc($tempscalar);
2180             }
2181             }
2182             else {
2183              
2184             #
2185             # Failed to decompress message from server
2186             #
2187 1         85 $data = "NO\x00$@";
2188             }
2189 1         7 delete $client->{_compress};
2190             }
2191             else {
2192              
2193             #
2194             # I was told not to compress
2195             #
2196 0         0 $data = "NO\x00I do not compress";
2197             }
2198             }
2199             elsif ($command eq "CU") {
2200              
2201             #
2202             # Compression Use
2203             #
2204 0 0       0 if ($client->{_donotcompresswith}{ $P[0] }) {
    0          
2205 0         0 $data = "NO\x00I do not compress with this module";
2206             }
2207             elsif (!$client->{_donotcompress}) {
2208 0         0 $temp2 = $P[0];
2209 0         0 $data = "CU\x00$temp2";
2210 0         0 $evl = '$client->{_compress} = $temp2;';
2211             }
2212             else {
2213 0         0 $data = "NO\x00I do not compress";
2214             }
2215             }
2216             elsif ($command eq "CA") {
2217              
2218             #
2219             # Compression available
2220             #
2221 1         3 $temp2 = "";
2222 1         3 $version = "";
2223 1 50       89 if (!$client->{_donotcompress}) {
2224 1         4 foreach (@P) {
2225 1 50       5 if ($_COMPRESS_AVAILABLE{$_}) {
2226 1         4 $temp2 = $_;
2227 1         4 $version = $_COMPRESS_AVAILABLE{$_}{version};
2228 1         2 last;
2229             }
2230             }
2231 1   50     8 $temp2 ||= "";
2232 1   50     7 $version ||= "";
2233             }
2234 1         64 $data = "CU\x00$temp2\x00$version";
2235 1 50       5 if ($temp2) {
2236 1         3 $evl = '$client->{_compress} = $temp2;';
2237             }
2238             }
2239             else {
2240              
2241             #
2242             # No Operation (do nothing)
2243             #
2244 1         16 $data = "NO\x00I don't understand you";
2245             }
2246 10 50 33     56 if (defined $data && !_send($client, $data, 0)) {
2247 0         0 $@ = "Error negotiating with server: Could not send : $@";
2248 0         0 return undef;
2249             }
2250              
2251             #
2252             # NOW WE SEE IF WE NEED TO EVL ANYTHING
2253             # IF THE RESULT OF THE EVAL IS "RETURNx" WHERE X IS A NUMBER, WE RETURN
2254             # OTHERWISE WE KEEP GOING
2255             #
2256 10 100       40 if (defined $evl) {
2257 2         477 $evl = eval($evl);
2258 2 100       24 if ($evl =~ /^RETURN(.+)$/) {
2259 1 50       9 return (($1) ? $1 : undef);
2260             }
2261             }
2262             }
2263 0         0 $@ = "Client timed out while negotiating with server [" . (time - $starttime) . "/$timeout] : $@";
2264 0         0 return undef;
2265             }
2266              
2267             #
2268             # Once the server accepts a new connection, it calls this to negotiate basics with the client
2269             # Unlike _client_negotiate() which does not return until negotiation is over, this sub
2270             # sends 1 command or parses one reply at a time then returns immediately
2271             # Although this is much more complicated, it needs to be done so
2272             # the server does not block when a client is negotiating with it
2273             #
2274             # Expects a client object
2275             #
2276             sub _serverclient_negotiate {
2277 20     20   48 my $client = shift;
2278 20         31 my ($tempprivate, $tempscalar);
2279 0         0 my $reply;
2280 0         0 my $temp;
2281 0         0 my @P;
2282 0         0 my $command;
2283 0         0 my $version;
2284              
2285 20 50       52 if (!$client->{_negotiating}) {
2286 0         0 return 1;
2287             }
2288              
2289 20         108 $reply = $client->data();
2290              
2291             # Let's avoid some strict claimings
2292 20 100       48 if (!defined $reply) { $reply = "" }
  10         23  
2293 20 100       49 if (!defined $client->{_negotiating_lastevent}) { $client->{_negotiating_lastevent} = "" }
  1         19  
2294              
2295 20 100       54 if (length($reply)) {
    50          
2296              
2297             #
2298             # We're parsing a reply the other end sent us
2299             #
2300 10         68 @P = split(/\x00/, $reply);
2301 10         20 $command = shift(@P);
2302 10 50       22 if (!$command) {
2303 0         0 $@ = "Error negotiating. No command received from client : $@";
2304 0         0 return undef;
2305             }
2306 10         25 $client->{_negotiating_lastevent} = "received";
2307 10 100       92 if ($command eq "EU") {
    50          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
2308              
2309             #
2310             # Encryption Use
2311             #
2312 1         101 $client->{_encrypt} = $P[0];
2313 1 50       7 if ($client->{_encrypt}) {
2314 0         0 $version = $_ENCRYPT_AVAILABLE{ $P[0] }{version};
2315 0 0 0     0 if ($version ne $P[1] && !$client->{_negotiatedencryptcompatability}) {
2316 0         0 unshift(@{ $client->{_negotiating_commands} }, "EVF\x00$version");
  0         0  
2317             }
2318 0 0       0 ($client->{_localpublickey}, $client->{_localprivatekey}) = _genkey($client->{_encrypt}) or return undef;
2319             }
2320 1         2 $temp = "EK\x00";
2321 1         13 $temp .= _munge($client, $client->{_localpublickey});
2322 1         2 unshift(@{ $client->{_negotiating_commands} }, $temp);
  1         4  
2323             }
2324             elsif ($command eq "EM") {
2325              
2326             #
2327             # Encryption module
2328             #
2329 0 0       0 if ($client->{_donotencryptwith}{ $P[0] }) {
    0          
2330              
2331             #
2332             # I was told not to encrypt with this module
2333             #
2334             }
2335             elsif (!$client->{_donotencrypt}) {
2336              
2337             #
2338             # Let's see if we can decrypt this module
2339             #
2340 0         0 $tempprivate = _asc2bin($P[2]);
2341 0         0 $tempscalar = _asc2bin($P[3]);
2342              
2343             #
2344             # Sometimes the tempprivate is frozen. If we can thaw it, let's do it:
2345             #
2346 0         0 eval { $temp = thaw $tempprivate };
  0         0  
2347 0 0       0 if (!$@) {
2348 0         0 $tempprivate = $temp;
2349             }
2350 0         0 $client->{_encrypt} = $P[0];
2351 0         0 $client->{_localprivatekey} = $tempprivate;
2352 0 0 0     0 if (_decrypt($client, \$tempscalar) && $tempscalar eq $client->{_compatabilityscalar}) {
2353              
2354             #
2355             # This is a viable module that I (the server) can decrypt
2356             # Since this is the second-reply to my EM, I know that the client can also decrypt using this module
2357             # So we use it !
2358             #
2359 0         0 unshift(@{ $client->{_negotiating_commands} }, "EU\x00$P[0]");
  0         0  
2360              
2361             #
2362             # Yank out any future EMs we were going to send the client since they're weaker
2363             #
2364 0         0 $client->{_negotiating_commands} = [ grep { $_ !~ /^EM\x00/ } @{ $client->{_negotiating_commands} } ];
  0         0  
  0         0  
2365             }
2366 0         0 delete $client->{_localprivatekey};
2367 0         0 delete $client->{_encrypt};
2368              
2369             #
2370             # Don't try EAs after this - we know the client supports EMs
2371             #
2372 0         0 $client->{_negotiatedencryptcompatability} = 1;
2373             }
2374             else {
2375              
2376             #
2377             # I was told not to encrypt
2378             #
2379             }
2380             }
2381             elsif ($command eq "CP") {
2382              
2383             #
2384             # Crypt Password
2385             #
2386 1 50       5 if (_munge($client, $P[0]) eq crypt($client->{_password}, $client->{_cryptsalt})) {
2387 1         4 $client->{_authenticated} = 1;
2388             }
2389             else {
2390 0         0 $client->{_authenticated} = 0;
2391 0         0 unshift(@{ $client->{_negotiating_commands} }, "PF");
  0         0  
2392             }
2393             }
2394             elsif ($command eq "COS") {
2395              
2396             #
2397             # Compatability scalar
2398             #
2399 1 50       6 if ($client->{_compatabilityscalar} ne _asc2bin($P[0])) {
2400 0         0 unshift(@{ $client->{_negotiating_commands} }, "COF\x00Initial scalar exchange");
  0         0  
2401             }
2402             }
2403             elsif ($command eq "VE") {
2404              
2405             #
2406             # Version
2407             #
2408 1         9 $client->{_version} = $P[0];
2409             }
2410             elsif ($command eq "SVE") {
2411              
2412             #
2413             # Version of Storable
2414             #
2415 1         3 $client->{_storableversion} = $P[0];
2416 1 50       710 if ($P[1]) {
    0          
2417              
2418             #
2419             # New method
2420             #
2421 1         6 $temp = thaw(_asc2bin($P[1]));
2422 1 50       64 if (!$temp) {
2423 0         0 unshift(@{ $client->{_negotiating_commands} }, "COF\x00Thawing compatability reference with the Storable module");
  0         0  
2424             }
2425 1 50       10 if (!_comparereferences($temp, $client->{_compatabilityreference})) {
2426 0         0 unshift(@{ $client->{_negotiating_commands} }, "COF\x00Comparing compatability reference with the Storable module");
  0         0  
2427             }
2428             }
2429             elsif ($P[0] ne $Storable::VERSION) {
2430              
2431             #
2432             # Old method
2433             #
2434 0         0 unshift(@{ $client->{_negotiating_commands} }, "SVF\x00" . $Storable::VERSION);
  0         0  
2435             }
2436             }
2437             elsif ($command eq "CM") {
2438              
2439             #
2440             # Compression module
2441             #
2442 0 0       0 if ($client->{_donotcompresswith}{ $P[0] }) {
    0          
2443              
2444             # I was told not to compress with this module
2445             }
2446             elsif (!$client->{_donotcompress}) {
2447              
2448             #
2449             # Let's see if we can decompress this module
2450             #
2451 0         0 $tempscalar = _asc2bin($P[2]);
2452 0         0 $client->{_compress} = $P[0];
2453 0 0 0     0 if (_decompress($client, \$tempscalar) && $tempscalar eq $client->{_compatabilityscalar}) {
2454              
2455             #
2456             # This is a viable module that I (the server) can decompress
2457             # Since this is the second-reply to my CM, I know that the client can also decrypt using this module
2458             # So we use it !
2459             #
2460 0         0 unshift(@{ $client->{_negotiating_commands} }, "CU\x00$P[0]");
  0         0  
2461              
2462             #
2463             # Yank out any future CMs we were going to send the client since they're weaker
2464             #
2465 0         0 $client->{_negotiating_commands} = [ grep { $_ !~ /^CM\x00/ } @{ $client->{_negotiating_commands} } ];
  0         0  
  0         0  
2466             }
2467 0         0 delete $client->{_compress};
2468              
2469             #
2470             # Don't try CAs after this - we know the client supports CMs
2471             #
2472 0         0 $client->{_negotiatedcompresscompatability} = 1;
2473             }
2474             else {
2475              
2476             #
2477             # I was told not to compress
2478             #
2479             }
2480             }
2481             elsif ($command eq "CU") {
2482              
2483             #
2484             # Compression Use
2485             #
2486 1         4 $client->{_compress} = $P[0];
2487 1 50       5 if ($client->{_compress}) {
2488 1         4 $version = $_COMPRESS_AVAILABLE{ $P[0] }{version};
2489 1 50 33     12 if ($version ne $P[1] && !$client->{_negotiatedcompresscompatability}) {
2490 0         0 unshift(@{ $client->{_negotiating_commands} }, "CVF\x00$version");
  0         0  
2491             }
2492             }
2493             }
2494             elsif ($command eq "EK") {
2495              
2496             #
2497             # Encryption Key
2498             #
2499 1         5 $client->{_remotepublickey} = _munge($client, $P[0]);
2500             }
2501             elsif ($command eq "EN") {
2502              
2503             #
2504             # End (of negotiation)
2505             #
2506 1 50 33     28 if ((defined $client->{_password} && length($client->{_password})) && !$client->{_authenticated}) {
      33        
2507 0         0 return undef;
2508             }
2509             else {
2510 1         3 $client->{_negotiating} = 0;
2511 1         4 delete $client->{_negotiating_lastevent};
2512 1         3 delete $client->{_negotiating_commands};
2513 1         4 return 1;
2514             }
2515             }
2516             else {
2517              
2518             # received unknown reply. so what..
2519             }
2520             }
2521             elsif ($client->{_negotiating_lastevent} ne "sent") {
2522              
2523             # We're sending a command to the other end, now we have to figure out which one
2524 10         43 _serverclient_negotiate_sendnext($client);
2525             }
2526 19         294 return undef;
2527             }
2528              
2529             #
2530             # This is called by _serverclient_negotiate(). It's job is to figure out what's the next command to send
2531             # to the other end and send it.
2532             #
2533             # Expects a client object
2534             #
2535             sub _serverclient_negotiate_sendnext {
2536 10     10   17 my $client = shift;
2537 10         11 my $data;
2538 10         16 my $class = $client;
2539 10         30 my ($temppublic, $tempprivate, $tempscalar);
2540 0         0 my $key;
2541 0         0 my @available;
2542 10         94 $class =~ s/=.*//g;
2543              
2544 10 100       33 if (!defined $client->{_negotiating_commands}) {
2545              
2546             #
2547             # Let's initialize the sequence of commands we send
2548             #
2549 1         2 $data = "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n";
2550 1         3 $data .= "-----BEGIN CLEARTEXT WELCOME MESSAGE-----\r\n";
2551 1         3 $data .= "::\r\n";
2552 1         6 $data .= ":: HELLO :: $class VERSION $VERSION :: SERVER READY ::\r\n";
2553 1         2 $data .= "::\r\n";
2554 1 50       5 if ($client->{_welcome}) {
2555 0         0 $data .= ":: $client->{_welcome}\r\n";
2556 0         0 $data .= "::\r\n";
2557             }
2558 1         3 $data .= "-----END CLEARTEXT WELCOME MESSAGE-----\r\n";
2559 1         2 push(@{ $client->{_negotiating_commands} }, $data);
  1         4  
2560 1         3 $data = "VE\x00$VERSION";
2561 1         2 push(@{ $client->{_negotiating_commands} }, $data);
  1         5  
2562 1         25 $data = "COS\x00" . _bin2asc($client->{_compatabilityscalar});
2563 1         3 push(@{ $client->{_negotiating_commands} }, $data);
  1         3  
2564 1         31 $data = "SVE\x00" . $Storable::VERSION . "\x00" . _bin2asc(nfreeze($client->{_compatabilityreference}));
2565 1         4 push(@{ $client->{_negotiating_commands} }, $data);
  1         6  
2566              
2567 1 50       5 if (!$client->{_donotencrypt}) {
2568              
2569 1         3 @available = ();
2570              
2571             #
2572             # New method
2573             #
2574 1         2 foreach $key (@{ $_ENCRYPT_AVAILABLE{_order} }) {
  1         13  
2575 0 0       0 if ($client->{_donotencryptwith}{$key}) {
2576              
2577             # I was told not to encrypt with this module
2578 0         0 next;
2579             }
2580 0 0       0 ($temppublic, $tempprivate) = _genkey($key, 1) or next;
2581 0         0 $client->{_remotepublickey} = $temppublic;
2582 0         0 $client->{_encrypt} = $key;
2583 0         0 $tempscalar = $client->{_compatabilityscalar};
2584 0 0       0 if (_encrypt($client, \$tempscalar)) {
2585 0         0 push(@available, $key);
2586 0 0       0 $data = "EM\x00$key\x00" . $_ENCRYPT_AVAILABLE{$key}{version} . "\x00" . _bin2asc(ref($tempprivate) ? nfreeze $tempprivate : $tempprivate) . "\x00" . _bin2asc($tempscalar);
2587 0         0 push(@{ $client->{_negotiating_commands} }, $data);
  0         0  
2588             }
2589 0         0 delete $client->{_remotepublickey};
2590 0         0 delete $client->{_encrypt};
2591             }
2592              
2593             #
2594             # Old method
2595             #
2596 1         7 $data = "EA" . join("", map { "\x00$_" } @available);
  0         0  
2597 1         2 push(@{ $client->{_negotiating_commands} }, $data);
  1         5  
2598             }
2599 1 50       6 if (!$client->{_donotcompress}) {
2600              
2601 1         3 @available = ();
2602              
2603             #
2604             # New method
2605             #
2606 1         2 foreach $key (@{ $_COMPRESS_AVAILABLE{_order} }) {
  1         12  
2607 1 50       6 if ($client->{_donotcompresswith}{$key}) {
2608              
2609             # I was told not to compress with this module
2610 0         0 next;
2611             }
2612 1         215 $client->{_compress} = $key;
2613 1         10 $tempscalar = $client->{_compatabilityscalar};
2614 1 50       12 if (_compress($client, \$tempscalar)) {
2615 1         2 push(@available, $key);
2616 1         9 $data = "CM\x00$_\x00" . $_COMPRESS_AVAILABLE{$_}{version} . "\x00" . _bin2asc($tempscalar);
2617 1         3 push(@{ $client->{_negotiating_commands} }, $data);
  1         5  
2618             }
2619 1         7 delete $client->{_compress};
2620             }
2621              
2622             #
2623             # Old method
2624             #
2625 1         4 $data = "CA" . join("", map { "\x00$_" } @available);
  1         8  
2626 1         2 push(@{ $client->{_negotiating_commands} }, $data);
  1         4  
2627             }
2628 1 50       6 if (defined $client->{_password}) {
2629 1 50       5 if (!exists $client->{_cryptsalt}) {
2630 1         5 $client->{_cryptsalt} = _genrandstring(2, 1);
2631             }
2632 1         3 $data = "CS\x00" . $client->{_cryptsalt};
2633 1         2 push(@{ $client->{_negotiating_commands} }, $data);
  1         3  
2634             }
2635 1         3 push(@{ $client->{_negotiating_commands} }, "EN");
  1         14  
2636             }
2637              
2638 10         13 $data = shift @{ $client->{_negotiating_commands} };
  10         27  
2639 10 50 33     96 if (($data =~ /^EA\x00/ && $client->{_negotiatedencryptcompatability}) || ($data =~ /^CA\x00/ && $client->{_negotiatedcompresscompatability})) {
      66        
      33        
2640              
2641             #
2642             # We've already negotiated through compatability. No need to re-negotiate based on versions
2643             #
2644 0         0 $data = "NO\x00Already negotiated through compatability";
2645             }
2646 10 50       23 if (!defined $data) {
2647 0         0 return undef;
2648             }
2649 10 50       40 if (!_send($client, $data, 0)) {
2650 0         0 $@ = "Error negotiating with client. Could not send : $@";
2651 0         0 return undef;
2652             }
2653 10         116 $client->{_negotiating_lastevent} = "sent";
2654 10         31 return 1;
2655             }
2656              
2657             #
2658             # This is called whenever a client (true client or serverclient) receives data without the realdata bit set
2659             # Takes client as first argument
2660             # Takes optional data as second argument, otherwise calls data() method to get it
2661             # It would parse the data and probably set variables inside the client object
2662             #
2663             sub _parseinternaldata {
2664 10     10   12 my $client = shift;
2665 10         13 my $data = shift;
2666 10 50 33     70 if ($client->{_mode} eq "serverclient" && $client->{_negotiating}) {
2667              
2668             # The serverclient is still negotiating
2669 10 100       25 if (_serverclient_negotiate($client)) {
2670              
2671             # Negotiation's complete and successful
2672 1         6 _callback($client, "connect");
2673             }
2674             }
2675             else {
2676              
2677             #
2678             # It's normal internal data
2679             #
2680 0 0       0 if (!defined $data) {
2681              
2682             #
2683             # Data was not supplied - get it from bucket
2684             #
2685 0         0 $data = $client->data();
2686             }
2687              
2688             # Now do something with it
2689             }
2690             }
2691              
2692             #
2693             # This takes an integer, packs it as tightly as possible as a binary representation
2694             # and returns the binary value
2695             #
2696             sub _packint {
2697 22     22   29 my $int = shift;
2698 22         21 my $bin;
2699 22         593 $bin = pack("N", $int);
2700 22         125 $bin =~ s/^\0+//;
2701 22         52 return $bin;
2702             }
2703              
2704             #
2705             # This does the opposite of _packint. It takes a packed binary produced by _packint and
2706             # returns the integer
2707             #
2708             sub _unpackint {
2709 22     22   40 my $bin = shift;
2710 22         25 my $int;
2711 22         62 $int = "\0" x (4 - length($bin)) . $bin;
2712 22         87 $int = unpack("N", $int);
2713 22         44 return $int;
2714             }
2715              
2716             #
2717             # This creates a new client object and outgoing connection and returns it as an object
2718             # , or returns undef if unsuccessful
2719             # If special parameter _sock is supplied, it will be taken as an existing connection
2720             # and no outgoing connection will be made
2721             #
2722             sub _new_client {
2723 2     2   15 my $class = shift;
2724 2         35 my %para = @_;
2725 2         8 my $sock;
2726 2         27 my $self = {};
2727 2         11 my $temp;
2728             my $remoteip;
2729 0         0 my $remoteport;
2730 0         0 my $key;
2731 2   50     54 my $timeout = $para{timeout} || 30;
2732 2         49 $class =~ s/=.*//g;
2733              
2734 2 100       32 if (!$para{_sock}) {
2735 1 50       15 if (!$para{host}) {
    50          
2736 0         0 $@ = "Invalid host";
2737 0         0 return undef;
2738             }
2739             elsif (!$para{port}) {
2740 0         0 $@ = "Invalid port";
2741 0         0 return undef;
2742             }
2743 1         51 $sock = new IO::Socket::INET(
2744             PeerAddr => $para{host},
2745             PeerPort => $para{port},
2746             Proto => 'tcp',
2747             Timeout => $timeout,
2748             );
2749 1         2022 $self->{_mode} = "client";
2750 1         3 $self->{_negotiating} = time;
2751             }
2752             else {
2753 1         3 $sock = $para{_sock};
2754 1         10 $self->{_mode} = "serverclient";
2755 1         7 $self->{_negotiating} = time;
2756 1         21 $self->{_authenticated} = 0;
2757             }
2758 2 50       30 if (!$sock) {
2759 0         0 $@ = "Could not connect to $para{host}:$para{port}: $!";
2760 0         0 return undef;
2761             }
2762 2         12 $sock->autoflush(1);
2763 2 100 66     98 if ($para{_remoteport} && $para{_remoteip}) {
2764 1         3 $self->{_remoteport} = $para{_remoteport};
2765 1         4 $self->{_remoteip} = $para{_remoteip};
2766             }
2767             else {
2768 1 50       26 if (!($temp = getpeername($sock))) {
2769 0         0 $@ = "Error getting peername";
2770 0         0 return undef;
2771             }
2772 1 50       27 if (!(($remoteport, $remoteip) = sockaddr_in($temp))) {
2773 0         0 $@ = "Error getting socket address";
2774 0         0 return undef;
2775             }
2776 1 50       48 if (!($self->{_remoteip} = inet_ntoa($remoteip))) {
2777 0         0 $@ = "Error determing remote IP";
2778 0         0 return undef;
2779             }
2780 1         9 $self->{_remoteport} = $remoteport;
2781             }
2782 2         5 $self->{_sock} = $sock;
2783 2         7 $self->{_password} = $para{password};
2784 2 50       12 $self->{_donotcompress} = ($para{donotcompress}) ? 1 : 0;
2785 2 50       12 $self->{_donotencrypt} = ($para{donotencrypt}) ? 1 : 0;
2786 2 50       9 $self->{_donotcheckversion} = ($para{donotcheckversion}) ? 1 : 0;
2787 2         34 $self->{_localpublickey} = "";
2788 2         11 $self->{_databucket} = [];
2789              
2790             #
2791             # Populate donotcompresswith with the keys of the supplied module names
2792             #
2793 2         11 $self->{_donotcompresswith} = {};
2794 2 50       11 if (ref($para{donotcompresswith}) ne "ARRAY") {
2795 2         11 $para{donotcompresswith} = [ $para{donotcompresswith} ];
2796             }
2797 2         40 foreach $key (keys %_COMPRESS_AVAILABLE) {
2798 4 50 66     48 if ($key ne "_order" && grep { $_COMPRESS_AVAILABLE{$key}{name} eq $_ } @{ $para{donotcompresswith} }) {
  2         24  
  2         15  
2799 0         0 $self->{_donotcompresswith}{$key} = 1;
2800             }
2801             }
2802              
2803             #
2804             # Populate donotencryptwith with the keys of the supplied module names
2805             #
2806 2         8 $self->{_donotencryptwith} = {};
2807 2 50       19 if (ref($para{donotencryptwith}) ne "ARRAY") {
2808 2         8 $para{donotencryptwith} = [ $para{donotencryptwith} ];
2809             }
2810 2         6 foreach $key (keys %_ENCRYPT_AVAILABLE) {
2811 2 50 33     13 if ($key ne "_order" && grep { $_ENCRYPT_AVAILABLE{$key}{name} eq $_ } @{ $para{donotencryptwith} }) {
  0         0  
  0         0  
2812 0         0 $self->{_donotencryptwith}{$key} = 1;
2813             }
2814             }
2815              
2816 2         8 bless($self, $class);
2817              
2818 2 100       24 if ($self->{_mode} eq "client") {
2819 1 50       23 if (!_client_negotiate($self)) {
2820              
2821             # Bad server
2822 0         0 $self->close();
2823 0         0 $@ = "Error negotiating with server: $@";
2824 0         0 return undef;
2825             }
2826             else {
2827 1         5 $self->{_negotiating} = 0;
2828             }
2829             }
2830 2         22 return $self;
2831             }
2832              
2833             #
2834             # This creates a new listening server object and returns it, or returns undef if unsuccessful
2835             #
2836             # Expects a class
2837             #
2838             sub _new_server {
2839 2     2   6 my $class = shift;
2840 2         4 my %para = @_;
2841 2         4 my $sock;
2842             my $key;
2843 2         4 my $self = {};
2844 2 50       8 if (!$para{port}) {
2845 0         0 $@ = "Invalid port";
2846 0         0 return undef;
2847             }
2848 2         26 $sock = new IO::Socket::INET(
2849             LocalPort => $para{port},
2850             Proto => 'tcp',
2851             Listen => SOMAXCONN,
2852             Reuse => 1,
2853             );
2854 2 50       27204 if (!$sock) {
2855 0         0 $@ = "Could not create listening socket on port $para{port}: $!";
2856 0         0 return undef;
2857             }
2858 2         10 $sock->autoflush(1);
2859 2         60 $self->{_sock} = $sock;
2860 2         16 $self->{_selector} = new IO::Select;
2861 2         26 $self->{_selector}->add($sock);
2862 2         78 $self->{_mode} = "server";
2863 2         6 $self->{_welcome} = $para{welcome};
2864 2         50 $self->{_password} = $para{password};
2865 2 50       10 $self->{_donotcompress} = ($para{donotcompress}) ? 1 : 0;
2866 2 50       6 $self->{_donotencrypt} = ($para{donotencrypt}) ? 1 : 0;
2867 2         6 $self->{_clients} = {};
2868 2         4 $self->{_clientip} = {};
2869              
2870             #
2871             # Populate donotcompresswith with the keys of the supplied module names
2872             #
2873 2         4 $self->{_donotcompresswith} = {};
2874 2 50       8 if (ref($para{donotcompresswith}) ne "ARRAY") {
2875 2         4 $para{donotcompresswith} = [ $para{donotcompresswith} ];
2876             }
2877 2         8 foreach $key (keys %_COMPRESS_AVAILABLE) {
2878 4 50 66     12 if ($key ne "_order" && grep { $_COMPRESS_AVAILABLE{$key}{name} eq $_ } @{ $para{donotcompresswith} }) {
  2         16  
  2         6  
2879 0         0 $self->{_donotcompresswith}{$key} = 1;
2880             }
2881             }
2882              
2883             #
2884             # Populate donotencryptwith with the keys of the supplied module names
2885             #
2886 2         4 $self->{_donotencryptwith} = {};
2887 2 50       8 if (ref($para{donotencryptwith}) ne "ARRAY") {
2888 2         4 $para{donotencryptwith} = [ $para{donotencryptwith} ];
2889             }
2890 2         6 foreach $key (keys %_ENCRYPT_AVAILABLE) {
2891 2 50 33     8 if ($key ne "_order" && grep { $_ENCRYPT_AVAILABLE{$key}{name} eq $_ } @{ $para{donotencryptwith} }) {
  0         0  
  0         0  
2892 0         0 $self->{_donotencryptwith}{$key} = 1;
2893             }
2894             }
2895              
2896             #
2897             # To avoid key-gen delays while running, let's create global RSA keypairs right now
2898             #
2899 2 50 33     12 if (!$self->{_donotencrypt} && !$self->{_donotencryptwith}{'B'}) {
2900 2 50       6 if (!_generateglobalkeypair('Crypt::RSA')) {
2901 0         0 $@ = "Could not generate global Crypt::RSA keypairs. $@";
2902 0         0 return undef;
2903             }
2904             }
2905              
2906 2         6 bless($self, $class);
2907 2         12 return $self;
2908             }
2909              
2910             #
2911             # This takes a client object and tries to extract as many data buckets as possible out of it's data buffer
2912             # If no buckets were extracted, returns false
2913             # Otherwise returns true
2914             #
2915             sub _extractdata {
2916 56     56   70 my $client = shift;
2917 56         62 my ($alwayson, $complexstructure, $realdata, $reserved, $encrypted, $compressed, $lenlen);
2918 0         0 my $lendata;
2919 0         0 my $len;
2920 0         0 my $data;
2921 56 50       162 my $key = (defined $client->{_databuffer}) ? substr($client->{_databuffer}, 0, 2) : '';
2922 56 100       133 if (length($key) != 2) {
2923 34         65 return undef;
2924             }
2925 22         38 $alwayson = vec($key, 0, 1);
2926 22         31 $complexstructure = vec($key, 1, 1);
2927 22         28 $realdata = vec($key, 2, 1);
2928 22         31 $encrypted = vec($key, 3, 1);
2929 22         30 $compressed = vec($key, 4, 1);
2930 22         31 $reserved = vec($key, 5, 1);
2931 22         32 $reserved = vec($key, 6, 1);
2932 22         122 $reserved = vec($key, 7, 1);
2933 22         29 $lenlen = vec($key, 1, 8);
2934              
2935 22 50       119 if (!$alwayson) {
2936 0         0 return undef;
2937             }
2938 22         51 $len = substr($client->{_databuffer}, 2, $lenlen);
2939 22         57 $lendata = _unpackint($len);
2940 22 50       68 if (length($client->{_databuffer}) < (2 + $lenlen + $lendata)) {
2941 0         0 return undef;
2942             }
2943 22         74 $data = substr($client->{_databuffer}, 2 + $lenlen, $lendata);
2944 22 50       50 if (length($data) != $lendata) {
2945 0         0 return undef;
2946             }
2947 22         81 substr($client->{_databuffer}, 0, 2 + $lenlen + $lendata) = '';
2948 22 50       53 if ($encrypted) {
2949 0 0       0 _decrypt($client, \$data) || return undef;
2950             }
2951 22 100       55 if ($compressed) {
2952 6 50       25 _decompress($client, \$data) || return undef;
2953             }
2954 22 100       44 if ($complexstructure) {
2955 1         9 $data = thaw($data);
2956 1 50       37 if (!$data) {
2957 0         0 $@ = "Error decompressing complex structure: $!";
2958 0         0 return undef;
2959             }
2960             }
2961              
2962             #
2963             # We extracted it fine from the buffer, we add it in the data buckets
2964             #
2965             push(
2966 22         51 @{ $client->{_databucket} },
  22         115  
2967             {
2968             data => $data,
2969             realdata => $realdata,
2970             }
2971             );
2972              
2973             #
2974             # Let's push our luck and see if we can extract more :)
2975             #
2976 22         141 _extractdata($client);
2977              
2978             #
2979             # All is good, we know we extracted at least 1 bucket
2980             #
2981 22         64 return (1);
2982             }
2983              
2984             #
2985             # This takes a client object and data, serializes the data if necesary, constructs a proprietary protocol packet
2986             # containing the user's data in it, implements crypto and compression as needed, and sends the packet to the supplied socket
2987             # Returns 1 for success, undef on failure
2988             #
2989             sub _send {
2990 22     22   3303 local $SIG{'PIPE'} = 'IGNORE';
2991 22         35 my $client = shift;
2992 22         79 my $data = shift;
2993 22         28 my $realdata = shift;
2994 22         38 my $sock = $client->{_sock};
2995 22         30 my $encrypted;
2996             my $compressed;
2997 0         0 my $lendata;
2998 0         0 my $lenlen;
2999 0         0 my $len;
3000 0         0 my $key;
3001 0         0 my $finaldata;
3002 0         0 my $packet;
3003 0         0 my $temp;
3004 0         0 my $bytes_written;
3005 22         38 my $complexstructure = ref($data);
3006              
3007 22 50       80 if (!$sock) {
    50          
3008 0         0 $@ = "Error sending data: Socket handle not supplied";
3009 0         0 return undef;
3010             }
3011             elsif (!defined $data) {
3012 0         0 $@ = "Error sending data: Data not supplied";
3013 0         0 return undef;
3014             }
3015 22 100       47 if ($complexstructure) {
3016 1         8 $data = nfreeze $data;
3017             }
3018 22 50       167 $compressed = ($client->{_donotcompress}) ? 0 : _compress($client, \$data);
3019 22 50       125 $encrypted = ($client->{_donotencrypt}) ? 0 : _encrypt($client, \$data);
3020 22         33 $lendata = length($data);
3021 22         50 $len = _packint($lendata);
3022 22         38 $lenlen = length($len);
3023              
3024             # Reset the key byte into 0-filled bits
3025 22         31 $key = chr(0) x 2;
3026 22         1044 vec($key, 0, 16) = 0;
3027              
3028             # 1 BIT: ALWAYSON :
3029 22         84 vec($key, 0, 1) = 1;
3030              
3031             # 1 BIT: COMPLEXSTRUCTURE :
3032 22 100       65 vec($key, 1, 1) = ($complexstructure) ? 1 : 0;
3033              
3034             # 1 BIT: REAL DATA:
3035 22 100 66     138 vec($key, 2, 1) = (defined $realdata && !$realdata) ? 0 : 1;
3036              
3037             # 1 BIT: ENCRYPTED :
3038 22 50       69 vec($key, 3, 1) = ($encrypted) ? 1 : 0;
3039              
3040             # 1 BIT: COMPRESSED :
3041 22 100       52 vec($key, 4, 1) = ($compressed) ? 1 : 0;
3042              
3043             # 1 BIT: RESERVED :
3044 22         49 vec($key, 5, 1) = 0;
3045              
3046             # 1 BIT: RESERVED :
3047 22         36 vec($key, 6, 1) = 0;
3048              
3049             # 1 BIT: RESERVED :
3050 22         38 vec($key, 7, 1) = 0;
3051              
3052             # 8 BITS: LENGTH OF "DATA LENGTH STRING"
3053 22         42 vec($key, 1, 8) = $lenlen;
3054              
3055             # Construct the final data and send it:
3056 22         73 $finaldata = $key . $len . $data;
3057 22         29 $len = length($finaldata);
3058 22         26 $temp = 0;
3059 22         66 while (length($finaldata)) {
3060 22         44 $packet = substr($finaldata, 0, $PACKETSIZE);
3061 22         39 substr($finaldata, 0, $PACKETSIZE) = '';
3062 22         1421 $bytes_written = syswrite($sock, $packet, length($packet));
3063 22 50       68 if (!defined $bytes_written) {
3064 0         0 $@ = "Error writing to socket while sending data: $!";
3065 0         0 return undef;
3066             }
3067 22         59 $temp += $bytes_written;
3068             }
3069 22 50       49 if ($temp != $len) {
3070 0         0 $@ = "Error sending data: $!";
3071 0         0 return undef;
3072             }
3073             else {
3074 22         349 return 1;
3075             }
3076             }
3077              
3078             #
3079             # Leave me alone:
3080             #
3081             1;