/* shishi authentication */ int auth (Shishi * h, int verbose, const char *cname, const char *sname, int sock, char *cmd, char *port, Shishi_key ** enckey, Shishi_key * deckey) { Shishi_ap *ap; Shishi_tkt *tkt; Shishi_tkts_hint hint; int rc; char *out; int outlen; int krb5len, msglen; 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]; /* size of KRB5 auth message */ krb5len = strlen (krb5sendauth) + 1; msglen = htonl (krb5len); safewrite (sock, &msglen, sizeof (int)); /* KRB5 authentication message */ safewrite (sock, krb5sendauth, krb5len); /* size of client message */ krb5len = strlen (krb5sendclient) + 1; msglen = htonl (krb5len); safewrite (sock, &msglen, sizeof (int)); /* KRB5 client message */ safewrite (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'; printf ("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)); hint.client = (char *) cname; hint.server = (char *) sname; tkt = shishi_tkts_get (shishi_tkts_default (h), &hint); if (!tkt) { printf ("cannot find ticket for \"%s\"\n", sname); return 1; } 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) { printf ("cannot create authentication context\n"); return 1; } /* checksum = port: terminal name */ snprintf (cksumdata, 100, "%s:%s%s", 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) { printf ("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 */ shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey); /* send size of AP-REQ to the server */ msglen = htonl (outlen); safewrite (sock, (char *) &msglen, sizeof (int)); /* send AP-REQ to the server */ safewrite (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) printf ("AP-REP verification failed...\n"); else printf ("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 AUTH_OK; }
/* Request part of gss_krb5_init_sec_context. Assumes that context_handle is valid, and has krb5 specific structure, and that output_token is valid and cleared. */ static OM_uint32 init_request (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; char *cksum, *der; size_t cksumlen; int rc; OM_uint32 maj_stat; gss_buffer_desc tmp; Shishi_tkts_hint hint; /* Get service ticket. */ maj_stat = gss_krb5_canonicalize_name (minor_status, target_name, GSS_C_NO_OID, &k5->peerptr); if (GSS_ERROR (maj_stat)) return maj_stat; memset (&hint, 0, sizeof (hint)); hint.server = k5->peerptr->value; hint.endtime = time_req; k5->tkt = shishi_tkts_get (shishi_tkts_default (k5->sh), &hint); if (!k5->tkt) { if (minor_status) *minor_status = GSS_KRB5_S_KG_CCACHE_NOMATCH; return GSS_S_NO_CRED; } /* Create Authenticator checksum field. */ maj_stat = _gss_krb5_checksum_pack (minor_status, initiator_cred_handle, context_handle, input_chan_bindings, req_flags, &cksum, &cksumlen); if (GSS_ERROR (maj_stat)) return maj_stat; /* Create AP-REQ in output_token. */ rc = shishi_ap_tktoptionsraw (k5->sh, &k5->ap, k5->tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED, 0x8003, cksum, cksumlen); free (cksum); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = shishi_authenticator_seqnumber_get (k5->sh, shishi_ap_authenticator (k5->ap), &k5->initseqnr); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = shishi_ap_req_der (k5->ap, &der, &tmp.length); if (rc != SHISHI_OK) return GSS_S_FAILURE; tmp.value = der; rc = gss_encapsulate_token_prefix (&tmp, TOK_AP_REQ, TOK_LEN, GSS_KRB5, output_token); free (der); if (!rc) return GSS_S_FAILURE; if (req_flags & GSS_C_MUTUAL_FLAG) return GSS_S_CONTINUE_NEEDED; return GSS_S_COMPLETE; }
static Shishi_ap * auth (Shishi * h, int verbose, const char *cname, const char *sname) { Shishi_ap *ap; Shishi_tkt *tkt; Shishi_tkts_hint hint; int rc; printf ("Client: %s\n", cname); printf ("Server: %s\n", sname); /* Get a ticket for the server. */ memset (&hint, 0, sizeof (hint)); hint.client = (char *) cname; hint.server = (char *) sname; tkt = shishi_tkts_get (shishi_tkts_default (h), &hint); if (!tkt) { printf ("cannot find ticket for \"%s\"\n", sname); return NULL; } 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) { printf ("cannot create authentication context\n"); return NULL; } /* Build Authentication request */ rc = shishi_ap_req_build (ap); if (rc != SHISHI_OK) { printf ("cannot build authentication request: %s\n", shishi_strerror (rc)); return NULL; } if (verbose) shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap)); /* Authentication ourself to server */ shishi_apreq_print (h, stdout, shishi_ap_req (ap)); /* Note: to get the binary blob to send, use: * * char *out; int outlen; * ... * rc = shishi_ap_req_der (ap, &out, &outlen); * ... * write(fd, out, outlen); */ /* For mutual authentication, wait for server reply. */ if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap))) { Shishi_asn1 aprep; printf ("Waiting for server to authenticate itself...\n"); rc = shishi_aprep_parse (h, stdin, &aprep); if (rc != SHISHI_OK) { printf ("Cannot parse AP-REP from server: %s\n", shishi_strerror (rc)); return NULL; } rc = shishi_ap_rep_verify_asn1 (ap, aprep); if (rc == SHISHI_OK) printf ("AP-REP verification OK...\n"); else { if (rc == SHISHI_APREP_VERIFY_FAILED) printf ("AP-REP verification failed...\n"); else printf ("AP-REP verification error: %s\n", shishi_strerror (rc)); return NULL; } /* The server is authenticated. */ printf ("Server authenticated.\n"); } /* We are now authenticated. */ printf ("User authenticated.\n"); return ap; }
int main (int argc, char *argv[]) { struct gengetopt_args_info args; time_t starttime, endtime, renew_till; Shishi *sh; int rc; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); set_program_name (argv[0]); if (cmdline_parser (argc, argv, &args) != 0) usage (EXIT_FAILURE); if (args.version_given) { version_etc (stdout, "shishi", PACKAGE_NAME, VERSION, "Simon Josefsson", (char *) NULL); return EXIT_SUCCESS; } if (args.inputs_num > 2 || args.destroy_given + args.list_given + args.renew_given > 1) { error (0, 0, _("too many arguments")); usage (EXIT_FAILURE); } if (args.help_given) usage (EXIT_SUCCESS); rc = shishi_init_with_paths (&sh, args.ticket_file_arg, args.system_configuration_file_arg, args.configuration_file_arg); if (rc == SHISHI_HANDLE_ERROR) error (EXIT_FAILURE, 0, _("Could not initialize libshishi.")); rc = shishi_cfg_clientkdcetype_set (sh, args.encryption_type_arg); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not set encryption types: %s"), shishi_strerror (rc)); if (args.inputs_num > 0) { rc = shishi_parse_name (sh, args.inputs[0], (args.client_name_arg ? NULL : &args.client_name_arg), (args.realm_arg ? NULL : &args.realm_arg)); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not parse client principal \"%s\": %s"), args.inputs[0], shishi_strerror (rc)); } if (args.inputs_num > 1) { rc = shishi_parse_name (sh, args.inputs[1], (args.server_name_arg ? NULL : &args.server_name_arg), (args.realm_arg ? NULL : &args.realm_arg)); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not parse server principal \"%s\": %s"), args.inputs[1], shishi_strerror (rc)); } rc = shishi_cfg (sh, args.library_options_arg); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not read library options: %s"), shishi_strerror (rc)); if (args.verbose_given > 0) shishi_cfg (sh, "verbose"); if (args.verbose_given > 1) shishi_cfg (sh, "verbose-noise"); if (args.verbose_given > 2) shishi_cfg (sh, "verbose-asn1"); if (args.verbose_given > 3) shishi_cfg (sh, "verbose-crypto"); if (args.verbose_given > 4) shishi_cfg (sh, "verbose-crypto-noise"); if (args.starttime_arg) { starttime = shishi_get_date (args.starttime_arg, NULL); if (starttime == -1) error (EXIT_FAILURE, 0, _("Invalid --starttime date `%s'"), args.starttime_arg); } else starttime = time (NULL); if (args.endtime_arg) { endtime = shishi_get_date (args.endtime_arg, &starttime); if (endtime == -1) error (EXIT_FAILURE, 0, _("Invalid --endtime date `%s'"), args.starttime_arg); } else endtime = 0; if (args.renew_till_arg) { renew_till = shishi_get_date (args.renew_till_arg, &starttime); if (renew_till == -1) error (EXIT_FAILURE, 0, _("Invalid --renew-till date `%s'"), args.renew_till_arg); } else renew_till = 0; if (args.client_name_arg) shishi_principal_default_set (sh, args.client_name_arg); if (args.realm_arg) shishi_realm_default_set (sh, args.realm_arg); if (!args.ticket_granter_arg) asprintf (&args.ticket_granter_arg, "krbtgt/%s", shishi_realm_default (sh)); if (args.list_flag) { if (!args.quiet_flag) printf (_("Tickets in `%s':\n"), shishi_tkts_default_file (sh)); rc = shishi_tkts_print_for_service (shishi_tkts_default (sh), stdout, args.server_name_arg); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not list tickets: %s"), shishi_strerror (rc)); } else if (args.destroy_flag) { int i, removed = 0; for (i = 0; i < shishi_tkts_size (shishi_tkts_default (sh)); i++) { if (args.server_name_arg && !shishi_tkt_server_p (shishi_tkts_nth (shishi_tkts_default (sh), i), args.server_name_arg)) continue; if (args.verbose_given) { printf (_("Removing ticket:\n")); shishi_tkt_pretty_print (shishi_tkts_nth (shishi_tkts_default (sh), i), stdout); } rc = shishi_tkts_remove (shishi_tkts_default (sh), i); if (rc != SHISHI_OK) error (EXIT_FAILURE, 0, _("Could not destroy ticket %d:\n%s"), i, shishi_strerror (rc)); i--; removed++; } if (!args.quiet_flag) { if (removed == 0) printf (_("No tickets removed.\n")); else printf (ngettext ("%d ticket removed.\n", "%d tickets removed.\n", removed), removed); } } else if (args.renew_given) { error (EXIT_FAILURE, 0, "Command --renew not implemented."); } else { Shishi_tkt *tkt; Shishi_tkts_hint hint; memset (&hint, 0, sizeof (hint)); hint.client = args.client_name_arg; hint.server = args.server_name_arg ? args.server_name_arg : args.ticket_granter_arg; hint.starttime = starttime; hint.endtime = endtime; hint.renew_till = renew_till; if (args.renewable_flag) hint.tktflags |= SHISHI_TICKETFLAGS_RENEWABLE; if (args.proxiable_flag) hint.tktflags |= SHISHI_TICKETFLAGS_PROXIABLE; if (args.proxy_flag) hint.tktflags |= SHISHI_TICKETFLAGS_PROXY; if (args.forwardable_flag) hint.tktflags |= SHISHI_TICKETFLAGS_FORWARDABLE; if (args.forwarded_flag) hint.tktflags |= SHISHI_TICKETFLAGS_FORWARDED; tkt = shishi_tkts_get (shishi_tkts_default (sh), &hint); if (!tkt) error (EXIT_FAILURE, 0, _("Could not get ticket as `%s' for `%s'."), hint.client ? hint.client : shishi_principal_default (sh), hint.server); shishi_tkt_pretty_print (tkt, stdout); } shishi_tkts_expire (shishi_tkts_default (sh)); if (args.ticket_write_file_arg) shishi_tkts_default_file_set (sh, args.ticket_write_file_arg); shishi_done (sh); return EXIT_SUCCESS; }