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; }
/* 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 }
/* 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; }