コード例 #1
0
ファイル: client-safe.c プロジェクト: dmr0605/Kerberos
int
main (int argc, char *argv[])
{
  Shishi *h;
  Shishi_ap *ap;
  char *sname;
  int rc;

  printf ("sample-client (shishi " SHISHI_VERSION ")\n");

  if (!shishi_check_version (SHISHI_VERSION))
    {
      printf ("shishi_check_version() failed:\n"
	      "Header file incompatible with shared library.\n");
      return 1;
    }

  rc = shishi_init (&h);
  if (rc != SHISHI_OK)
    {
      printf ("error initializing shishi: %s\n", shishi_strerror (rc));
      return 1;
    }

  if (argc > 1)
    sname = argv[1];
  else
    sname = shishi_server_for_local_service (h, SERVICE);

  ap = auth (h, 1, shishi_principal_default (h), sname);

  if (ap)
    rc = doit (h, ap, 1);
  else
    rc = 1;

  shishi_done (h);

  return rc;
}
コード例 #2
0
ファイル: client.c プロジェクト: dezelin/maily
int
_gsasl_kerberos_v5_client_start (Gsasl_session * sctx, void **mech_data)
{
  struct _Gsasl_kerberos_v5_client_state *state;
  Gsasl_ctx *ctx;
  int err;

  state = malloc (sizeof (*state));
  if (state == NULL)
    return GSASL_MALLOC_ERROR;

  memset (state, 0, sizeof (*state));

  err = shishi_init (&state->sh);
  if (err)
    return GSASL_KERBEROS_V5_INIT_ERROR;

  state->step = 0;
  state->clientqop = GSASL_QOP_AUTH_INT;

  *mech_data = state;

  return GSASL_OK;
}
コード例 #3
0
ファイル: rsh.c プロジェクト: dmr0605/Kerberos
int
main (int argc, char **argv)
{
  char *user = NULL;
  char *luser = NULL;
  char *host = NULL;
  char *port = "shell";
  char *p;
  char lport[5];

  struct passwd *pw;

  int af = AF_UNSPEC;
  struct addrinfo hint, *ai, *aip, *lai;
  struct sockaddr raddr;
  int raddrlen;
  int err, sock = -1, lsock = -1, esock = -1, i;

  int opt;

  bool verbose = false;

  char hostaddr[NI_MAXHOST];
  char portnr[NI_MAXSERV];

  char buf[3][BUFLEN], *bufp[3];
  int len[3], wlen;

  fd_set infd, outfd, infdset, outfdset, errfd;
  int maxfd;

  int flags;

#ifdef SHISHI

  Shishi *h;
  Shishi_key *enckey = NULL, *deckey = NULL;
  int rc;
  char *sname = NULL;
  int shishi = 0;
  int encryption = 0;
  int auth2 = 0;
  char *cmd, *tcmd;
  int hostlen, cmdlen;
  struct hostent *hostdata;
  char *iv = NULL;
  char *iv2 = NULL;
  char *iv3 = NULL;
  int ivlen;
  int ivlen2;
  int ivlen3;

#endif

  argv0 = argv[0];

  /* Lookup local username */

  if (!(pw = getpwuid (getuid ())))
    {
      fprintf (stderr, "%s: Could not lookup username: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

  /* Process options */

#ifdef SHISHI
  while ((opt = getopt (argc, argv, "+l:p:46vsx")) != -1)
#else
  while ((opt = getopt (argc, argv, "+l:p:46v")) != -1)
#endif
    {

      switch (opt)
	{
	case 'l':
	  user = optarg;
	  break;
	case 'p':
	  port = optarg;
	  break;
	case '4':
	  af = AF_INET;
	  break;
	case '6':
	  af = AF_INET6;
	  break;
	case 'v':
	  verbose = true;
	  break;
#ifdef SHISHI
	case 's':
	  shishi = 1;
	  port = "544";
	  break;
	case 'x':
	  shishi = 1;
	  encryption = 1;
	  port = "544";
	  break;
#endif
	default:
	  fprintf (stderr, "%s: Unknown option!\n", argv0);
	  usage ();
	  return 1;
	}
    }

  if (optind == argc)
    {
      fprintf (stderr, "%s: No host specified!\n", argv0);
      usage ();
      return 1;
    }

#ifdef SHISHI

  if (!shishi)
    {
      luser = pw->pw_name;
      if (!user)
	user = luser;
    }
#endif

  host = argv[optind++];

  if ((p = strchr (host, '@')))
    {
      user = host;
      *p = '\0';
      host = p + 1;
    }

  /* Resolve hostname and try to make a connection */

  memset (&hint, '\0', sizeof (hint));
  hint.ai_family = af;
  hint.ai_socktype = SOCK_STREAM;

  err = getaddrinfo (host, port, &hint, &ai);

  if (err)
    {
      fprintf (stderr, "%s: Error looking up host: %s\n", argv0,
	       gai_strerror (err));
      return 1;
    }

  hint.ai_flags = AI_PASSIVE;

  for (aip = ai; aip; aip = aip->ai_next)
    {
      if (getnameinfo
	  (aip->ai_addr, aip->ai_addrlen, hostaddr, sizeof (hostaddr), portnr,
	   sizeof (portnr), NI_NUMERICHOST | NI_NUMERICSERV))
	{
	  fprintf (stderr, "%s: Error resolving address: %s\n", argv0,
		   strerror (errno));
	  return 1;
	}
      if (verbose)
	fprintf (stderr, "Trying %s port %s...", hostaddr, portnr);

      if ((sock =
	   socket (aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1)
	{
	  if (verbose)
	    fprintf (stderr, " Could not open socket: %s\n",
		     strerror (errno));
	  continue;
	}

      hint.ai_family = aip->ai_family;

      /* Bind to a privileged port */

      for (i = 1023; i >= 512; i--)
	{
	  snprintf (lport, sizeof (lport), "%d", i);
	  err = getaddrinfo (NULL, lport, &hint, &lai);
	  if (err)
	    {
	      fprintf (stderr, " Error looking up localhost: %s\n",
		       gai_strerror (err));
	      return 1;
	    }

	  err = bind (sock, lai->ai_addr, lai->ai_addrlen);

	  freeaddrinfo (lai);

	  if (err)
	    continue;
	  else
	    break;
	}

      if (err)
	{
	  if (verbose)
	    fprintf (stderr, " Could not bind to privileged port: %s\n",
		     strerror (errno));
	  continue;
	}

      if (connect (sock, aip->ai_addr, aip->ai_addrlen) == -1)
	{
	  if (verbose)
	    fprintf (stderr, " Connection failed: %s\n", strerror (errno));
	  continue;
	}
      if (verbose)
	fprintf (stderr, " Connected.\n");
      break;
    }

  if (!aip)
    {
      fprintf (stderr, "%s: Could not make a connection.\n", argv0);
      return 1;
    }

  /* Create a socket for the incoming connection for stderr output */

  if ((lsock =
       socket (aip->ai_family, aip->ai_socktype, aip->ai_protocol)) == -1)
    {
      fprintf (stderr, "%s: Could not open socket: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

  hint.ai_family = aip->ai_family;

  freeaddrinfo (ai);

  for (i--; i >= 512; i--)
    {
      snprintf (lport, sizeof (lport), "%d", i);
      err = getaddrinfo (NULL, lport, &hint, &lai);
      if (err)
	{
	  fprintf (stderr, "%s: Error looking up localhost: %s\n", argv0,
		   gai_strerror (err));
	  return 1;
	}

      err = bind (lsock, lai->ai_addr, lai->ai_addrlen);

      freeaddrinfo (lai);

      if (err)
	continue;
      else
	break;
    }

  if (err)
    {
      fprintf (stderr, "%s: Could not bind to privileged port: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

  if (listen (lsock, 1))
    {
      fprintf (stderr, "%s: Could not listen: %s\n", argv0, strerror (errno));
      return 1;
    }

  /* Drop privileges */

  if (setuid (getuid ()))
    {
      fprintf (stderr, "%s: Unable to drop privileges: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

  /* Send required information to the server */

  bufp[0] = buf[0];
  len[0] = sizeof (buf[0]);
#ifdef SHISHI

  if (shishi)
    {
      if (!shishi_check_version (SHISHI_VERSION))
	{
	  printf ("shishi_check_version() failed:\n"
		  "Header file incompatible with shared library.\n");
	  return 1;
	}

      rc = shishi_init (&h);
      if (rc != SHISHI_OK)
	{
	  printf ("error initializing shishi: %s\n", shishi_strerror (rc));
	  return 1;
	}

      hostdata = gethostbyname (host);
      hostlen = strlen (hostdata->h_name) + strlen (SERVICE) + 2;
      sname = malloc (hostlen);
      snprintf (sname, hostlen, "%s/%s", SERVICE, hostdata->h_name);

      rc = optind;
      cmdlen = BUFLEN;
      cmd = malloc (cmdlen);
      tcmd = cmd;

      if (encryption)
	safecpy (&tcmd, &cmdlen, "-x ", 0);

      for (; optind < argc; optind++)
	{
	  safecpy (&tcmd, &cmdlen, argv[optind], 0);
	  if (optind < argc - 1)
	    safecpy (&tcmd, &cmdlen, " ", 0);
	}

      safecpy (&tcmd, &cmdlen, "", 1);

      optind = rc;

      if (!user)
	user = (char *) shishi_principal_default (h);

      safewrite (sock, lport, strlen (lport) + 1);

      /* Wait for incoming connection from server */

      if ((esock = accept (lsock, &raddr, &raddrlen)) == -1)
	{
	  fprintf (stderr, "%s: Could not accept stderr connection: %s\n",
		   argv0, strerror (errno));
	  return 1;
	}

      close (lsock);

      if (auth (h, 0, user, sname, sock, cmd, port, &enckey, deckey) !=
	  AUTH_OK)
	return 1;

      free (cmd);

    }
  else
    {
      safecpy (&bufp[0], &len[0], lport, 1);
      safecpy (&bufp[0], &len[0], luser, 1);
    }

#else
  safecpy (&bufp[0], &len[0], lport, 1);
  safecpy (&bufp[0], &len[0], luser, 1);
#endif

  safecpy (&bufp[0], &len[0], user, 1);

#ifdef SHISHI
  if (encryption)
    safecpy (&bufp[0], &len[0], "-x ", 0);
#endif

  for (; optind < argc; optind++)
    {
      safecpy (&bufp[0], &len[0], argv[optind], 0);
      if (optind < argc - 1)
	safecpy (&bufp[0], &len[0], " ", 0);
    }

#ifdef SHISHI
  if (shishi)
    {
      safecpy (&bufp[0], &len[0], "", 1);
      safecpy (&bufp[0], &len[0], user, 1);
    }
  else
#endif

    safecpy (&bufp[0], &len[0], "", 1);

  if (!len[0])
    {
      fprintf (stderr, "%s: Arguments too long!\n", argv0);
      return 1;
    }

  if (safewrite (sock, buf[0], bufp[0] - buf[0]) == -1)
    {
      fprintf (stderr, "%s: Unable to send required information: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

#ifdef SHISHI

  if (shishi)
    {
      safewrite (sock, &auth2, sizeof (int));
    }
#endif

  /* Wait for acknowledgement from server */

  errno = 0;

  if (read (sock, buf[0], 1) != 1 || *buf[0])
    {
      fprintf (stderr, "%s: Didn't receive NULL byte from server: %s\n",
	       argv0, strerror (errno));
      return 1;
    }

#ifdef SHISHI

  if (encryption)
    {
      ivlen = ivlen2 = ivlen3 = shishi_key_length (enckey);
      iv = malloc (ivlen);
      memset (iv, 1, ivlen);
      iv2 = malloc (ivlen2);
      memset (iv2, 3, ivlen2);
      iv3 = malloc (ivlen3);
      memset (iv3, 0, ivlen3);
    }

  if (!shishi)
    {

      /* Wait for incoming connection from server */

      if ((esock = accept (lsock, &raddr, &raddrlen)) == -1)
	{
	  fprintf (stderr, "%s: Could not accept stderr connection: %s\n",
		   argv0, strerror (errno));
	  return 1;
	}

      close (lsock);
    }

#else

  /* Wait for incoming connection from server */

  if ((esock = accept (lsock, &raddr, &raddrlen)) == -1)
    {
      fprintf (stderr, "%s: Could not accept stderr connection: %s\n", argv0,
	       strerror (errno));
      return 1;
    }

  close (lsock);

#endif

  /* Process input/output */

  flags = fcntl (sock, F_GETFL);
  fcntl (sock, F_SETFL, flags | O_NONBLOCK);
  flags = fcntl (esock, F_GETFL);
  fcntl (esock, F_SETFL, flags | O_NONBLOCK);

  bufp[0] = buf[0];
  bufp[1] = buf[1];
  bufp[2] = buf[2];

  FD_ZERO (&infdset);
  FD_ZERO (&outfdset);
  FD_SET (0, &infdset);
  FD_SET (sock, &infdset);
  FD_SET (esock, &infdset);

  maxfd = (sock > esock ? sock : esock) + 1;

  for (;;)
    {
      errno = 0;
      infd = infdset;
      outfd = outfdset;
      errfd = infdset;

      if (select (maxfd, &infd, &outfd, &errfd, NULL) <= 0)
	{
	  if (errno == EINTR)
	    continue;
	  else
	    break;
	}


      if (FD_ISSET (esock, &infd))
	{
#ifdef SHISHI
	  if (encryption)
	    {
	      rc = readenc (h, esock, buf[2], &len[2], iv2, &ivlen2, enckey);
	      if (rc != SHISHI_OK)
		break;
	    }
	  else
#endif
	    len[2] = read (esock, buf[2], BUFLEN);
	  if (len[2] <= 0)
	    {
	      if (errno != EINTR)
		{
		  if (FD_ISSET (sock, &infdset) || FD_ISSET (1, &outfdset))
		    FD_CLR (esock, &infdset);
		  else
		    break;
		}
	    }
	  else
	    {
	      FD_SET (2, &outfdset);
	      FD_CLR (esock, &infdset);
	    }
	}

      if (FD_ISSET (2, &outfd))
	{
	  wlen = write (2, bufp[2], len[2]);
	  if (wlen <= 0)
	    {
	      if (errno != EINTR)
		{
		  if (FD_ISSET (sock, &infdset) || FD_ISSET (1, &outfdset))
		    FD_CLR (esock, &infdset);
		  else
		    break;
		}
	    }
	  else
	    {
	      len[2] -= wlen;
	      bufp[2] += wlen;
	      if (!len[2])
		{
		  FD_CLR (2, &outfdset);
		  FD_SET (esock, &infdset);
		  bufp[2] = buf[2];
		}
	    }
	}

      if (FD_ISSET (sock, &infd))
	{
#ifdef SHISHI
	  if (encryption)
	    {
	      rc = readenc (h, sock, buf[1], &len[1], iv, &ivlen, enckey);
	      if (rc != SHISHI_OK)
		break;
	    }
	  else
#endif
	    len[1] = read (sock, buf[1], BUFLEN);
	  if (len[1] <= 0)
	    {
	      if (errno != EINTR)
		{
		  if (FD_ISSET (esock, &infdset) || FD_ISSET (2, &outfdset))
		    FD_CLR (sock, &infdset);
		  else
		    break;
		}
	    }
	  else
	    {
	      FD_SET (1, &outfdset);
	      FD_CLR (sock, &infdset);
	    }
	}

      if (FD_ISSET (1, &outfd))
	{
	  wlen = write (1, bufp[1], len[1]);
	  if (wlen <= 0)
	    {
	      if (errno != EINTR)
		{
		  if (FD_ISSET (esock, &infdset) || FD_ISSET (2, &outfdset))
		    FD_CLR (sock, &infdset);
		  else
		    break;
		}
	    }
	  else
	    {
	      len[1] -= wlen;
	      bufp[1] += wlen;
	      if (!len[1])
		{
		  FD_CLR (1, &outfdset);
		  FD_SET (sock, &infdset);
		  bufp[1] = buf[1];
		}
	    }
	}

      if (FD_ISSET (0, &infd))
	{
	  len[0] = read (0, buf[0], BUFLEN);
	  if (len[0] <= 0)
	    {
	      if (errno != EINTR)
		{
		  FD_CLR (0, &infdset);
		  shutdown (sock, SHUT_WR);
		}
	    }
	  else
	    {
	      FD_SET (sock, &outfdset);
	      FD_CLR (0, &infdset);
	    }
	}

      if (FD_ISSET (sock, &outfd))
	{
#ifdef SHISHI
	  if (encryption)
	    {
	      rc =
		writeenc (h, sock, bufp[0], len[0], &wlen, iv3, &ivlen3,
			  enckey);
	      if (rc != SHISHI_OK)
		break;
	    }
	  else
#endif
	    wlen = write (sock, bufp[0], len[0]);
	  if (wlen <= 0)
	    {
	      if (errno != EINTR)
		break;
	    }
	  else
	    {
	      len[0] -= wlen;
	      bufp[0] += wlen;
	      if (!len[0])
		{
		  FD_CLR (sock, &outfdset);
		  FD_SET (0, &infdset);
		  bufp[0] = buf[0];
		}
	    }
	}


    }

  if (errno)
    {
      fprintf (stderr, "%s: %s\n", argv0, strerror (errno));
      return 1;
    }

  close (sock);
  close (esock);

#ifdef SHISHI

  if (shishi)
    {
      shishi_done (h);
      if (encryption)
	{
	  free (iv);
	  free (iv2);
	  free (iv3);
	}
    }

#endif

  return 0;
}
コード例 #4
0
ファイル: context.c プロジェクト: dezelin/maily
/* Initiates the establishment of a krb5 security context between the
   application and a remote peer.  Assumes that context_handle and
   output_token are valid and cleared. */
OM_uint32
gss_krb5_init_sec_context (OM_uint32 * minor_status,
                           const gss_cred_id_t initiator_cred_handle,
                           gss_ctx_id_t * context_handle,
                           const gss_name_t target_name,
                           const gss_OID mech_type,
                           OM_uint32 req_flags,
                           OM_uint32 time_req,
                           const gss_channel_bindings_t input_chan_bindings,
                           const gss_buffer_t input_token,
                           gss_OID * actual_mech_type,
                           gss_buffer_t output_token,
                           OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
    gss_ctx_id_t ctx = *context_handle;
    _gss_krb5_ctx_t k5 = ctx->krb5;
    OM_uint32 maj_stat;
    int rc;

    if (minor_status)
        *minor_status = 0;

    if (initiator_cred_handle)
    {
        /* We only support the default initiator.  See k5internal.h for
           adding a Shishi_tkt to the credential structure.  I'm not sure
           what the use would be -- user-to-user authentication perhaps?
           Later: if you have tickets for foo@BAR and bar@FOO, it may be
           useful to call gss_acquire_cred first to chose which one to
           initiate the context with.  Not many applications need this. */
        return GSS_S_NO_CRED;
    }

    if (k5 == NULL)
    {
        k5 = ctx->krb5 = calloc (sizeof (*k5), 1);
        if (!k5)
        {
            if (minor_status)
                *minor_status = ENOMEM;
            return GSS_S_FAILURE;
        }

        rc = shishi_init (&k5->sh);
        if (rc != SHISHI_OK)
            return GSS_S_FAILURE;
    }

    if (!k5->reqdone)
    {
        maj_stat = init_request (minor_status,
                                 initiator_cred_handle,
                                 context_handle,
                                 target_name,
                                 mech_type,
                                 req_flags,
                                 time_req,
                                 input_chan_bindings,
                                 input_token,
                                 actual_mech_type,
                                 output_token, ret_flags, time_rec);
        if (GSS_ERROR (maj_stat))
            return maj_stat;

        k5->flags = req_flags & (	/* GSS_C_DELEG_FLAG | */
                        GSS_C_MUTUAL_FLAG |
                        GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
                        GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
        /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
           it anyway. */
        k5->flags |= GSS_C_PROT_READY_FLAG;

        if (ret_flags)
            *ret_flags = k5->flags;

        k5->key = shishi_ap_key (k5->ap);
        k5->reqdone = 1;
    }
    else if (k5->reqdone && k5->flags & GSS_C_MUTUAL_FLAG && !k5->repdone)
    {
        maj_stat = init_reply (minor_status,
                               initiator_cred_handle,
                               context_handle,
                               target_name,
                               mech_type,
                               req_flags,
                               time_req,
                               input_chan_bindings,
                               input_token,
                               actual_mech_type,
                               output_token, ret_flags, time_rec);
        if (GSS_ERROR (maj_stat))
            return maj_stat;

        if (ret_flags)
            *ret_flags = k5->flags;

        k5->repdone = 1;
    }
    else
        maj_stat = GSS_S_FAILURE;

    if (time_rec)
        *time_rec = gss_krb5_tktlifetime (k5->tkt);

    return maj_stat;
}
コード例 #5
0
ファイル: shishi.c プロジェクト: millken/zhuxianB30
/* shishi authentication */
int
shishi_auth (Shishi ** handle, int verbose, char **cname,
	     const char *sname, int sock,
	     char *cmd, int port, Shishi_key ** enckey, char *realm)
{
  Shishi_ap *ap;
  Shishi_tkt *tkt;
  Shishi_tkts_hint hint;
  Shishi *h;

  int rc;
  char *out;
  int outlen;
  int krb5len, msglen;
  char *tmpserver;
  char auth;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5sendclient[] = "KCMDV0.2";
  /* to store error msg sent by server */
  char errormsg[101];
  char cksumdata[101];

  if (!shishi_check_version (SHISHI_VERSION))
    {
      fprintf (stderr, "shishi_check_version() failed:\n"
	       "Header file incompatible with shared library.\n");
      return 1;
    }

  if (realm)
    shishi_realm_default_set (*handle, realm);

  rc = shishi_init (handle);
  if (rc != SHISHI_OK)
    {
      fprintf (stderr,
	       "error initializing shishi: %s\n", shishi_strerror (rc));
      return 1;
    }

  h = *handle;

  if (!*cname)
    *cname = (char *) shishi_principal_default (h);

  /* size of KRB5 auth message */
  krb5len = strlen (krb5sendauth) + 1;
  msglen = htonl (krb5len);
  write (sock, &msglen, sizeof (int));
  /* KRB5 authentication message */
  write (sock, krb5sendauth, krb5len);
  /* size of client message */
  krb5len = strlen (krb5sendclient) + 1;
  msglen = htonl (krb5len);
  write (sock, &msglen, sizeof (int));
  /* KRB5 client message */
  write (sock, krb5sendclient, krb5len);

  /* get answer from server 0 = ok, 1 = error with message */
  read (sock, &auth, 1);
  if (auth)
    {
      read (sock, errormsg, 100);
      errormsg[100] = '\0';

      fprintf (stderr, "Error during server authentication : %s\n", errormsg);
      return 1;
    }

  if (verbose)
    {
      printf ("Client: %s\n", *cname);
      printf ("Server: %s\n", sname);
    }

  /* Get a ticket for the server. */

  memset (&hint, 0, sizeof (hint));

  tmpserver = malloc (strlen (SERVICE) + strlen (sname) + 2);
  if (!tmpserver)
    {
      perror ("shishi_auth()");
      return 1;
    }
  strcpy (tmpserver, SERVICE);
  strcat (tmpserver, "/");
  strcat (tmpserver, sname);

  hint.client = (char *) *cname;
  hint.server = (char *) tmpserver;

  tkt = shishi_tkts_get (shishi_tkts_default (h), &hint);
  if (!tkt)
    {
      free (tmpserver);
      fprintf (stderr, "cannot find ticket for \"%s\"\n", sname);
      return 1;
    }

  free (tmpserver);

  if (verbose)
    shishi_tkt_pretty_print (tkt, stderr);

  /* Create Authentication context */

  rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED);
  if (rc != SHISHI_OK)
    {
      fprintf (stderr, "cannot create authentication context\n");
      return 1;
    }


  /* checksum = port: terminal name */

  snprintf (cksumdata, 100, "%u:%s%s", ntohs (port), cmd, *cname);

  /* add checksum to authenticator */

  shishi_ap_authenticator_cksumdata_set (ap, cksumdata, strlen (cksumdata));
  /* To be compatible with MIT rlogind */
  shishi_ap_authenticator_cksumtype_set (ap, SHISHI_RSA_MD5);

  /* create der encoded AP-REQ */

  rc = shishi_ap_req_der (ap, &out, &outlen);
  if (rc != SHISHI_OK)
    {
      fprintf (stderr, "cannot build authentication request: %s\n",
	       shishi_strerror (rc));

      return 1;
    }

  if (verbose)
    shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));

  /* extract subkey if present from ap exchange for secure connection */

  if (enckey)
    shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey);

  /* send size of AP-REQ to the server */

  msglen = htonl (outlen);
  write (sock, (char *) &msglen, sizeof (int));

  /* send AP-REQ to the server */

  write (sock, out, outlen);

  /* read a respond from server - what ? */

  read (sock, &auth, sizeof (int));

  /* For mutual authentication, wait for server reply. */

  if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap)))
    {
      if (verbose)
	printf ("Waiting for server to authenticate itself...\n");

      /* read size of the AP-REP */

      read (sock, (char *) &outlen, sizeof (int));

      /* read AP-REP */
      outlen = ntohl (outlen);
      outlen = read (sock, out, outlen);

      rc = shishi_ap_rep_verify_der (ap, out, outlen);
      if (rc == SHISHI_OK)
	{
	  if (verbose)
	    printf ("AP-REP verification OK...\n");
	}
      else
	{
	  if (rc == SHISHI_APREP_VERIFY_FAILED)
	    fprintf (stderr, "AP-REP verification failed...\n");
	  else
	    fprintf (stderr, "AP-REP verification error: %s\n",
		     shishi_strerror (rc));
	  return 1;
	}

      /* The server is authenticated. */
      if (verbose)
	printf ("Server authenticated.\n");
    }

  /* We are now authenticated. */
  if (verbose)
    printf ("User authenticated.\n");

  return 0;

}