int _gsasl_kerberos_v5_client_init (Gsasl_ctx * ctx) { if (!shishi_check_version (SHISHI_VERSION)) return GSASL_UNKNOWN_MECHANISM; return GSASL_OK; }
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; }
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; }
/* authentication, server side */ int get_auth (int infd, krb5_context *ctx, krb5_auth_context *actx, krb5_keyblock **key, const char **err_msg, int *protoversion, int *cksumtype, char **cksum, size_t *cksumlen, char *srvname) { char *out; size_t outlen; char *buf; int buflen; int len; int rc; int error; /* KERBEROS 5 SENDAUTH MESSAGE */ char krb5sendauth[] = "KRB5_SENDAUTH_V1.0"; /* PROTOCOL VERSION */ char krb5kcmd1[] = "KCMDV0.1"; char krb5kcmd2[] = "KCMDV0.2"; char *servername, *server = NULL, *realm = NULL; *err_msg = NULL; /* Get key for the server. */ # if 0 /* * XXX: Taken straight from the version for libshishi. * XXX: No adaptions yet. */ rc = shishi_init_server (handle); if (rc != SHISHI_OK) return rc; if (srvname && *srvname) { rc = shishi_parse_name (*handle, srvname, &server, &realm); if (rc != SHISHI_OK) { *err_msg = shishi_strerror (rc); return rc; } } if (server && *server) { char *p; servername = malloc (sizeof (SERVICE) + strlen (server) + 2); if (!servername) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } p = strchr (server, '/'); if (p && (p != server)) sprintf (servername, "%s", server); /* Non-empty prefix. */ else sprintf (servername, "%s/%s", SERVICE, server + (p ? 1 : 0)); /* Remove initial slash. */ } else servername = shishi_server_for_local_service (*handle, SERVICE); if (realm && *realm) shishi_realm_default_set (*handle, realm); free (server); free (realm); /* Enable use of `~/.k5login'. */ if (shishi_check_version ("1.0.2")) /* Faulty in version 1.0.1. */ { rc = shishi_cfg_authorizationtype_set (*handle, "k5login basic"); if (rc != SHISHI_OK) { *err_msg = shishi_error (*handle); return rc; } } key = shishi_hostkeys_for_serverrealm (*handle, servername, shishi_realm_default (*handle)); free (servername); if (!key) { *err_msg = shishi_error (*handle); return SHISHI_INVALID_KEY; } /* Read Kerberos 5 sendauth message */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading message size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication message"; return SHISHI_IO_ERROR; } len = strlen (krb5sendauth); rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen); if (rc) { *err_msg = "Invalid authentication type"; /* Authentication type is wrong. */ write (infd, "\001", 1); return SHISHI_VERIFY_FAILED; } free (buf); /* Read protocol version */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading protocol message size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading protocol message"; return SHISHI_IO_ERROR; } len = strlen (krb5kcmd1); rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen); if (rc) { len = strlen (krb5kcmd2); rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen); if (rc) { *err_msg = "Protocol version not supported"; /* Protocol version is wrong. */ write (infd, "\002", 1); return SHISHI_VERIFY_FAILED; } *protoversion = 2; } else *protoversion = 1; free (buf); /* Authentication type is ok */ write (infd, "\0", 1); /* Read Authentication request from client */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading authentication request size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication request"; return SHISHI_IO_ERROR; } /* Create Authentication context */ rc = shishi_ap_nosubkey (*handle, ap); if (rc != SHISHI_OK) return rc; /* Store request in context */ rc = shishi_ap_req_der_set (*ap, buf, buflen); if (rc != SHISHI_OK) return rc; free (buf); /* Process authentication request */ rc = shishi_ap_req_process (*ap, key); if (rc != SHISHI_OK) return rc; # ifdef ENCRYPTION /* extract subkey if present from ap exchange for secure connection */ if (*protoversion == 2) { *enckey = NULL; shishi_authenticator_get_subkey (*handle, shishi_ap_authenticator (*ap), enckey); } # endif /* Get authenticator checksum */ rc = shishi_authenticator_cksum (*handle, shishi_ap_authenticator (*ap), cksumtype, cksum, cksumlen); if (rc != SHISHI_OK) return rc; /* User is authenticated. */ error = 0; write (infd, &error, sizeof (int)); /* Authenticate ourself to client, if requested. */ if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap))) { int len; rc = shishi_ap_rep_der (*ap, &out, &outlen); if (rc != SHISHI_OK) return rc; len = outlen; len = htonl (len); rc = write (infd, &len, sizeof (len)); if (rc != sizeof (int)) { *err_msg = "Error sending AP-REP"; free (out); return SHISHI_IO_ERROR; } rc = write (infd, out, ntohl (len)); if (rc != (int) ntohl (len)) { *err_msg = "Error sending AP-REP"; free (out); return SHISHI_IO_ERROR; } free (out); /* We are authenticated to client */ } # ifdef ENCRYPTION if (*protoversion == 1) { Shishi_tkt *tkt; tkt = shishi_ap_tkt (*ap); if (tkt == NULL) { *err_msg = "Could not get tkt from AP-REQ"; return SHISHI_INVALID_TICKET; } rc = shishi_encticketpart_get_key (*handle, shishi_tkt_encticketpart (tkt), enckey); if (rc != SHISHI_OK) return rc; } # endif /* ENCRYPTION */ return 0; # else return -1; # endif }
static Shishi * init_handle (int outputtype) { Shishi *handle; int rc; handle = xcalloc (1, sizeof (*handle)); shishi_error_set_outputtype (handle, outputtype); if (!shishi_check_version (SHISHI_VERSION)) { shishi_warn (handle, "Library and header version missmatch (%s vs %s).", shishi_check_version (NULL), SHISHI_VERSION); free (handle); return NULL; } rc = gl_sockets_startup (SOCKETS_2_1); if (rc) { shishi_warn (handle, "Failed to initialized Windows sockets (%d)", rc); free (handle); return NULL; } rc = _shishi_crypto_init (handle); if (rc != SHISHI_OK) { shishi_warn (handle, "Cannot initialize crypto library"); free (handle); return NULL; } #ifdef USE_STARTTLS rc = _shishi_tls_init (handle); if (rc != SHISHI_OK) { shishi_warn (handle, "Cannot initialize TLS library"); free (handle); return NULL; } #endif rc = _shishi_asn1_init (handle); if (rc != SHISHI_OK) { shishi_warn (handle, "%s", shishi_strerror (SHISHI_ASN1_ERROR)); free (handle); return NULL; } bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); handle->kdctimeout = 5; handle->kdcretries = 3; handle->ticketlife = TICKETLIFE; handle->renewlife = RENEWLIFE; handle->nclientkdcetypes = 1; handle->clientkdcetypes = xmalloc (sizeof (*handle->clientkdcetypes) * handle->nclientkdcetypes); handle->clientkdcetypes[0] = SHISHI_AES256_CTS_HMAC_SHA1_96; handle->nauthorizationtypes = 1; handle->authorizationtypes = xmalloc (sizeof (*handle->authorizationtypes) * handle->nauthorizationtypes); handle->authorizationtypes[0] = SHISHI_AUTHORIZATION_BASIC; return handle; }
/* 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; }
int get_auth (int infd, Shishi ** handle, Shishi_ap ** ap, Shishi_key ** enckey, const char **err_msg, int *protoversion, int *cksumtype, char **cksum, int *cksumlen) { Shishi_key *key; char *out; int outlen; char *buf; int buflen; int len; int rc; int i; int error; /* KERBEROS 5 SENDAUTH MESSAGE */ char krb5sendauth[] = "KRB5_SENDAUTH_V1.0"; /* PROTOCOL VERSION */ char krb5kcmd1[] = "KCMDV0.1"; char krb5kcmd2[] = "KCMDV0.2"; int auth_correct = 0; char *servername; *err_msg = NULL; /* Get key for the server. */ if (!shishi_check_version (SHISHI_VERSION)) { *err_msg = "shishi_check_version() failed: header file incompatible with shared library."; return 1; } rc = shishi_init_server (handle); if (rc != SHISHI_OK) return rc; servername = shishi_server_for_local_service (*handle, SERVICE); key = shishi_hostkeys_for_server (*handle, servername); if (!key) { *err_msg = shishi_error (*handle); return 1; } /* Read Kerberos 5 sendauth message */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading message size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication message"; return 1; } len = strlen (krb5sendauth); rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen); if (rc) { *err_msg = "Invalid authentication type"; return 1; } free (buf); /* Read protocol version */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading protocol message size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading protocol message"; return 1; } len = strlen (krb5kcmd1); rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen); if (rc) { len = strlen (krb5kcmd2); rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen); if (rc) { *err_msg = "Protocol version not supported"; return 1; } *protoversion = 2; } else *protoversion = 1; free (buf); /* Authentication type is ok */ write (infd, "\0", 1); /* Read Authentication request from client */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading authentication request size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication request"; return 1; } /* Create Authentication context */ rc = shishi_ap_nosubkey (*handle, ap); if (rc != SHISHI_OK) return rc; /* Store request in context */ shishi_ap_req_der_set (*ap, buf, buflen); if (rc != SHISHI_OK) return rc; free (buf); /* Process authentication request */ rc = shishi_ap_req_process (*ap, key); if (rc != SHISHI_OK) return rc; # ifdef ENCRYPTION /* extract subkey if present from ap exchange for secure connection */ if (*protoversion == 2) { *enckey = NULL; shishi_authenticator_get_subkey (*handle, shishi_ap_authenticator (*ap), enckey); } # endif /* Get authenticator checksum */ rc = shishi_authenticator_cksum (*handle, shishi_ap_authenticator (*ap), cksumtype, cksum, cksumlen); if (rc != SHISHI_OK) return rc; /* User is authenticated. */ error = 0; write (infd, &error, sizeof (int)); /* Authenticate ourself to client, if request */ if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap))) { rc = shishi_ap_rep_der (*ap, &out, &outlen); if (rc != SHISHI_OK) return rc; outlen = htonl (outlen); rc = write (infd, &outlen, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error sending AP-REP"; free (out); return 1; } rc = write (infd, out, ntohl (outlen)); if (rc != ntohl (outlen)) { *err_msg = "Error sending AP-REP"; free (out); return 1; } free (out); /* We are authenticated to client */ } # ifdef ENCRYPTION if (*protoversion == 1) { Shishi_tkt *tkt; tkt = shishi_ap_tkt (*ap); if (tkt == NULL) { *err_msg = "Could not get tkt from AP-REQ"; return 1; } rc = shishi_encticketpart_get_key (*handle, shishi_tkt_encticketpart (tkt), enckey); if (rc != SHISHI_OK) return rc; } # endif return SHISHI_OK; }