DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 

(heimdal.info) Walkthru a sample Kerberos 5 client

Info Catalog (heimdal.info) Kerberos 5 API Overview (heimdal.info) Programming with Kerberos (heimdal.info) Validating a password in a server application
 
 Walkthru a sample Kerberos 5 client
 ===================================
 
 This example contains parts of a sample TCP Kerberos 5 clients, if you
 want a real working client, please look in `appl/test' directory in the
 Heimdal distribution.
 
 All Kerberos error-codes that are returned from kerberos functions in
 this program are passed to `krb5_err', that will print a descriptive
 text of the error code and exit. Graphical programs can convert
 error-code to a humal readable error-string with the
 `krb5_get_err_text(3)' function.
 
 Note that you should not use any Kerberos function before
 `krb5_init_context()' have completed successfully. That is the reson
 `err()' is used when `krb5_init_context()' fails.
 
 First the client needs to call `krb5_init_context' to initialize the
 Kerberos 5 library. This is only needed once per thread in the program.
 If the function returns a non-zero value it indicates that either the
 Kerberos implemtation is failing or its disabled on this host.
 
      #include <krb5.h>
      
      int
      main(int argc, char **argv)
      {
              krb5_context context;
      
              if (krb5_context(&context))
                      errx (1, "krb5_context");
 
 Now the client wants to connect to the host at the other end. The
 preferred way of doing this is using `getaddrinfo(3)' (for operating
 system that have this function implemented), since getaddrinfo is
 neutral to the address type and can use any protocol that is available.
 
              struct addrinfo *ai, *a;
              struct addrinfo hints;
              int error;
      
              memset (&hints, 0, sizeof(hints));
              hints.ai_socktype = SOCK_STREAM;
              hints.ai_protocol = IPPROTO_TCP;
      
              error = getaddrinfo (hostname, "pop3", &hints, &ai);
              if (error)
                      errx (1, "%s: %s", hostname, gai_strerror(error));
      
              for (a = ai; a != NULL; a = a->ai_next) {
                      int s;
      
                      s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
                      if (s < 0)
                              continue;
                      if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
                              warn ("connect(%s)", hostname);
                                  close (s);
                                  continue;
                      }
                      freeaddrinfo (ai);
                      ai = NULL;
              }
              if (ai) {
                          freeaddrinfo (ai);
                          errx ("failed to contact %s", hostname);
              }
 
 Before authenticating, an authentication context needs to be created.
 This context keeps all information for one (to be) authenticated
 connection (see `krb5_auth_context(3)').
 
              status = krb5_auth_con_init (context, &auth_context);
              if (status)
                      krb5_err (context, 1, status, "krb5_auth_con_init");
 
 For setting the address in the authentication there is a help function
 `krb5_auth_con_setaddrs_from_fd' that does everthing that is needed
 when given a connected file descriptor to the socket.
 
              status = krb5_auth_con_setaddrs_from_fd (context,
                                                       auth_context,
                                                       &sock);
              if (status)
                      krb5_err (context, 1, status,
                                "krb5_auth_con_setaddrs_from_fd");
 
 The next step is to build a server principal for the service we want to
 connect to. (See also `krb5_sname_to_principal(3)'.)
 
              status = krb5_sname_to_principal (context,
                                                hostname,
                                                service,
                                                KRB5_NT_SRV_HST,
                                                &server);
              if (status)
                      krb5_err (context, 1, status, "krb5_sname_to_principal");
 
 The client principal is not passed to `krb5_sendauth(3)' function, this
 causes the `krb5_sendauth' function to try to figure it out itself.
 
 The server program is using the function `krb5_recvauth(3)' to receive
 the Kerberos 5 authenticator.
 
 In this case, mutual authenication will be tried. That means that the
 server will authenticate to the client. Using mutual authenication is
 good since it enables the user to verify that they are talking to the
 right server (a server that knows the key).
 
 If you are using a non-blocking socket you will need to do all work of
 `krb5_sendauth' yourself. Basically you need to send over the
 authenticator from `krb5_mk_req(3)' and, in case of mutual
 authentication, verifying the result from the server with
 `krb5_rd_rep(3)'.
 
              status = krb5_sendauth (context,
                                      &auth_context,
                                      &sock,
                                      VERSION,
                                      NULL,
                                      server,
                                      AP_OPTS_MUTUAL_REQUIRED,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL);
              if (status)
                      krb5_err (context, 1, status, "krb5_sendauth");
 
 Once authentication has been performed, it is time to send some data.
 First we create a krb5_data structure, then we sign it with
 `krb5_mk_safe(3)' using the `auth_context' that contains the
 session-key that was exchanged in the
 `krb5_sendauth(3)'/`krb5_recvauth(3)' authentication sequence.
 
              data.data   = "hej";
              data.length = 3;
      
              krb5_data_zero (&packet);
      
              status = krb5_mk_safe (context,
                                     auth_context,
                                     &data,
                                     &packet,
                                     NULL);
              if (status)
                      krb5_err (context, 1, status, "krb5_mk_safe");
 
 And send it over the network.
 
              len = packet.length;
              net_len = htonl(len);
      
              if (krb5_net_write (context, &sock, &net_len, 4) != 4)
                      err (1, "krb5_net_write");
              if (krb5_net_write (context, &sock, packet.data, len) != len)
                      err (1, "krb5_net_write");
 
 To send encrypted (and signed) data `krb5_mk_priv(3)' should be used
 instead. `krb5_mk_priv(3)' works the same way as `krb5_mk_safe(3)',
 with the exception that it encrypts the data in addition to signing it.
 
              data.data   = "hemligt";
              data.length = 7;
      
              krb5_data_free (&packet);
      
              status = krb5_mk_priv (context,
                                     auth_context,
                                     &data,
                                     &packet,
                                     NULL);
              if (status)
                      krb5_err (context, 1, status, "krb5_mk_priv");
 
 And send it over the network.
 
              len = packet.length;
              net_len = htonl(len);
      
              if (krb5_net_write (context, &sock, &net_len, 4) != 4)
                      err (1, "krb5_net_write");
              if (krb5_net_write (context, &sock, packet.data, len) != len)
                      err (1, "krb5_net_write");
 
 The server is using `krb5_rd_safe(3)' and `krb5_rd_priv(3)' to verify
 the signature and decrypt the packet.
 
Info Catalog (heimdal.info) Kerberos 5 API Overview (heimdal.info) Programming with Kerberos (heimdal.info) Validating a password in a server application
automatically generated byinfo2html