]> arthur.barton.de Git - netatalk.git/commitdiff
deliver asip-status.pl with netatalk
authorbfernhomberg <bfernhomberg>
Wed, 9 Jun 2004 01:43:08 +0000 (01:43 +0000)
committerbfernhomberg <bfernhomberg>
Wed, 9 Jun 2004 01:43:08 +0000 (01:43 +0000)
configure.in
contrib/shell_utils/.cvsignore
contrib/shell_utils/Makefile.am
contrib/shell_utils/asip-status.pl.in [new file with mode: 0755]

index b79e630fab4e8d759102fa4f4b9b75b23839bc4d..9c220e2651defa27b428a7d398c23b2900fdd7d5 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.179.2.3.2.29 2004-06-09 01:25:52 bfernhomberg Exp $
+dnl $Id: configure.in,v 1.179.2.3.2.30 2004-06-09 01:43:08 bfernhomberg Exp $
 dnl configure.in for netatalk
 
 AC_INIT(etc/afpd/main.c)
@@ -1023,6 +1023,7 @@ AC_OUTPUT([Makefile
        contrib/shell_utils/apple_cp
        contrib/shell_utils/apple_mv
        contrib/shell_utils/apple_rm
+       contrib/shell_utils/asip-status.pl
        contrib/shell_utils/cleanappledouble.pl
        contrib/shell_utils/netatalkshorternamelinks.pl
        contrib/timelord/Makefile
index 0a7b3665b69293fcaf1fc0bfe82687a8f7017d28..0d52d6241bcf6532d3737e3f9a66037bc3937592 100644 (file)
@@ -7,3 +7,4 @@ apple_rm
 cleanappledouble.pl
 netatalkshorternamelinks.pl
 lp2pap.sh
+asip-status.pl
index 8d363b9f19ba4f6ff04b9a33b34c3a4732d300d1..3d1a4c885e850c014e0a061c3160e570cef47811 100644 (file)
@@ -8,7 +8,8 @@ PERLSCRIPTS = \
        afpd-mtab.pl                    \
        apple_cp apple_mv apple_rm      \
        cleanappledouble.pl             \
-       netatalkshorternamelinks.pl
+       netatalkshorternamelinks.pl     \
+       asip-status.pl
 
 SUFFIXES = .tmpl .
 
diff --git a/contrib/shell_utils/asip-status.pl.in b/contrib/shell_utils/asip-status.pl.in
new file mode 100755 (executable)
index 0000000..b9cef9b
--- /dev/null
@@ -0,0 +1,521 @@
+#!@PERL@
+#
+# asip-status - send DSIGetStatus to an AppleShare IP file server (aka
+#               ASIP, aka AFP over TCP port 548).  A returned UAM of 
+#               "No User Authen" means that the server supports guest access.
+#
+# author: James W. Abendschan  <jwa@jammed.com>
+# license: GPL - http://www.gnu.org/copyleft/gpl.html
+# url: http://www.jammed.com/~jwa/hacks/security/asip/
+# date: 7 May 1997 (v1.0)
+# see also: 
+#   - http://developer.apple.com/techpubs/macos8/NetworkCommSvcs/AppleShare/
+#   - http://www2.opendoor.com/asip/   (excellent Mac sharing / security site)
+#
+# todo: log in as guest & get a list of shares
+#
+# $Id: asip-status.pl.in,v 1.1.2.1 2004-06-09 01:43:09 bfernhomberg Exp $
+#
+
+use strict;
+use IO::Socket;                        # sucks because Timeout doesn't
+
+my ($arg);
+my ($host);
+
+while ($arg = shift @ARGV)
+{
+       $main::show_icon = 1 if ($arg eq "-i");
+       $main::debug = 1 if ($arg eq "-d");
+       $main::hexdump = 1 if ($arg eq "-x");
+       $host = $arg if ($arg !~ /^-/);
+}
+
+if ($host eq "")
+{
+       print "usage: $0 hostname [-i show icon] [-d debug] [-x hex dump]\n";
+       exit(-1);
+}
+
+my ($packet) = build_packet();
+my ($code) = sendpacket($host, 548, $packet);
+exit $code;
+
+
+sub build_packet 
+{
+       my (@packet) = 
+               (
+               0x00,                   # 0- request, 1-reply
+               0x03,                   # 3- DSIGetStatus
+               0xde, 0xad, 0x00,       # request ID
+               0x00, 0x00, 0x00, 0x00, # data field
+               0x00, 0x00, 0x00, 0x00, # length of data stream header
+               0x00, 0x00, 0x00, 0x00  # reserved
+               );
+
+
+        my ($packet) = pack("C*", @packet);
+
+       return $packet;
+
+}
+
+sub sendpacket 
+{
+       my ($host, $port, $packet) = @_;
+       my ($b, $buf);
+
+       print "opening $host:$port\n" if ($main::debug);
+
+       my ($asip_sock) = IO::Socket::INET->new( 
+               PeerAddr => $host, 
+               PeerPort => $port, 
+               Proto => 'tcp', 
+               Type => SOCK_STREAM, 
+               Timeout => 10
+               ) || die "connect to $host failure: $!"; 
+       $asip_sock->autoflush(1);
+
+       print "sending packet\n" if ($main::debug);
+
+       my ($count) = syswrite($asip_sock, $packet, length($packet));
+
+       if ($count != length($packet))
+       {
+               print "only wrote $count of " . length($packet) . " bytes?\n";
+               exit(-1);
+       }
+
+       # reply can span multiple packets
+
+       print "sysread: " if ($main::debug);
+       while (sysread($asip_sock, $b, 256))
+       {
+               $buf .= $b;
+               print "." if ($main::debug);
+       }       
+
+       close ($asip_sock);
+
+       print " read " . length($buf) . " bytes\n" if ($main::debug);
+
+       if (length($buf) == 0)
+       {
+               print "empty reply packet?\n";
+               return -2;
+       }
+       else
+       {
+               print "AFP reply from $host:$port\n";
+               return (parse_packet($buf));
+       }       
+}
+
+
+sub parse_packet 
+{
+       my ($buf) = shift @_;
+       my (@packet);
+       my ($i);
+
+       hexdump($buf) if ($main::hexdump);
+
+       for ($i=0;$i<length($buf);$i++)
+       {
+               push(@packet, substr($buf, $i, 1));
+       }       
+
+       my ($flags) = unpack("C", @packet[0]);
+       my ($cmd) = unpack("C", @packet[1]);
+
+       my ($request_id) = unpack("n", @packet[2] . @packet[3]);
+       print "Flags: $flags  Cmd: $cmd  ID: $request_id\n";
+
+       print getasipsrv("flags", $flags) . ": " . getasipsrv("command", $cmd) . "\n";
+       print "Request ID: $request_id\n";
+
+       print "** Request ID didn't match what we sent!\n" if ($request_id != 0xdead);
+
+       # "Error Code / Enclosed Data Offset"
+       # I have never seen this be non-zero ..
+
+       my ($edo) = unpack("N2", @packet[4] . @packet[5] . @packet[6] . @packet[7]);
+       print "** Wow, a non-zero Error/Enclosed Data Offset: $edo\n" if ($edo);
+
+       # "Total Data Length"
+
+       my ($datalen) = unpack("N2", @packet[8] . @packet[9] . @packet[10] . @packet[11]);
+
+       print "Total data length: $datalen\n" if ($main::debug);
+
+       # "Reserved Field"
+
+       my ($reserved) = unpack("N2", @packet[12] . @packet[13] . @packet[14] . @packet[15]);
+
+       print "Reserved field: $reserved\n" if ($reserved);
+
+       if ($cmd != 3)
+       {
+               print "I can only parse packets of reply-type DSIGetStatus (3)\n";
+               print "This is reply-type " . getasipsrv("command", $cmd) . "\n";
+       }
+       if ($datalen == 0)
+       {
+               print "No data in packet?\n";
+       }       
+       if (($datalen > 0) && ($cmd == 3)) 
+       {
+               my (@AFPpacket) = @packet[($edo+16)..($edo+16+$datalen)];
+               return (parse_FPGetSrvrInfo(@AFPpacket));
+       }
+       else
+       {
+               print "I don't know how to parse this type of packet.\n";
+               return(2);
+       }       
+}
+
+
+
+sub parse_FPGetSrvrInfo() 
+{
+       my (@packet) = @_;
+       my ($i);
+
+       my ($machinetype_offset) = unpack("n", @packet[0] . @packet[1]);
+       print "Machine type offset in packet: $machinetype_offset\n" if ($main::debug);
+       my ($machinetype) = extract(1, $machinetype_offset, @packet);
+       print "Machine type: $machinetype\n";
+
+       my ($afpversioncount_offset) = unpack("n", @packet[2] . @packet[3]);
+       print "AFPversion count offset: $afpversioncount_offset\n" if ($main::debug);
+       my (@afpversions) = extract(0, $afpversioncount_offset, @packet);
+       print "AFP versions: " . join(",", @afpversions) . "\n";
+
+       my ($uamcount_offset) = unpack("n", @packet[4] . @packet[5]);
+       print "UAMcount offset: $uamcount_offset\n" if ($main::debug);
+       my (@uams) = extract(0, $uamcount_offset, @packet);
+       print "UAMs: " . join(",", @uams) . "\n";
+
+       my ($allow_guest) = 0;
+       $allow_guest = 1 if (grep(/No User Authen/, @uams));
+
+       # it would be cute to see the icon.
+
+       my ($icon_offset) = unpack("n", @packet[6] . @packet[7]);
+       print "Volume Icon & Mask offset: $icon_offset\n" if ($main::debug);
+
+       my ($flags) = unpack("n", @packet[8] . @packet[9]);
+       my (@flags) = parse_afp_flags($flags);
+
+       print "Flags: ";
+       print "$flags - " if ($main::debug);
+       print join(",", @flags) . "\n";
+
+       # server name starts at offset+10, length byte first.
+
+       my ($servername_len) = unpack("C1", @packet[10]);
+       my ($servername) = join("", @packet[11..(11+$servername_len-1)]);
+       print "Server name length: $servername_len\n" if ($main::debug);
+       print "Server name: $servername\n";
+
+       my ($offset) = 11 + $servername_len;
+
+       # quietly ++ the $offset to account for the padding that happens
+       # in the reply packet if the field names don't align on an even boundary
+
+       $offset++ if ($servername_len % 2 == 0);
+
+       print "New offset: $offset\n" if ($main::debug);
+
+       my ($signature_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+       print "Signature offset: $signature_offset\n" if ($main::debug);
+       if ($signature_offset)
+       {
+                my ($signature) = join("",  @packet[$signature_offset..$signature_offset+15]);
+
+               print "Signature:\n";   
+               hexdump($signature);
+       }
+
+       my ($network_address_count_offset) = unpack("n2", @packet[$offset+2] . @packet[$offset+3]);
+       print "Network address count offset: $network_address_count_offset\n" if ($main::debug);
+
+       extract_network_address($network_address_count_offset, @packet);
+
+       $offset += 4;
+       if ($flags & (1<<8)) { # Supports directory services
+               my ($directory_service_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+               print "Directory service offset: $directory_service_offset\n" if ($main::debug);
+               if ($directory_service_offset)
+               {
+                       my (@dirsvcs) = extract(0, $directory_service_offset, @packet);
+                       while (@dirsvcs)
+                       {
+                               printf "Directory Service: %s\n", shift @dirsvcs;
+                       }
+               }
+               $offset +=2;
+       }
+
+       if ($flags & (1<<9)) { # Supports UTF8 servername
+               my ($utf8_name_offset) = unpack("n2", @packet[$offset] . @packet[$offset+1]);
+               print "UTF8 name offset: $utf8_name_offset\n" if ($main::debug);
+               if ($utf8_name_offset)
+               {
+                       my ($utf8name) = extract(1, $utf8_name_offset+1, @packet);
+                       print "UTF8 Servername: $utf8name\n";
+               }
+       }
+
+       draw_icon($icon_offset, @packet) if ($main::show_icon);
+
+       return $allow_guest;
+}
+
+# getsrvbyname .. sorta ..
+
+sub getasipsrv 
+{
+       my ($what, $code) = @_;
+
+       if ($what eq "flags") 
+       {
+               return "Request" if ($code == 0);
+               return "Reply" if ($code == 1); 
+       }
+
+       if ($what eq "command") 
+       {
+               return "DSICloseSession" if ($code == 1);
+               return "DSICommand" if ($code == 2);
+               return "DSIGetStatus" if ($code == 3);
+               return "DSIOpenSession" if ($code == 4);
+               return "DSITickle" if ($code == 5);
+               return "DSIWrite" if ($code == 6);
+               return "DSIAttention" if ($code == 7);
+       }
+       return "[$what/$code] unknown";
+}
+
+
+# return "counted" data at @packet[$offset]
+# when called with a zero as the first argument, this will
+# look in the packet for the count.  Otherwise, it will
+# assume I know what I'm doing.  (hah, what a foolish function..)
+
+sub extract 
+{
+       my ($count, $offset, @packet) = @_;
+       my ($i, $j);
+       my (@items, $data);
+       my ($hack);
+
+       if ($count == 0)
+       {
+               ($count) = unpack("C", @packet[$offset]);
+               return if ($count == 0);
+               $offset++;
+       }
+       else
+       {
+               $hack = 1;
+       }       
+       #print ">> extracting $count items from offset $offset\n";
+       for ($i=0;$i<$count;$i++)
+       {
+               #print "Working on count $i\n";
+               my ($len) = unpack("C1", @packet[$offset]);
+               $data = join("",  @packet[$offset+1..$offset+$len]);
+               #print "$i. [$data] ($len)\n";
+               push (@items, $data);
+               $offset = $offset + $len + 1;
+               #print "new offset is $offset\n";
+       }
+       return $data if ($hack);
+       return @items;
+}
+
+sub draw_icon
+{
+       my ($offset, @packet) = @_;
+       my ($cols);
+       my ($i, $j);
+
+       # icons are 32x32 bitmaps; 128 byte icon + 128 byte mask
+       # to show the mask, change 128 to 256.  
+
+       for ($i=0;$i<128;$i++)
+       {
+               my ($c) = @packet[$i+$offset];
+               my ($bin) = unpack ("B*", $c);
+
+               for ($j=0;$j<8;$j++)
+               {
+                       if (substr($bin, $j, 1))
+                       {
+                               print "#";
+                       }
+                       else
+                       {
+                               print " ";
+                       }
+               }       
+               $cols++;
+               if ($cols == 4)
+               {
+                       $cols = 0;
+                       print "\n";
+               }
+
+       }
+       print "\n";
+}
+
+
+sub parse_afp_flags
+{
+       my ($flags) = shift @_;
+       my (@flags);
+
+       # $flags is a 16 bit little-endian number
+
+       push (@flags, "SupportsCopyFile") if ($flags & (1<<0));
+       push (@flags, "SupportsChgPwd") if ($flags & (1<<1));
+       push (@flags, "DontAllowSavePwd") if ($flags & (1<<2));
+       push (@flags, "SupportsServerMessages") if ($flags & (1<<3));
+       push (@flags, "SupportsServerSignature") if ($flags & (1<<4));
+       push (@flags, "SupportsTCP/IP") if ($flags & (1<<5));
+       push (@flags, "SupportsSrvrNotifications") if ($flags & (1<<6));
+       push (@flags, "SupportsReconnect") if ($flags & (1<<7));
+       push (@flags, "SupportsOpenDirectory") if ($flags & (1<<8));
+       push (@flags, "SupportsUTF8Servername") if ($flags & (1<<9));
+       push (@flags, "SupportsSuperClient") if ($flags & (1<<15));
+
+       return @flags;
+}
+
+
+sub hexdump
+{
+       my ($buf) = @_;
+       my ($p, $c, $pc, $str);
+       my ($i);
+
+       for ($i=0;$i<length($buf);$i++)
+       {
+               $p = substr($buf, $i, 1);
+               $c = ord ($p);
+               printf "%.2x ", $c;
+               $pc++;
+               if (($c > 31) && ($c < 127))
+               {
+                       $str .= $p;
+               }
+               else
+               {
+                       $str .= ".";
+               }       
+               if ($pc == 16)
+               {
+                       print " $str\n";
+                       undef $str;
+                       $pc = 0;
+               }       
+       }
+       print "   " x (16 - $pc);
+       print " $str \n";
+}
+
+
+sub extract_network_address
+{
+       my ($offset, @packet) = @_;
+       my ($count);
+       my ($i) = 0;
+       my ($data);
+
+       # get the number of addresses
+        ($count) = unpack("C", @packet[$offset]);
+        return if ($count == 0);
+        $offset++;
+
+        #print "\n>> extracting $count items from offset $offset\n";
+        for ($i=0;$i<$count;$i++)
+        {
+                #print "Working on count $i\n";
+                my ($len) = unpack("C1", @packet[$offset]);
+               #printf "len:  %u\n",$len;
+               my ($type) = unpack("C1", @packet[$offset+1]);
+               #printf "type: %u\n",$type;
+                $data = join("",  @packet[$offset+2..$offset+$len-1]);
+                #print "$i. [$data] ($len)\n";
+                $offset = $offset + $len ;
+                #print "new offset is $offset\n";
+
+
+               # 1st byte is 'tag'
+               # 1 - IP address; 4 bytes
+               # 2 - IP address (4) + port (2)
+               # 3 - DDP (2 bytes net, 1 byte node, 1 byte socket)
+               # 4 - DNS address
+               # 5 - IP address (4) + port (2), for SSH tunnel
+               # 6 - IPV6 address (16)
+               # 7 - IPV6 address (16) + port (2)
+
+               my (@nap) = unpack("C*", $data);
+
+               if ($type == 1)
+               {
+                       # quad
+                       my ($ip) = sprintf "%d.%d.%d.%d (TCP/IP address)",
+                               $nap[0], $nap[1], @nap[2], @nap[3];
+       
+                       print "Network address: $ip\n";
+               }
+               elsif ($type == 2)
+               {
+                       # quad+port
+                       my ($ipport) = sprintf "%d.%d.%d.%d:%d",
+                               @nap[0], @nap[1], @nap[2], @nap[3], (@nap[4]*256 + @nap[5]);
+                       print "Network address: $ipport (TCP/IP address and port)\n";
+               }
+               elsif ($type == 3)
+               {
+                       printf "Network address: %d.%d (ddp address)\n",
+                               (@nap[0] * 256) + @nap[1], @nap[2];
+               }
+               elsif ($type == 4)
+               {
+                       print "Network address: $data (DNS address)\n";
+               }
+               elsif ($type == 5)
+               {
+                       # according to the specs this should be an IP address
+                       # however, OSX Server uses the FQDN instead
+                       print "Network address: $data (SSH tunnel address)\n";
+               }
+               elsif ($type == 6 || $type == 7)
+               {
+                       print "Network address: ";
+                       my ($j) = 0;
+                       for ( $j = 0; $j<=13; $j = $j+2) {
+                               printf("%.2x%.2x:", @nap[$j], @nap[$j+1]);
+                       }
+                       printf("%.2x%.2x", @nap[14], @nap[15]);
+                       if ($type == 7 ) {
+                               printf(":%d", (@nap[16]*256) + @nap[17]);
+                               print " (IPv6 address + port)\n";
+                       }
+                       else {
+                               print " (IPv6 address)\n";
+                       }
+               }
+               else 
+               {
+                       printf "unsupported address type: %u\n", $type;
+               }
+
+        }
+}