root/examples/gss-client.pl

Revision 2, 4.8 kB (checked in by jroth2, 2 years ago)

intial import of gssapi examples

  • Property svn:executable set to
Line 
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use lib "/afs/acm.uiuc.edu/user/cclausen/perl/lib/perl/5.8.7";
7
8 use Getopt::Long;
9 use IO::Socket::INET;
10 use MIME::Base64;
11 use GSSAPI;
12
13 my %opt;
14
15 unless(GetOptions(\%opt, qw(prodid=s hostname=s port=s mutual))) {
16   print "$0 needs arguments, provide at least -prodid and -hostname, optionally -port (defauly 10000) or -mutual (for two sided authentication)\n";
17   exit(1);
18 }
19
20 if(! $opt{hostname}) {
21   die "$0: must specify -hostname\n";
22 }
23
24 if(! $opt{prodid}) {
25   die "$0: must specify -prodid\n";
26 }
27
28 if(! $opt{port}) {
29   warn "$0: -port not specified, defaulting to 10000\n";
30   $opt{port} = 10000;
31 }
32
33 if(! $opt{prodid}) {
34   $opt{prodid} = "host";
35 }
36
37 warn "$0: using [$opt{prodid}\@$opt{hostname}:$opt{port}]\n";
38
39
40 #
41 # GSSAPI::Name->import produces $gss_server_name
42 # which is then passed in to GSSAPI::Context::init
43 # $gss_server_name represents the principcal name
44 # of the app server to which we are authenticating
45 #
46
47 my $server_name = "$opt{prodid}\@$opt{hostname}";
48 my $status = GSSAPI::Name->import(my $gss_server_name, $server_name, gss_nt_service_name);
49 $status || gss_exit("CLIENT::Unable to import server name: $server_name", $status);
50
51 $status = $gss_server_name->display(my $display_name, my $type);
52 print "CLIENT::principal [$server_name] means going to communicate with server name [$display_name]\n";
53
54 my $gss_input_token = GSS_C_NO_BUFFER;
55
56 my $socket = IO::Socket::INET->new
57   (
58    PeerAddr                 => $opt{hostname},
59    PeerPort                 => $opt{port},
60    Proto                    => 'tcp',
61    Type                     => SOCK_STREAM,
62   );
63
64 die "socket/connect: $!\n" unless ($socket);
65
66 #
67 # The main purpose of GSSAPI::Context::init is to produce
68 # an authentication token ($gss_output_token) which will
69 # be sent by the app client to app server. Note the output
70 # is binary data.
71 #
72
73 my $gss_auth_flags;
74 if($opt{mutual}) {
75   $gss_auth_flags = GSS_C_MUTUAL_FLAG;
76 } else {
77   $gss_auth_flags = 0;
78 }
79
80 my $client_context;
81
82 my $counter = 0;
83 my $error = 0;
84
85 do {
86     $counter++;
87     my $gss_output_token;
88
89     $status = GSSAPI::Context::init($client_context,           # output context
90                                     GSS_C_NO_CREDENTIAL,
91                                     $gss_server_name,          # authenticate to this name
92                                     GSS_C_NO_OID,              # use default mechanism (krb5)
93                                     $gss_auth_flags,           # input flags
94                                     0,                         # input time
95                                     GSS_C_NO_CHANNEL_BINDINGS, # no channel binding
96                                     $gss_input_token,          # input token
97                                     my $out_mech,
98                                     $gss_output_token,
99                                     my $out_flags,
100                                     my $out_time);
101
102     $status || gss_exit("CLIENT::Unable to initialize security context", $status);
103
104     print "CLIENT::gss_init_sec_context success\n";
105
106     # The GSS protocol can do mutual authentication. If this is requested, the token
107     # that we generate in the first pass will indicate this to the server. The major
108     # status will have the GSS_S_CONTINUE_NEEDED bit set to indicate that we are
109     # expecting a reply with a server identity token. This loop will continue until
110     # that bit is no longer set. It should go through only once (non-mutual) or twice
111     # (mutual).
112
113     if ($counter == 1) {
114         print "CLIENT::going to identify client to server\n";
115     } elsif ($counter == 2) {
116         print "CLIENT::confirmed server identity from mutual token\n";
117         $gss_server_name->display(my $server_name, my $type);
118         print "CLIENT::authenticated server name is $server_name\n" if $server_name;
119
120     } else {
121         print "CLIENT::iteration [$counter] successful, but should not be here\n";
122     }
123
124     if($gss_output_token) {
125         print "CLIENT::have token to send ...\n";
126         print "CLIENT::GSS token length is " . length($gss_output_token) . "\n";
127
128         #
129         # $gss_output_token is binary data
130         #
131
132         print $socket encode_base64($gss_output_token, '') . "\n";
133         print "CLIENT::sent token to server\n";
134     }
135
136     if ($status->major & GSS_S_CONTINUE_NEEDED) {
137         print "CLIENT::Mutual auth requested ...\n";
138         $gss_input_token = <$socket>;
139         if ($gss_input_token) {
140             print "CLIENT::got mutual auth token from server\n";
141             $gss_input_token = decode_base64($gss_input_token);
142             print "CLIENT::mutual auth token length is " . length($gss_input_token) . "\n";
143         } else {
144             print "CLIENT::server did not send needed continue token back\n";
145             $error = 1;
146         }
147     }
148 } while (!$error and $status->major & GSS_S_CONTINUE_NEEDED);
149
150 $socket->shutdown(2);
151
152 exit(0);
153
154 ################################################################################
155
156 sub gss_exit {
157   my $errmsg = shift;
158   my $status = shift;
159
160   my @major_errors = $status->generic_message();
161   my @minor_errors = $status->specific_message();
162  
163   print STDERR "$errmsg:\n";
164   foreach my $s (@major_errors) {
165     print STDERR "  MAJOR::$s\n";
166   }
167   foreach my $s (@minor_errors) {
168     print STDERR "  MINOR::$s\n";
169   }
170   exit(1);
171 }
Note: See TracBrowser for help on using the browser.