int kerberos5_is_auth (TN_Authenticator * ap, unsigned char *data, int cnt, char *errbuf, int errbuflen) { int r = 0; krb5_keytab keytabid = 0; krb5_authenticator *authenticator; char *name; krb5_data outbuf; krb5_keyblock *newkey = NULL; krb5_principal server; # ifdef ENCRYPTION Session_Key skey; # endif auth.data = (char *) data; auth.length = cnt; if (!r && !auth_context) r = krb5_auth_con_init (telnet_context, &auth_context); if (!r) { krb5_rcache rcache; r = krb5_auth_con_getrcache (telnet_context, auth_context, &rcache); if (!r && !rcache) { r = krb5_sname_to_principal (telnet_context, 0, 0, KRB5_NT_SRV_HST, &server); if (!r) { r = krb5_get_server_rcache (telnet_context, krb5_princ_component (telnet_context, server, 0), &rcache); krb5_free_principal (telnet_context, server); } } if (!r) r = krb5_auth_con_setrcache (telnet_context, auth_context, rcache); } if (!r && telnet_srvtab) r = krb5_kt_resolve (telnet_context, telnet_srvtab, &keytabid); if (!r) r = krb5_rd_req (telnet_context, &auth_context, &auth, NULL, keytabid, NULL, &ticket); if (r) { snprintf (errbuf, errbuflen, "krb5_rd_req failed: %s", error_message (r)); return r; } /* 256 bytes should be much larger than any reasonable first component of a service name especially since the default is of length 4. */ if (krb5_princ_component (telnet_context, ticket->server, 0)->length < 256) { char princ[256]; strncpy (princ, krb5_princ_component (telnet_context, ticket->server, 0)->data, krb5_princ_component (telnet_context, ticket->server, 0)->length); princ[krb5_princ_component (telnet_context, ticket->server, 0)-> length] = '\0'; if (strcmp ("host", princ)) { snprintf (errbuf, errbuflen, "incorrect service name: \"%s\" != \"host\"", princ); return 1; } } else { strncpy (errbuf, "service name too long", errbuflen); return 1; } r = krb5_auth_con_getauthenticator (telnet_context, auth_context, &authenticator); if (r) { snprintf (errbuf, errbuflen, "krb5_auth_con_getauthenticator failed: %s", error_message (r)); return 1; } # ifdef AUTH_ENCRYPT_MASK if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON && !authenticator->checksum) { snprintf (errbuf, errbuflen, "authenticator is missing required checksum"); return 1; } # endif if (authenticator->checksum) { char type_check[2]; krb5_checksum *cksum = authenticator->checksum; krb5_keyblock *key; type_check[0] = ap->type; type_check[1] = ap->way; r = krb5_auth_con_getkey (telnet_context, auth_context, &key); if (r) { snprintf (errbuf, errbuflen, "krb5_auth_con_getkey failed: %s", error_message (r)); return 1; } r = krb5_verify_checksum (telnet_context, cksum->checksum_type, cksum, &type_check, 2, key->contents, key->length); if (r) { snprintf (errbuf, errbuflen, "checksum verification failed: %s", error_message (r)); return 1; } krb5_free_keyblock (telnet_context, key); } krb5_free_authenticator (telnet_context, authenticator); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { if ((r = krb5_mk_rep (telnet_context, auth_context, &outbuf))) { snprintf (errbuf, errbuflen, "Make reply failed: %s", error_message (r)); return 1; } Data (ap, KRB_RESPONSE, outbuf.data, outbuf.length); } if (krb5_unparse_name (telnet_context, ticket->enc_part2->client, &name)) name = 0; Data (ap, KRB_ACCEPT, name, name ? -1 : 0); DEBUG (("telnetd: Kerberos5 identifies him as ``%s''\r\n", name ? name : "")); auth_finished (ap, AUTH_USER); free (name); krb5_auth_con_getremotesubkey (telnet_context, auth_context, &newkey); if (session_key) { krb5_free_keyblock (telnet_context, session_key); session_key = 0; } if (newkey) { krb5_copy_keyblock (telnet_context, newkey, &session_key); krb5_free_keyblock (telnet_context, newkey); } else { krb5_copy_keyblock (telnet_context, ticket->enc_part2->session, &session_key); } telnet_encrypt_key (&skey); return 0; }
int main(int argc, const char *argv[]) { static const char *server = NULL; static const char *principal = NULL; static const char *keytab = NULL; static const char *enctypes_string = NULL; static const char *binddn = NULL; static const char *bindpw = NULL; int quiet = 0; int askpass = 0; int permitted_enctypes = 0; int retrieve = 0; struct poptOption options[] = { { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, _("Print as little as possible"), _("Output only on errors")}, { "server", 's', POPT_ARG_STRING, &server, 0, _("Contact this specific KDC Server"), _("Server Name") }, { "principal", 'p', POPT_ARG_STRING, &principal, 0, _("The principal to get a keytab for (ex: ftp/[email protected])"), _("Kerberos Service Principal Name") }, { "keytab", 'k', POPT_ARG_STRING, &keytab, 0, _("File were to store the keytab information"), _("Keytab File Name") }, { "enctypes", 'e', POPT_ARG_STRING, &enctypes_string, 0, _("Encryption types to request"), _("Comma separated encryption types list") }, { "permitted-enctypes", 0, POPT_ARG_NONE, &permitted_enctypes, 0, _("Show the list of permitted encryption types and exit"), _("Permitted Encryption Types") }, { "password", 'P', POPT_ARG_NONE, &askpass, 0, _("Asks for a non-random password to use for the principal"), NULL }, { "binddn", 'D', POPT_ARG_STRING, &binddn, 0, _("LDAP DN"), _("DN to bind as if not using kerberos") }, { "bindpw", 'w', POPT_ARG_STRING, &bindpw, 0, _("LDAP password"), _("password to use if not using kerberos") }, { "retrieve", 'r', POPT_ARG_NONE, &retrieve, 0, _("Retrieve current keys without changing them"), NULL }, POPT_AUTOHELP POPT_TABLEEND }; poptContext pc; char *ktname; char *password = NULL; krb5_context krbctx; krb5_ccache ccache; krb5_principal uprinc = NULL; krb5_principal sprinc; krb5_error_code krberr; struct keys_container keys = { 0 }; krb5_keytab kt; int kvno; int i, ret; char *err_msg; ret = init_gettext(); if (ret) { fprintf(stderr, "Failed to load translations\n"); } krberr = krb5_init_context(&krbctx); if (krberr) { fprintf(stderr, _("Kerberos context initialization failed\n")); exit(1); } pc = poptGetContext("ipa-getkeytab", argc, (const char **)argv, options, 0); ret = poptGetNextOpt(pc); if (ret == -1 && permitted_enctypes && !(server || principal || keytab || quiet)) { krb5_enctype *ktypes; char enc[79]; /* fit std terminal or truncate */ krberr = krb5_get_permitted_enctypes(krbctx, &ktypes); if (krberr) { fprintf(stderr, _("No system preferred enctypes ?!\n")); exit(1); } fprintf(stdout, _("Supported encryption types:\n")); for (i = 0; ktypes[i]; i++) { krberr = krb5_enctype_to_string(ktypes[i], enc, 79); if (krberr) { fprintf(stderr, _("Warning: " "failed to convert type (#%d)\n"), i); continue; } fprintf(stdout, "%s\n", enc); } ipa_krb5_free_ktypes(krbctx, ktypes); exit (0); } if (ret != -1 || !principal || !keytab || permitted_enctypes) { if (!quiet) { poptPrintUsage(pc, stderr, 0); } exit(2); } if (NULL!=binddn && NULL==bindpw) { fprintf(stderr, _("Bind password required when using a bind DN.\n")); if (!quiet) poptPrintUsage(pc, stderr, 0); exit(10); } if (!server) { struct ipa_config *ipacfg = NULL; ret = read_ipa_config(&ipacfg); if (ret == 0) { server = ipacfg->server_name; ipacfg->server_name = NULL; } free(ipacfg); if (!server) { fprintf(stderr, _("Server name not provided and unavailable\n")); exit(2); } } if (askpass && retrieve) { fprintf(stderr, _("Incompatible options provided (-r and -P)\n")); exit(2); } if (askpass) { password = ask_password(krbctx); if (!password) { exit(2); } } else if (enctypes_string && strchr(enctypes_string, ':')) { if (!quiet) { fprintf(stderr, _("Warning: salt types are not honored" " with randomized passwords (see opt. -P)\n")); } } ret = asprintf(&ktname, "WRFILE:%s", keytab); if (ret == -1) { exit(3); } krberr = krb5_parse_name(krbctx, principal, &sprinc); if (krberr) { fprintf(stderr, _("Invalid Service Principal Name\n")); exit(4); } if (NULL == bindpw) { krberr = krb5_cc_default(krbctx, &ccache); if (krberr) { fprintf(stderr, _("Kerberos Credential Cache not found. " "Do you have a Kerberos Ticket?\n")); exit(5); } krberr = krb5_cc_get_principal(krbctx, ccache, &uprinc); if (krberr) { fprintf(stderr, _("Kerberos User Principal not found. " "Do you have a valid Credential Cache?\n")); exit(6); } } krberr = krb5_kt_resolve(krbctx, ktname, &kt); if (krberr) { fprintf(stderr, _("Failed to open Keytab\n")); exit(7); } kvno = -1; ret = ldap_get_keytab(krbctx, (retrieve == 0), password, enctypes_string, server, principal, uprinc, binddn, bindpw, &keys, &kvno, &err_msg); if (ret) { if (!quiet && err_msg != NULL) { fprintf(stderr, "%s", err_msg); } } if (retrieve == 0 && kvno == -1) { if (!quiet) { fprintf(stderr, _("Retrying with pre-4.0 keytab retrieval method...\n")); } /* create key material */ ret = create_keys(krbctx, sprinc, password, enctypes_string, &keys, &err_msg); if (!ret) { if (err_msg != NULL) { fprintf(stderr, "%s", err_msg); } fprintf(stderr, _("Failed to create key material\n")); exit(8); } kvno = ldap_set_keytab(krbctx, server, principal, uprinc, binddn, bindpw, &keys); } if (kvno == -1) { fprintf(stderr, _("Failed to get keytab\n")); exit(9); } for (i = 0; i < keys.nkeys; i++) { krb5_keytab_entry kt_entry; memset((char *)&kt_entry, 0, sizeof(kt_entry)); kt_entry.principal = sprinc; kt_entry.key = keys.ksdata[i].key; kt_entry.vno = kvno; krberr = krb5_kt_add_entry(krbctx, kt, &kt_entry); if (krberr) { fprintf(stderr, _("Failed to add key to the keytab\n")); exit (11); } } free_keys_contents(krbctx, &keys); krberr = krb5_kt_close(krbctx, kt); if (krberr) { fprintf(stderr, _("Failed to close the keytab\n")); exit (12); } if (!quiet) { fprintf(stderr, _("Keytab successfully retrieved and stored in: %s\n"), keytab); } exit(0); }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; krb5_init_creds_context icc; krb5_keytab kt = NULL; int will_use_keytab = (use_keytab || keytab_str); krb5_prompter_fct prompter = NULL; int need_prompt; passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #if defined(__APPLE__) && !defined(__APPLE_TARGET_EMBEDDED__) if (passwd[0] == '\0' && !will_use_keytab && home_directory_flag) { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, &length, &buffer, &passwordItem); free(name); if (osret != noErr) goto nopassword; if (length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } SecKeychainItemFreeContent(NULL, buffer); nopassword: do { } while(0); } #endif need_prompt = !(pk_user_id || ent_user_id || anonymous_flag || will_use_keytab || passwd[0] != '\0') && interactive; if (need_prompt) prompter = krb5_prompter_posix; else prompter = krb5_prompter_print_only; memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if(forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); if(proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); if(anonymous_flag) krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, interactive ? krb5_prompter_posix : krb5_prompter_print_only, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_cert(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time (renewstr, "s"); if (renew < 0) errx (1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life (opt, renew); } if(ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); if(start_str) { int tmp = parse_time (start_str, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if(etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if(enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if(ret) krb5_err(context, 1, ret, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &icc); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, icc, server_str); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_service"); } if (kdc_hostname) krb5_init_creds_set_kdc_hostname(context, icc, kdc_hostname); if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); ret = krb5_init_creds_set_fast_ccache(context, icc, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if(will_use_keytab) { if(keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err (context, 1, ret, "resolving keytab"); ret = krb5_init_creds_set_keytab(context, icc, kt); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_keytab"); } if (passwd[0] == '\0' && need_prompt) { char *p, *prompt; krb5_unparse_name(context, principal, &p); asprintf (&prompt, N_("%s's Password: "******""), p); free(p); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free (prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, icc, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } ret = krb5_init_creds_get(context, icc); #ifdef __APPLE__ /* * Save password in Keychain */ if (ret == 0 && keychain_flag && passwordItem == NULL) { krb5_error_code ret2; const char *realm; char *name; realm = krb5_principal_get_realm(context, principal); ret2 = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret2 == 0) { (void)SecKeychainAddGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, (UInt32)strlen(passwd), passwd, NULL); free(name); } } #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: #ifdef __APPLE__ if (passwordItem) SecKeychainItemDelete(passwordItem); #endif krb5_errx(context, 1, N_("Password incorrect", "")); case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); case KRB5KDC_ERR_KEY_EXPIRED: krb5_errx(context, 1, N_("Password expired", "")); default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } ret = krb5_init_creds_get_creds(context, icc, &cred); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_get_creds"); krb5_process_last_request(context, opt, icc); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); ret = krb5_init_creds_store(context, icc, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); ret = krb5_init_creds_store_config(context, icc, tempccache); if (ret) krb5_warn(context, ret, "krb5_init_creds_store_config"); ret = krb5_init_creds_warn_user(context, icc); if (ret) krb5_warn(context, ret, "krb5_init_creds_warn_user"); #ifdef __APPLE__ /* * Set for this case, default to * so that all processes can use * this cache. */ { heim_array_t bundleacl = heim_array_create(); heim_string_t ace; if (bundle_acl_strings.num_strings > 0) { int i; for (i = 0; i < bundle_acl_strings.num_strings; i++) { ace = heim_string_create(bundle_acl_strings.strings[i]); heim_array_append_value(bundleacl, ace); heim_release(ace); } } else { ace = heim_string_create("*"); heim_array_append_value(bundleacl, ace); heim_release(ace); } krb5_cc_set_acl(context, tempccache, "kHEIMAttrBundleIdentifierACL", bundleacl); heim_release(bundleacl); } #endif ret = krb5_cc_move(context, tempccache, ccache); if (ret) { (void)krb5_cc_destroy(context, tempccache); krb5_err (context, 1, ret, "krb5_cc_move"); } if (switch_cache_flags) krb5_cc_switch(context, ccache); if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } if (enctype) free(enctype); krb5_init_creds_free(context, icc); krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); #ifdef __APPLE__ if (passwordItem) CFRelease(passwordItem); #endif return 0; }
//---------------------------------------------------------------------- // Authenticate to server as a daemon (i.e. using the keytab) //---------------------------------------------------------------------- int Condor_Auth_Kerberos :: init_daemon() { int code, rc = TRUE; priv_state priv; char * daemonPrincipal = 0; krb5_keytab keytab = 0; // init some member vars creds_ = (krb5_creds *) malloc(sizeof(krb5_creds)); keytabName_ = param(STR_KERBEROS_SERVER_KEYTAB); // needed for extracting service name char * tmpsname = 0; MyString sname; memset(creds_, 0, sizeof(krb5_creds)); //------------------------------------------ // Initialize the principal for daemon (properly :-) //------------------------------------------ // this means using a keytab to obtain a tgt. // // in krb5-1.2 and earlier this was done with krb5_get_in_tkt_keytab() // // in krb5-1.3 and // later this should be done with krb5_get_init_creds_keytab // select a server principal daemonPrincipal = param(STR_KERBEROS_SERVER_PRINCIPAL); if (daemonPrincipal) { // it was defined explicitly in the config file if ((code = krb5_parse_name(krb_context_, daemonPrincipal, &krb_principal_))) { free(daemonPrincipal); goto error; } } else { // not defined in config, let's construct one from a service name daemonPrincipal = param(STR_KERBEROS_SERVER_SERVICE); if (!daemonPrincipal) { // use the host credential if no service was specified daemonPrincipal = strdup(STR_DEFAULT_CONDOR_SERVICE); } if ((code = krb5_sname_to_principal(krb_context_, NULL, daemonPrincipal, KRB5_NT_SRV_HST, &krb_principal_))) { free(daemonPrincipal); goto error; } } free(daemonPrincipal); daemonPrincipal = 0; dprintf_krb5_principal( D_SECURITY, "init_daemon: client principal is '%s'\n", krb_principal_); if (keytabName_) { dprintf(D_SECURITY, "init_daemon: Using keytab %s\n", keytabName_); code = krb5_kt_resolve(krb_context_, keytabName_, &keytab); } else { char defktname[_POSIX_PATH_MAX]; krb5_kt_default_name(krb_context_, defktname, _POSIX_PATH_MAX); dprintf(D_SECURITY, "init_daemon: Using default keytab %s\n", defktname); code = krb5_kt_default(krb_context_, &keytab); } if (code) { goto error; } // get the service name out of the member variable server_ tmpsname = 0; code = krb5_unparse_name(krb_context_, server_, &tmpsname); if (code) { goto error; } // copy it into a mystring for stack cleanup purposes sname = tmpsname; free (tmpsname); dprintf(D_SECURITY, "init_daemon: Trying to get tgt credential for service %s\n", sname.Value()); priv = set_root_priv(); // Get the old privilige code = krb5_get_init_creds_keytab(krb_context_, creds_, krb_principal_, keytab, 0, const_cast<char*>(sname.Value()), 0); set_priv(priv); if(code) { goto error; } dprintf_krb5_principal( D_SECURITY, "init_daemon: gic_kt creds_->client is '%s'\n", creds_->client ); dprintf_krb5_principal( D_SECURITY, "init_daemon: gic_kt creds_->server is '%s'\n", creds_->server ); dprintf(D_SECURITY, "Success..........................\n"); rc = TRUE; goto cleanup; error: dprintf(D_ALWAYS, "AUTH_ERROR: %s\n", error_message(code)); rc = FALSE; cleanup: if (keytab) { krb5_kt_close(krb_context_, keytab); } return rc; }
OM_uint32 Curl_gss_init_sec_context( struct connectdata *conn, OM_uint32 * minor_status, gss_ctx_id_t * context, gss_name_t target_name, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_buffer_t output_token, OM_uint32 * ret_flags) { krb5_context krb_context = NULL; /* Kerberos context object */ krb5_ccache ccache = NULL; krb5_creds creds; krb5_get_init_creds_opt *opts = NULL; krb5_principal principal = NULL; krb5_keytab ktab = NULL; OM_uint32 min_stat, maj_stat; char *cachename = NULL; char *keytabfile = ""; OM_uint32 major_status; struct SessionHandle *data = conn->data; int ret; OM_uint32 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; conn->data->curl_gss_creds = GSS_C_NO_CREDENTIAL; memset(&creds, 0, sizeof(creds)); if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { #ifdef GSS_C_DELEG_POLICY_FLAG req_flags |= GSS_C_DELEG_POLICY_FLAG; #else infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " "compiled in\n"); #endif } if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) req_flags |= GSS_C_DELEG_FLAG; if((ret = krb5_init_context(&krb_context)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } if ((ret = krb5_parse_name(krb_context, conn->user, &principal)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } if ((ret = krb5_get_init_creds_opt_alloc (krb_context , &opts)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } if (conn->bits.user_keytab) { infof(data, "KRB5_DATA: Keytab location is %s \n", conn->keytab_location); if ((ret = krb5_kt_resolve(krb_context, conn->keytab_location, &ktab)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } if ((ret = krb5_get_init_creds_keytab(krb_context, &creds, principal, ktab, 0, NULL, opts)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } } else if(conn->bits.user_passwd) { infof(data,"KRB5_DATA: Using the user password method \n"); if ((ret = krb5_get_init_creds_password(krb_context,&creds,principal,conn->passwd,NULL,NULL,0,NULL,opts)) != 0 ) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } } else if(conn->bits.credential_cache) { infof(data, "Resolving given credential cache \n"); infof(data, "KRB5_DATA: Credential cache location is %s \n", conn->credential_cache); if ((ret = krb5_cc_resolve(krb_context, conn->credential_cache, &ccache))!=0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } } else if(conn->data->isIntermediateServer) { infof(data, "KRB5_DATA: Curl is carrying a gss credential \n"); major_status = gss_init_sec_context(minor_status, conn->data->deleg_gss_creds, /* cred_handle */ context, target_name, GSS_C_NO_OID, /* mech_type */ req_flags, 0, /* time_req */ input_chan_bindings, input_token, NULL, /* actual_mech_type */ output_token, ret_flags, NULL /* time_rec */); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return major_status; } else { infof(data, "KRB5_DATA: Passed no password/keytab location, using default credentials\n "); conn->data->curl_gss_creds = GSS_C_NO_CREDENTIAL; major_status = gss_init_sec_context(minor_status, conn->data->curl_gss_creds, /* cred_handle */ context, target_name, GSS_C_NO_OID, /* mech_type */ req_flags, 0, /* time_req */ input_chan_bindings, input_token, NULL, /* actual_mech_type */ output_token, ret_flags, NULL /* time_rec */); curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); return major_status; } if(!conn->bits.credential_cache) { infof(data, "Creating new credential cache, since none specified \n"); if((ret = krb5_cc_new_unique( krb_context, "MEMORY", NULL, &ccache)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data_memory(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } infof(data, "Initializing credential cache \n"); if ((ret = krb5_cc_initialize(krb_context, ccache, principal))!=0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data_memory(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } infof(data, "Storing credential within credential cache \n"); if ((ret = krb5_cc_store_cred(krb_context,ccache,&creds)) != 0) { curl_krb5_print_error_message(krb_context, ret, data); curl_krb5_free_local_data_memory(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED ; } } infof(data, "Attempting to import the credential \n"); if ((maj_stat = gss_krb5_import_cred(&min_stat, ccache, principal, NULL, &conn->data->curl_gss_creds))!=0) { infof(data, "Importing krb5 credential into gss credentials failed\n"); curl_krb5_print_error_message(krb_context, min_stat, data); if(conn->bits.credential_cache) curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); else curl_krb5_free_local_data_memory(krb_context, ccache, &creds, principal, opts, ktab); return CURLE_KERBEROS_AUTH_FAILED; } infof(data, "Able to convert the credential \n"); infof(data, "Attempting init sec context \n"); major_status = gss_init_sec_context(minor_status, conn->data->curl_gss_creds, /* cred_handle */ context, target_name, GSS_C_NO_OID, /* mech_type */ req_flags, 0, /* time_req */ input_chan_bindings, input_token, NULL, /* actual_mech_type */ output_token, ret_flags, NULL /* time_rec */); if(conn->bits.credential_cache) curl_krb5_free_local_data(krb_context, ccache, &creds, principal, opts, ktab); else curl_krb5_free_local_data_memory(krb_context, ccache, &creds, principal, opts, ktab); return major_status; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; void *kadm_handle; kadm5_server_context *server_context; kadm5_config_params conf; krb5_socket_t signal_fd, listen_fd; int log_fd; slave *slaves = NULL; uint32_t current_version = 0, old_version = 0; uint32_t current_tstamp = 0; krb5_keytab keytab; char **files; int aret; int optidx = 0; int restarter_fd = -1; struct stat st; setprogname(argv[0]); if (getarg(args, num_args, argc, argv, &optidx)) krb5_std_usage(1, args, num_args); if (help_flag) krb5_std_usage(0, args, num_args); if (version_flag) { print_version(NULL); exit(0); } if (detach_from_console && daemon_child == -1) roken_detach_prep(argc, argv, "--daemon-child"); rk_pidfile(NULL); ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_context failed: %d", ret); setup_signal(); if (config_file == NULL) { aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); if (aret == -1 || config_file == NULL) errx(1, "out of memory"); } ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(context, 1, ret, "getting configuration files"); ret = krb5_set_config_files(context, files); krb5_free_config_files(files); if (ret) krb5_err(context, 1, ret, "reading configuration files"); init_stats_names(context); time_before_gone = parse_time (slave_time_gone, "s"); if (time_before_gone < 0) krb5_errx (context, 1, "couldn't parse time: %s", slave_time_gone); time_before_missing = parse_time (slave_time_missing, "s"); if (time_before_missing < 0) krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing); krb5_openlog(context, "ipropd-master", &log_facility); krb5_set_warn_dest(context, log_facility); ret = krb5_kt_register(context, &hdb_get_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); ret = krb5_kt_resolve(context, keytab_str, &keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str); memset(&conf, 0, sizeof(conf)); if(realm) { conf.mask |= KADM5_CONFIG_REALM; conf.realm = realm; } ret = kadm5_init_with_skey_ctx (context, KADM5_ADMIN_SERVICE, NULL, KADM5_ADMIN_SERVICE, &conf, 0, 0, &kadm_handle); if (ret) krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); server_context = (kadm5_server_context *)kadm_handle; log_fd = open (server_context->log_context.log_file, O_RDONLY, 0); if (log_fd < 0) krb5_err (context, 1, errno, "open %s", server_context->log_context.log_file); if (fstat(log_fd, &st) == -1) krb5_err(context, 1, errno, "stat %s", server_context->log_context.log_file); if (flock(log_fd, LOCK_SH) == -1) krb5_err(context, 1, errno, "shared flock %s", server_context->log_context.log_file); kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, ¤t_version, ¤t_tstamp); flock(log_fd, LOCK_UN); signal_fd = make_signal_socket (context); listen_fd = make_listen_socket (context, port_str); krb5_warnx(context, "ipropd-master started at version: %lu", (unsigned long)current_version); roken_detach_finish(NULL, daemon_child); restarter_fd = restarter(context, NULL); while (exit_flag == 0){ slave *p; fd_set readset; int max_fd = 0; struct timeval to = {30, 0}; uint32_t vers; struct stat st2;; #ifndef NO_LIMIT_FD_SETSIZE if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE || restarter_fd >= FD_SETSIZE) krb5_errx (context, IPROPD_RESTART, "fd too large"); #endif FD_ZERO(&readset); FD_SET(signal_fd, &readset); max_fd = max(max_fd, signal_fd); FD_SET(listen_fd, &readset); max_fd = max(max_fd, listen_fd); if (restarter_fd > -1) { FD_SET(restarter_fd, &readset); max_fd = max(max_fd, restarter_fd); } for (p = slaves; p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) continue; FD_SET(p->fd, &readset); max_fd = max(max_fd, p->fd); } ret = select (max_fd + 1, &readset, NULL, NULL, &to); if (ret < 0) { if (errno == EINTR) continue; else krb5_err (context, IPROPD_RESTART, errno, "select"); } if (stat(server_context->log_context.log_file, &st2) == -1) { krb5_warn(context, errno, "could not stat log file by path"); st2 = st; } if (st2.st_dev != st.st_dev || st2.st_ino != st.st_ino) { (void) close(log_fd); log_fd = open(server_context->log_context.log_file, O_RDONLY, 0); if (log_fd < 0) krb5_err(context, 1, IPROPD_RESTART_SLOW, "open %s", server_context->log_context.log_file); if (fstat(log_fd, &st) == -1) krb5_err(context, IPROPD_RESTART_SLOW, errno, "stat %s", server_context->log_context.log_file); if (flock(log_fd, LOCK_SH) == -1) krb5_err(context, IPROPD_RESTART, errno, "shared flock %s", server_context->log_context.log_file); kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, ¤t_version, ¤t_tstamp); flock(log_fd, LOCK_UN); } if (ret == 0) { /* Recover from failed transactions */ if (kadm5_log_init_nb(server_context) == 0) kadm5_log_end(server_context); if (flock(log_fd, LOCK_SH) == -1) krb5_err(context, IPROPD_RESTART, errno, "could not lock log file"); kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, ¤t_version, ¤t_tstamp); flock(log_fd, LOCK_UN); if (current_version > old_version) { krb5_warnx(context, "Missed a signal, updating slaves %lu to %lu", (unsigned long)old_version, (unsigned long)current_version); for (p = slaves; p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) continue; send_diffs (server_context, p, log_fd, database, current_version, current_tstamp); } old_version = current_version; } } if (ret && FD_ISSET(restarter_fd, &readset)) { exit_flag = SIGTERM; break; } if (ret && FD_ISSET(signal_fd, &readset)) { #ifndef NO_UNIX_SOCKETS struct sockaddr_un peer_addr; #else struct sockaddr_storage peer_addr; #endif socklen_t peer_len = sizeof(peer_addr); if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0, (struct sockaddr *)&peer_addr, &peer_len) < 0) { krb5_warn (context, errno, "recvfrom"); continue; } --ret; assert(ret >= 0); old_version = current_version; if (flock(log_fd, LOCK_SH) == -1) krb5_err(context, IPROPD_RESTART, errno, "shared flock %s", server_context->log_context.log_file); kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, ¤t_version, ¤t_tstamp); flock(log_fd, LOCK_UN); if (current_version != old_version) { /* * If current_version < old_version then the log got * truncated and we'll end up doing full propagations. * * Truncating the log when the current version is * numerically small can lead to race conditions. * Ideally we should identify log versions as * {init_or_trunc_time, vno}, then we could not have any * such race conditions, but this would either require * breaking backwards compatibility for the protocol or * adding new messages to it. */ krb5_warnx(context, "Got a signal, updating slaves %lu to %lu", (unsigned long)old_version, (unsigned long)current_version); for (p = slaves; p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) continue; send_diffs (server_context, p, log_fd, database, current_version, current_tstamp); } } else { krb5_warnx(context, "Got a signal, but no update in log version %lu", (unsigned long)current_version); } } for(p = slaves; p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) continue; if (ret && FD_ISSET(p->fd, &readset)) { --ret; assert(ret >= 0); if(process_msg (server_context, p, log_fd, database, current_version, current_tstamp)) slave_dead(context, p); } else if (slave_gone_p (p)) slave_dead(context, p); else if (slave_missing_p (p)) send_are_you_there (context, p); } if (ret && FD_ISSET(listen_fd, &readset)) { add_slave (context, keytab, &slaves, listen_fd); --ret; assert(ret >= 0); } write_stats(context, slaves, current_version); } if(exit_flag == SIGINT || exit_flag == SIGTERM) krb5_warnx(context, "%s terminated", getprogname()); #ifdef SIGXCPU else if(exit_flag == SIGXCPU) krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); #endif else krb5_warnx(context, "%s unexpected exit reason: %ld", getprogname(), (long)exit_flag); write_master_down(context); return 0; }
static int verify_krb5_tgt(krb5_context context, rlm_krb5_t *inst, const char *user, krb5_ccache ccache) { int rcode; int ret; char phost[BUFSIZ]; krb5_principal princ; krb5_keyblock *keyblock = 0; krb5_data packet, *server; krb5_auth_context auth_context = NULL; krb5_keytab keytab; char service[SERVICE_NAME_LEN] = "host"; char *server_name = NULL; char *keytab_name; /* krb5_kt_read_service_key lacks const qualifier */ memcpy(&keytab_name, &inst->keytab, sizeof(keytab_name)); if (inst->service_princ != NULL) { server_name = strchr(inst->service_princ, '/'); if (server_name != NULL) { *server_name = '\0'; } strlcpy(service, inst->service_princ, sizeof(service)); if (server_name != NULL) { *server_name = '/'; server_name++; } } memset(&packet, 0, sizeof packet); ret = krb5_sname_to_principal(context, server_name, service, KRB5_NT_SRV_HST, &princ); if (ret) { radlog(L_DBG, "rlm_krb5: [%s] krb5_sname_to_principal failed: %s", user, error_message(ret)); return RLM_MODULE_REJECT; } server = krb5_princ_component(c, princ, 1); if (!server) { radlog(L_DBG, "rlm_krb5: [%s] krb5_princ_component failed.", user); return RLM_MODULE_REJECT; } strlcpy(phost, server->data, sizeof(phost)); /* * Do we have host/<host> keys? * (use default/configured keytab, kvno IGNORE_VNO to get the * first match, and enctype is currently ignored anyhow.) */ ret = krb5_kt_read_service_key(context, keytab_name, princ, 0, ENCTYPE_DES_CBC_MD5, &keyblock); if (ret) { /* Keytab or service key does not exist */ radlog(L_DBG, "rlm_krb5: verify_krb_v5_tgt: host key not found : %s", error_message(ret)); return RLM_MODULE_OK; } if (keyblock) krb5_free_keyblock(context, keyblock); /* * Talk to the kdc and construct the ticket. */ ret = krb5_build_auth_context(inst, context, &auth_context); if (ret) { radlog(L_DBG, "rlm_krb5: [%s] krb5_build_auth_context() failed: %s", user, error_message(ret)); rcode = RLM_MODULE_REJECT; goto cleanup; } ret = krb5_mk_req(context, &auth_context, 0, service, phost, NULL, ccache, &packet); if (auth_context) { krb5_auth_con_free(context, auth_context); auth_context = NULL; /* setup for rd_req */ } if (ret) { radlog(L_DBG, "rlm_krb5: [%s] krb5_mk_req() failed: %s", user, error_message(ret)); rcode = RLM_MODULE_REJECT; goto cleanup; } if (keytab_name != NULL) { ret = krb5_kt_resolve(context, keytab_name, &keytab); } if (keytab_name == NULL || ret) { ret = krb5_kt_default(context, &keytab); } /* Hmm? The keytab was just fine a second ago! */ if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_kt_resolve failed: %s", user, error_message(ret)); rcode = RLM_MODULE_REJECT; goto cleanup; } /* Try to use the ticket. */ ret = krb5_build_auth_context(inst, context, &auth_context); if (ret) { radlog(L_DBG, "rlm_krb5: [%s] krb5_build_auth_context() failed: %s", user, error_message(ret)); rcode = RLM_MODULE_REJECT; goto cleanup; } ret = krb5_rd_req(context, &auth_context, &packet, princ, keytab, NULL, NULL); if (auth_context) krb5_auth_con_free(context, auth_context); krb5_kt_close(context, keytab); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_rd_req() failed: %s", user, error_message(ret)); rcode = RLM_MODULE_REJECT; } else { rcode = RLM_MODULE_OK; } cleanup: if (packet.data) { krb5_free_data_contents(context, &packet); } return rcode; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(2, ("Failed to init kerberos context\n")); return krberr; } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(2, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) goto done; } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(4, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } if (krberr) { DEBUG(0, ("Failed to read keytab file: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(2, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(2, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(0, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", keytab_name, sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_initialize(context, ccache, kprinc); if (krberr) { DEBUG(2, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(2, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(2, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }
OM_uint32 _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, krb5_ccache id, krb5_principal keytab_principal, krb5_keytab keytab, gss_cred_id_t *cred) { krb5_context context; krb5_error_code kret; gsskrb5_cred handle; OM_uint32 ret; *cred = NULL; GSSAPI_KRB5_INIT (&context); handle = calloc(1, sizeof(*handle)); if (handle == NULL) { _gsskrb5_clear_status (); *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); handle->usage = 0; if (id) { char *str; handle->usage |= GSS_C_INITIATE; kret = krb5_cc_get_principal(context, id, &handle->principal); if (kret) { free(handle); *minor_status = kret; return GSS_S_FAILURE; } if (keytab_principal) { krb5_boolean match; match = krb5_principal_compare(context, handle->principal, keytab_principal); if (match == FALSE) { krb5_free_principal(context, handle->principal); free(handle); _gsskrb5_clear_status (); *minor_status = EINVAL; return GSS_S_FAILURE; } } ret = __gsskrb5_ccache_lifetime(minor_status, context, id, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_free_principal(context, handle->principal); free(handle); return ret; } kret = krb5_cc_get_full_name(context, id, &str); if (kret) goto out; kret = krb5_cc_resolve(context, str, &handle->ccache); free(str); if (kret) goto out; } if (keytab) { char *str; handle->usage |= GSS_C_ACCEPT; if (keytab_principal && handle->principal == NULL) { kret = krb5_copy_principal(context, keytab_principal, &handle->principal); if (kret) goto out; } kret = krb5_kt_get_full_name(context, keytab, &str); if (kret) goto out; kret = krb5_kt_resolve(context, str, &handle->keytab); free(str); if (kret) goto out; } if (id || keytab) { ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { kret = *minor_status; goto out; } } *minor_status = 0; *cred = (gss_cred_id_t)handle; return GSS_S_COMPLETE; out: gss_release_oid_set(minor_status, &handle->mechanisms); if (handle->ccache) krb5_cc_close(context, handle->ccache); if (handle->keytab) krb5_kt_close(context, handle->keytab); if (handle->principal) krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = kret; return GSS_S_FAILURE; }
/* * Validate user/pass (Heimdal) */ static rlm_rcode_t krb5_auth(void *instance, REQUEST *request) { rlm_krb5_t *inst = instance; rlm_rcode_t rcode; krb5_error_code ret; krb5_principal client; krb5_ccache ccache; krb5_keytab keytab; krb5_verify_opt options; krb5_context *context = NULL; /* * See above in MIT krb5_auth */ ret = krb5_copy_context(*(inst->context), context); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Error cloning krb5 context: %s", inst->xlat_name, error_message(ret)); return RLM_MODULE_FAIL; } /* * Setup krb5_verify_user options * * Not entirely sure this is necessary, but as we use context * to get the cache handle, we probably do have to do this with * the cloned context. */ krb5_cc_default(*context, &ccache); krb5_verify_opt_init(&options); krb5_verify_opt_set_ccache(&options, ccache); memset(&keytab, 0, sizeof(keytab)); ret = inst->keytabname ? krb5_kt_resolve(*context, inst->keytabname, &keytab) : krb5_kt_default(*context, &keytab); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Resolving keytab failed: %s", inst->xlat_name, error_message(ret)); goto cleanup; } krb5_verify_opt_set_keytab(&options, keytab); krb5_verify_opt_set_secure(&options, TRUE); if (inst->service) { krb5_verify_opt_set_service(&options, inst->service); } rcode = krb5_parse_user(inst, request, &client); if (rcode != RLM_MODULE_OK) goto cleanup; /* * Verify the user, using the options we set in instantiate */ ret = krb5_verify_user_opt(*context, client, request->password->vp_strvalue, &options); if (ret) { switch (ret) { case KRB5_LIBOS_BADPWDMATCH: case KRB5KRB_AP_ERR_BAD_INTEGRITY: RDEBUG("Provided password was incorrect: %s", error_message(ret)); rcode = RLM_MODULE_REJECT; break; case KRB5KDC_ERR_KEY_EXP: case KRB5KDC_ERR_CLIENT_REVOKED: case KRB5KDC_ERR_SERVICE_REVOKED: RDEBUG("Account has been locked out: %s", error_message(ret)); rcode = RLM_MODULE_USERLOCK; break; case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: RDEBUG("User not found: %s", error_message(ret)); rcode = RLM_MODULE_NOTFOUND; default: radlog(L_ERR, "rlm_krb5 (%s): Verifying user failed: " "%s", inst->xlat_name, error_message(ret)); rcode = RLM_MODULE_FAIL; break; } goto cleanup; } cleanup: krb5_free_context(*context); krb5_kt_close(*context, keytab); return rcode; }
/* * Given the plugin options, a Kerberos context, and a pointer to krb5_ccache * storage, initialize a memory cache using the configured keytab to obtain * initial credentials. Returns a Kerberos status code. */ static krb5_error_code get_creds(kadm5_hook_modinfo *config, krb5_context ctx, krb5_ccache *cc) { krb5_error_code code; krb5_keytab kt = NULL; krb5_principal princ = NULL; krb5_get_init_creds_opt *opts = NULL; krb5_creds creds; bool creds_valid = false; const char *realm UNUSED; /* Initialize the credential cache pointer to NULL. */ *cc = NULL; /* Ensure the configuration is sane. */ CHECK_CONFIG(ad_keytab); CHECK_CONFIG(ad_principal); /* Resolve the keytab and principal used to get credentials. */ code = krb5_kt_resolve(ctx, config->ad_keytab, &kt); if (code != 0) goto fail; code = krb5_parse_name(ctx, config->ad_principal, &princ); if (code != 0) goto fail; /* Set our credential acquisition options. */ code = krb5_get_init_creds_opt_alloc(ctx, &opts); if (code != 0) goto fail; realm = krb5_principal_get_realm(ctx, princ); krb5_get_init_creds_opt_set_default_flags(ctx, "krb5-sync", realm, opts); /* Obtain credentials. */ memset(&creds, 0, sizeof(creds)); code = krb5_get_init_creds_keytab(ctx, &creds, princ, kt, 0, NULL, opts); if (code != 0) goto fail; krb5_get_init_creds_opt_free(ctx, opts); opts = NULL; krb5_kt_close(ctx, kt); kt = NULL; creds_valid = true; /* Open and initialize the credential cache. */ code = krb5_cc_resolve(ctx, CACHE_NAME, cc); if (code != 0) goto fail; code = krb5_cc_initialize(ctx, *cc, princ); if (code == 0) code = krb5_cc_store_cred(ctx, *cc, &creds); if (code != 0) { krb5_cc_close(ctx, *cc); *cc = NULL; goto fail; } /* Clean up and return success. */ krb5_free_cred_contents(ctx, &creds); krb5_free_principal(ctx, princ); return 0; fail: if (kt != NULL) krb5_kt_close(ctx, kt); if (princ != NULL) krb5_free_principal(ctx, princ); if (opts != NULL) krb5_get_init_creds_opt_free(ctx, opts); if (creds_valid) krb5_free_cred_contents(ctx, &creds); return code; }
/* * Validate userid/passwd (MIT) */ static rlm_rcode_t krb5_auth(void *instance, REQUEST *request) { rlm_krb5_t *inst = instance; rlm_rcode_t rcode; krb5_error_code ret; krb5_principal client; krb5_creds init_creds; krb5_keytab keytab; krb5_context *context = NULL; /* * All the snippets on threadsafety say that individual threads * must each use their own copy of context. * * As we don't have any per thread instantiation, we either have * to clone inst->context on every request, or use the connection * API. * * @todo Use the connection API (3.0 only). */ ret = krb5_copy_context(*(inst->context), context); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Error cloning krb5 context: %s", inst->xlat_name, error_message(ret)); return RLM_MODULE_FAIL; } /* * Check we have all the required VPs, and convert the username * into a principal. */ rcode = krb5_parse_user(inst, request, &client); if (rcode != RLM_MODULE_OK) goto cleanup; /* * Retrieve the TGT from the TGS/KDC and check we can decrypt it. */ memset(&init_creds, 0, sizeof(init_creds)); ret = krb5_get_init_creds_password(*context, &init_creds, client, request->password->vp_strvalue, NULL, NULL, 0, NULL, inst->gic_options); if (ret) { error: switch (ret) { case KRB5_LIBOS_BADPWDMATCH: case KRB5KRB_AP_ERR_BAD_INTEGRITY: RDEBUG("Provided password was incorrect: %s", error_message(ret)); rcode = RLM_MODULE_REJECT; break; case KRB5KDC_ERR_KEY_EXP: case KRB5KDC_ERR_CLIENT_REVOKED: case KRB5KDC_ERR_SERVICE_REVOKED: RDEBUG("Account has been locked out: %s", error_message(ret)); rcode = RLM_MODULE_USERLOCK; break; case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: RDEBUG("User not found: %s", error_message(ret)); rcode = RLM_MODULE_NOTFOUND; default: radlog(L_ERR, "rlm_krb5 (%s): Failed getting/verifying " "credentials: %s", inst->xlat_name, error_message(ret)); rcode = RLM_MODULE_FAIL; break; } goto cleanup; } RDEBUG("Successfully retrieved and decrypted TGT"); memset(&keytab, 0, sizeof(keytab)); ret = inst->keytabname ? krb5_kt_resolve(*context, inst->keytabname, &keytab) : krb5_kt_default(*context, &keytab); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Resolving keytab failed: %s", inst->xlat_name, error_message(ret)); goto cleanup; } ret = krb5_verify_init_creds(*context, &init_creds, inst->server, keytab, NULL, inst->vic_options); if (ret) goto error; cleanup: krb5_free_cred_contents(*context, &init_creds); krb5_free_context(*context); krb5_kt_close(*context, keytab); return rcode; }
static krb5_error_code ccache_init_system(void) { kcm_ccache ccache; krb5_error_code ret; if (system_cache_name == NULL) system_cache_name = kcm_system_config_get_string("cc_name"); ret = kcm_ccache_new(kcm_context, system_cache_name ? system_cache_name : "SYSTEM", &ccache); if (ret) return ret; ccache->flags |= KCM_FLAGS_OWNER_IS_SYSTEM; ccache->flags |= KCM_FLAGS_USE_KEYTAB; ret = parse_owners(ccache); if (ret) return ret; ret = krb5_parse_name(kcm_context, system_principal, &ccache->client); if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } if (system_server == NULL) system_server = kcm_system_config_get_string("server"); if (system_server != NULL) { ret = krb5_parse_name(kcm_context, system_server, &ccache->server); if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } } if (system_keytab == NULL) system_keytab = kcm_system_config_get_string("keytab_name"); if (system_keytab != NULL) { ret = krb5_kt_resolve(kcm_context, system_keytab, &ccache->key.keytab); } else { ret = krb5_kt_default(kcm_context, &ccache->key.keytab); } if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } if (renew_life == NULL) renew_life = kcm_system_config_get_string("renew_life"); if (renew_life == NULL) renew_life = "1 month"; if (renew_life != NULL) { ccache->renew_life = parse_time(renew_life, "s"); if (ccache->renew_life < 0) { kcm_release_ccache(kcm_context, ccache); return EINVAL; } } if (ticket_life == NULL) ticket_life = kcm_system_config_get_string("ticket_life"); if (ticket_life != NULL) { ccache->tkt_life = parse_time(ticket_life, "s"); if (ccache->tkt_life < 0) { kcm_release_ccache(kcm_context, ccache); return EINVAL; } } if (system_perms == NULL) system_perms = kcm_system_config_get_string("mode"); if (system_perms != NULL) { int mode; if (sscanf(system_perms, "%o", &mode) != 1) return EINVAL; ccache->mode = mode; } if (disallow_getting_krbtgt == -1) { disallow_getting_krbtgt = krb5_config_get_bool_default(kcm_context, NULL, FALSE, "kcm", "disallow-getting-krbtgt", NULL); } /* enqueue default actions for credentials cache */ ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL); kcm_release_ccache(kcm_context, ccache); /* retained by event queue */ return ret; }
int main(int argc, char **argv) { krb5_context context; krb5_error_code ret; int optidx = 0; const char *principal, *keytab, *ccache; krb5_ccache id; krb5_keytab kt; krb5_principal sprincipal; setprogname(argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc < 3) usage(1); principal = argv[0]; keytab = argv[1]; ccache = argv[2]; ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); ret = krb5_cc_resolve(context, ccache, &id); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve"); ret = krb5_parse_name(context, principal, &sprincipal); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_kt_resolve(context, keytab, &kt); if (ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); test_ap(context, sprincipal, kt, id, 0); test_ap(context, sprincipal, kt, id, AP_OPTS_MUTUAL_REQUIRED); krb5_cc_close(context, id); krb5_kt_close(context, kt); krb5_free_principal(context, sprincipal); krb5_free_context(context); return ret; }
/* Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"), ** and krb5 AP_REQ message & message length, ** Return Kerberos session key and client principle ** to SSL Server in KSSL_CTX *kssl_ctx. ** ** 19990702 VRS Started. */ krb5_error_code kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx, /* IN */ krb5_data *indata, /* OUT */ krb5_ticket_times *ttimes, /* OUT */ KSSL_ERR *kssl_err ) { krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; static krb5_context krb5context = NULL; static krb5_auth_context krb5auth_context = NULL; krb5_ticket *krb5ticket = NULL; KRB5_TKTBODY *asn1ticket = NULL; const unsigned char *p; krb5_keytab krb5keytab = NULL; krb5_keytab_entry kt_entry; krb5_principal krb5server; krb5_rcache rcache = NULL; kssl_err_set(kssl_err, 0, ""); if (!kssl_ctx) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n"); goto err; } #ifdef KSSL_DEBUG printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name)); #endif /* KSSL_DEBUG */ if (!krb5context && (krb5rc = krb5_init_context(&krb5context))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_init_context() fails.\n"); goto err; } if (krb5auth_context && (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_auth_con_free() fails.\n"); goto err; } else krb5auth_context = NULL; if (!krb5auth_context && (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_auth_con_init() fails.\n"); goto err; } if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context, &rcache))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_auth_con_getrcache() fails.\n"); goto err; } if ((krb5rc = krb5_sname_to_principal(krb5context, NULL, (kssl_ctx->service_name) ? kssl_ctx->service_name : KRB5SVC, KRB5_NT_SRV_HST, &krb5server)) != 0) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_sname_to_principal() fails.\n"); goto err; } if (rcache == NULL) { if ((krb5rc = krb5_get_server_rcache(krb5context, krb5_princ_component(krb5context, krb5server, 0), &rcache))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_get_server_rcache() fails.\n"); goto err; } } if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache))) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_auth_con_setrcache() fails.\n"); goto err; } /* kssl_ctx->keytab_file == NULL ==> use Kerberos default */ if (kssl_ctx->keytab_file) { krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file, &krb5keytab); if (krb5rc) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_kt_resolve() fails.\n"); goto err; } } else { krb5rc = krb5_kt_default(krb5context, &krb5keytab); if (krb5rc) { kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "krb5_kt_default() fails.\n"); goto err; } } /* Actual Kerberos5 krb5_recvauth() has initial conversation here ** o check KRB5_SENDAUTH_BADAUTHVERS ** unless KRB5_RECVAUTH_SKIP_VERSION ** o check KRB5_SENDAUTH_BADAPPLVERS ** o send "0" msg if all OK */ /* 20010411 was using AP_REQ instead of true KerberosWrapper ** ** if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, ** &krb5in_data, krb5server, krb5keytab, ** &ap_option, &krb5ticket)) != 0) { Error } */ p = (unsigned char *)indata->data; if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p, (long)indata->length)) == NULL) { (void) snprintf(kssl_err->text, KSSL_ERR_MAX, "d2i_KRB5_TICKET() ASN.1 decode failure.\n"); kssl_err->reason = SSL_R_KRB5_S_RD_REQ; goto err; } /* Was: krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */ if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket, kssl_err)) != 0) { (void) snprintf(kssl_err->text, KSSL_ERR_MAX, "Error converting ASN.1 ticket to krb5_ticket.\n"); kssl_err->reason = SSL_R_KRB5_S_RD_REQ; goto err; } if (!krb5_principal_compare(krb5context, krb5server, krb5ticket->server)) { krb5rc = KRB5_PRINC_NOMATCH; (void) snprintf(kssl_err->text, KSSL_ERR_MAX, "server principal != ticket principal\n"); kssl_err->reason = SSL_R_KRB5_S_RD_REQ; goto err; } if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, krb5ticket->server, krb5ticket->enc_part.kvno, krb5ticket->enc_part.enctype, &kt_entry)) != 0) { (void) snprintf(kssl_err->text, KSSL_ERR_MAX, "krb5_kt_get_entry() fails with %x.\n", krb5rc); kssl_err->reason = SSL_R_KRB5_S_RD_REQ; goto err; } if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key, krb5ticket)) != 0) { (void) snprintf(kssl_err->text, KSSL_ERR_MAX, "krb5_decrypt_tkt_part() failed.\n"); kssl_err->reason = SSL_R_KRB5_S_RD_REQ; goto err; } else { krb5_kt_free_entry(krb5context, &kt_entry); #ifdef KSSL_DEBUG { int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs; printf("Decrypted ticket fields:\n"); printf("\tflags: %X, transit-type: %X", krb5ticket->enc_part2->flags, krb5ticket->enc_part2->transited.tr_type); print_krb5_data("\ttransit-data: ", &(krb5ticket->enc_part2->transited.tr_contents)); printf("\tcaddrs: %p, authdata: %p\n", krb5ticket->enc_part2->caddrs, krb5ticket->enc_part2->authorization_data); if (paddr) { printf("\tcaddrs:\n"); for (i = 0; paddr[i] != NULL; i++) { krb5_data d; d.length = paddr[i]->length; d.data = paddr[i]->contents; print_krb5_data("\t\tIP: ", &d); } } printf("\tstart/auth/end times: %d / %d / %d\n", krb5ticket->enc_part2->times.starttime, krb5ticket->enc_part2->times.authtime, krb5ticket->enc_part2->times.endtime); } #endif /* KSSL_DEBUG */ } krb5rc = KRB5_NO_TKT_SUPPLIED; if (!krb5ticket || !krb5ticket->enc_part2 || !krb5ticket->enc_part2->client || !krb5ticket->enc_part2->client->data || !krb5ticket->enc_part2->session) { kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, "bad ticket from krb5_rd_req.\n"); } else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT, &krb5ticket->enc_part2->client->realm, krb5ticket->enc_part2->client->data, krb5ticket->enc_part2->client->length)) { kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, "kssl_ctx_setprinc() fails.\n"); } else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session)) { kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, "kssl_ctx_setkey() fails.\n"); } else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID) { krb5rc = KRB5KRB_AP_ERR_TKT_INVALID; kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, "invalid ticket from krb5_rd_req.\n"); } else krb5rc = 0; kssl_ctx->enctype = krb5ticket->enc_part.enctype; ttimes->authtime = krb5ticket->enc_part2->times.authtime; ttimes->starttime = krb5ticket->enc_part2->times.starttime; ttimes->endtime = krb5ticket->enc_part2->times.endtime; ttimes->renew_till = krb5ticket->enc_part2->times.renew_till; err: #ifdef KSSL_DEBUG kssl_ctx_show(kssl_ctx); #endif /* KSSL_DEBUG */ if (asn1ticket) KRB5_TICKET_free((KRB5_TICKET *) asn1ticket); if (krb5keytab) krb5_kt_close(krb5context, krb5keytab); if (krb5ticket) krb5_free_ticket(krb5context, krb5ticket); if (krb5server) krb5_free_principal(krb5context, krb5server); return (krb5rc); }
krb5_error_code KRB5_LIB_FUNCTION krb5_kt_default(krb5_context context, krb5_keytab *id) { return krb5_kt_resolve (context, context->default_keytab, id); }
krb5_error_code smb_krb5_update_keytab(TALLOC_CTX *parent_ctx, krb5_context context, const char *keytab_name, const char *samAccountName, const char *realm, const char **SPNs, int num_SPNs, const char *saltPrincipal, const char *new_secret, const char *old_secret, int kvno, uint32_t supp_enctypes, bool delete_all_kvno, krb5_keytab *_keytab, const char **error_string) { krb5_keytab keytab; krb5_error_code ret; bool found_previous; TALLOC_CTX *tmp_ctx; krb5_principal *principals = NULL; if (keytab_name == NULL) { return ENOENT; } ret = krb5_kt_resolve(context, keytab_name, &keytab); if (ret) { *error_string = smb_get_krb5_error_message(context, ret, parent_ctx); return ret; } DEBUG(5, ("Opened keytab %s\n", keytab_name)); tmp_ctx = talloc_new(parent_ctx); if (!tmp_ctx) { return ENOMEM; } /* Get the principal we will store the new keytab entries under */ ret = principals_from_list(tmp_ctx, samAccountName, realm, SPNs, num_SPNs, context, &principals, error_string); if (ret != 0) { *error_string = talloc_asprintf(parent_ctx, "Failed to load principals from ldb message: %s\n", *error_string); goto done; } ret = remove_old_entries(tmp_ctx, kvno, principals, delete_all_kvno, context, keytab, &found_previous, error_string); if (ret != 0) { *error_string = talloc_asprintf(parent_ctx, "Failed to remove old principals from keytab: %s\n", *error_string); goto done; } if (!delete_all_kvno) { /* Create a new keytab. If during the cleanout we found * entires for kvno -1, then don't try and duplicate them. * Otherwise, add kvno, and kvno -1 */ ret = create_keytab(tmp_ctx, samAccountName, realm, saltPrincipal, kvno, new_secret, old_secret, supp_enctypes, principals, context, keytab, found_previous ? false : true, error_string); if (ret) { talloc_steal(parent_ctx, *error_string); } } if (ret == 0 && _keytab != NULL) { /* caller wants the keytab handle back */ *_keytab = keytab; } done: keytab_principals_free(context, principals); if (ret != 0 || _keytab == NULL) { krb5_kt_close(context, keytab); } talloc_free(tmp_ctx); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_auth_context ac = NULL; krb5_principal c1, c2; krb5_authenticator authent; krb5_keytab keytab; krb5_socket_t sock = rk_INVALID_SOCKET; HDB *db = NULL; int optidx = 0; char *tmp_db; krb5_log_facility *fac; int nprincs; setprogname(argv[0]); ret = krb5_init_context(&context); if(ret) exit(1); ret = krb5_openlog(context, "hpropd", &fac); if(ret) errx(1, "krb5_openlog"); krb5_set_warn_dest(context, fac); if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(local_realm != NULL) krb5_set_default_realm(context, local_realm); if(help_flag) usage(0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc != 0) usage(1); if (database == NULL) database = hdb_default_db(context); if(from_stdin) { sock = STDIN_FILENO; } else { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; socklen_t sin_len = sizeof(ss); char addr_name[256]; krb5_ticket *ticket; char *server; sock = STDIN_FILENO; #ifdef SUPPORT_INETD if (inetd_flag == -1) { if (getpeername (sock, sa, &sin_len) < 0) { inetd_flag = 0; } else { inetd_flag = 1; } } #else inetd_flag = 0; #endif if (!inetd_flag) { mini_inetd (krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT), &sock); } sin_len = sizeof(ss); if(getpeername(sock, sa, &sin_len) < 0) krb5_err(context, 1, errno, "getpeername"); if (inet_ntop(sa->sa_family, socket_get_address (sa), addr_name, sizeof(addr_name)) == NULL) strlcpy (addr_name, "unknown address", sizeof(addr_name)); krb5_log(context, fac, 0, "Connection from %s", addr_name); ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); if (ktname != NULL) { ret = krb5_kt_resolve(context, ktname, &keytab); if (ret) krb5_err (context, 1, ret, "krb5_kt_resolve %s", ktname); } else { ret = krb5_kt_default (context, &keytab); if (ret) krb5_err (context, 1, ret, "krb5_kt_default"); } ret = krb5_recvauth(context, &ac, &sock, HPROP_VERSION, NULL, 0, keytab, &ticket); if(ret) krb5_err(context, 1, ret, "krb5_recvauth"); ret = krb5_unparse_name(context, ticket->server, &server); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name"); if (strncmp(server, "hprop/", 5) != 0) krb5_errx(context, 1, "ticket not for hprop (%s)", server); free(server); krb5_free_ticket (context, ticket); ret = krb5_auth_con_getauthenticator(context, ac, &authent); if(ret) krb5_err(context, 1, ret, "krb5_auth_con_getauthenticator"); ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL); if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); _krb5_principalname2krb5_principal(context, &c2, authent->cname, authent->crealm); if(!krb5_principal_compare(context, c1, c2)) { char *s; ret = krb5_unparse_name(context, c2, &s); if (ret) s = "unparseable name"; krb5_errx(context, 1, "Unauthorized connection from %s", s); } krb5_free_principal(context, c1); krb5_free_principal(context, c2); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); } if(!print_dump) { asprintf(&tmp_db, "%s~", database); ret = hdb_create(context, &db, tmp_db); if(ret) krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db); ret = db->hdb_open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600); if(ret) krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db); } nprincs = 0; while(1){ krb5_data data; hdb_entry_ex entry; if(from_stdin) { ret = krb5_read_message(context, &sock, &data); if(ret != 0 && ret != HEIM_ERR_EOF) krb5_err(context, 1, ret, "krb5_read_message"); } else { ret = krb5_read_priv_message(context, ac, &sock, &data); if(ret) krb5_err(context, 1, ret, "krb5_read_priv_message"); } if(ret == HEIM_ERR_EOF || data.length == 0) { if(!from_stdin) { data.data = NULL; data.length = 0; krb5_write_priv_message(context, ac, &sock, &data); } if(!print_dump) { ret = db->hdb_close(context, db); if(ret) krb5_err(context, 1, ret, "db_close"); ret = db->hdb_rename(context, db, database); if(ret) krb5_err(context, 1, ret, "db_rename"); } break; } memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry(context, &data, &entry.entry); krb5_data_free(&data); if(ret) krb5_err(context, 1, ret, "hdb_value2entry"); if(print_dump) hdb_print_entry(context, db, &entry, stdout); else { ret = db->hdb_store(context, db, 0, &entry); if(ret == HDB_ERR_EXISTS) { char *s; ret = krb5_unparse_name(context, entry.entry.principal, &s); if (ret) s = strdup("unparseable name"); krb5_warnx(context, "Entry exists: %s", s); free(s); } else if(ret) krb5_err(context, 1, ret, "db_store"); else nprincs++; } hdb_free_entry(context, &entry); } if (!print_dump) krb5_log(context, fac, 0, "Received %d principals", nprincs); if (inetd_flag == 0) rk_closesocket(sock); exit(0); }
/* * validate user/pass (Heimdal) */ static int krb5_auth(void *instance, REQUEST *request) { rlm_krb5_t *inst = instance; krb5_error_code ret; krb5_ccache id; krb5_principal userP; krb5_context context = *(inst->context); /* copy data */ const char *user, *pass; char service[SERVICE_NAME_LEN] = "host"; char *server_name = NULL; char *princ_name; krb5_verify_opt krb_verify_options; krb5_keytab keytab; if (inst->service_princ != NULL) { server_name = strchr(inst->service_princ, '/'); if (server_name != NULL) { *server_name = '\0'; } strlcpy(service, inst->service_princ, sizeof(service)); if (server_name != NULL) { *server_name = '/'; server_name++; } } /* * We can only authenticate user requests which HAVE * a User-Name attribute. */ if (!request->username) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication."); return RLM_MODULE_INVALID; } /* * We can only authenticate user requests which HAVE * a User-Password attribute. */ if (!request->password) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication."); return RLM_MODULE_INVALID; } /* * Ensure that we're being passed a plain-text password, * and not anything else. */ if (request->password->attribute != PW_USER_PASSWORD) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name); return RLM_MODULE_INVALID; } user = request->username->vp_strvalue; pass = request->password->vp_strvalue; ret = krb5_parse_name(context, user, &userP); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s", user, error_message(ret)); return RLM_MODULE_REJECT; } /* * Heimdal krb5 verification. */ /* * The following bit allows us to also log user/instance@REALM if someone * logs in using an instance. */ ret = krb5_unparse_name(context, userP, &princ_name); if (ret != 0) { radlog(L_AUTH, "rlm_krb5: Unparsable name"); } else { radlog(L_AUTH, "rlm_krb5: Parsed name is: %s", princ_name); free(princ_name); } krb5_cc_default(context, &id); /* * Set up krb5_verify_user options. */ krb5_verify_opt_init(&krb_verify_options); krb5_verify_opt_set_ccache(&krb_verify_options, id); /* * Resolve keytab name. This allows us to use something other than * the default system keytab */ if (inst->keytab != NULL) { ret = krb5_kt_resolve(context, inst->keytab, &keytab); if (ret) { radlog(L_AUTH, "rlm_krb5: unable to resolve keytab %s: %s", inst->keytab, error_message(ret)); krb5_kt_close(context, keytab); return RLM_MODULE_REJECT; } krb5_verify_opt_set_keytab(&krb_verify_options, keytab); } /* * Verify aquired credentials against the keytab. */ krb5_verify_opt_set_secure(&krb_verify_options, 1); /* * Allow us to use an arbitrary service name. */ krb5_verify_opt_set_service(&krb_verify_options, service); /* * Verify the user, using the above set options. */ ret = krb5_verify_user_opt(context, userP, pass, &krb_verify_options); /* * We are done with the keytab, close it. */ krb5_kt_close(context, keytab); if (ret == 0) return RLM_MODULE_OK; radlog(L_AUTH, "rlm_krb5: failed verify_user: %s (%s@%s)", error_message(ret), *userP->name.name_string.val, userP->realm); return RLM_MODULE_REJECT; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; krb5_keytab kt = NULL; krb5_init_creds_context ctx; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if (forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag); if (proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag); if (anonymous_flag) krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, krb5_prompter_posix, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time(renewstr, "s"); if (renew < 0) errx(1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life(opt, renew); } if (ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life); if (start_str) { int tmp = parse_time(start_str, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if (etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if (enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if (ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, krb5_prompter_posix, NULL, start_time, opt, &ctx); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_service"); } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if (use_keytab || keytab_str) { if (keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err(context, 1, ret, "resolving keytab"); ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_keytab"); } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive) { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (!ret) { aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); } if (ret || aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } } ret = krb5_init_creds_get(context, ctx); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: krb5_errx(context, 1, N_("Password incorrect", "")); break; case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); break; default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_get_creds"); if (ticket_life != 0) { if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if (renew_life) { if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); krb5_init_creds_free(context, ctx); ret = krb5_cc_move(context, tempccache, ccache); if (ret) krb5_err(context, 1, ret, "krb5_cc_move"); if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); if (enctype) free(enctype); return 0; }
Code_t ZCheckSrvAuthentication(ZNotice_t *notice, struct sockaddr_in *from, char *realm) { #ifdef HAVE_KRB5 unsigned char *authbuf; krb5_principal princ; krb5_data packet; krb5_ticket *tkt; char *name; krb5_error_code result; krb5_principal server; krb5_keytab keytabid = 0; krb5_auth_context authctx; krb5_keyblock *keyblock; krb5_enctype enctype; krb5_cksumtype cksumtype; krb5_data cksumbuf; int valid; char *cksum0_base, *cksum1_base = NULL, *cksum2_base; char *x; unsigned char *asn1_data, *key_data, *cksum_data; int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0; KRB5_AUTH_CON_FLAGS_TYPE acflags; #ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER krb5_authenticator *authenticator; #define KRB5AUTHENT authenticator #else krb5_authenticator authenticator; #define KRB5AUTHENT &authenticator #endif int len; char *sender; char rlmprincipal[MAX_PRINCIPAL_SIZE]; if (!notice->z_auth) return ZAUTH_NO; /* Check for bogus authentication data length. */ if (notice->z_authent_len <= 0) { syslog(LOG_DEBUG, "ZCheckSrvAuthentication: bogus authenticator length"); return ZAUTH_FAILED; } #ifdef HAVE_KRB4 if (notice->z_ascii_authent[0] != 'Z' && realm == NULL) return ZCheckAuthentication4(notice, from); #endif len = strlen(notice->z_ascii_authent)+1; authbuf = malloc(len); /* Read in the authentication data. */ if (ZReadZcode((unsigned char *)notice->z_ascii_authent, authbuf, len, &len) == ZERR_BADFIELD) { syslog(LOG_DEBUG, "ZCheckSrvAuthentication: ZReadZcode: Improperly formatted field"); return ZAUTH_FAILED; } if (realm == NULL) { sender = notice->z_sender; } else { (void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE, SERVER_INSTANCE, realm); sender = rlmprincipal; } packet.length = len; packet.data = (char *)authbuf; result = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &keytabid); if (result) { free(authbuf); syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_kt_resolve: %s", error_message(result)); return ZAUTH_FAILED; } /* HOLDING: authbuf, keytabid */ /* Create the auth context */ result = krb5_auth_con_init(Z_krb5_ctx, &authctx); if (result) { krb5_kt_close(Z_krb5_ctx, keytabid); free(authbuf); syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_init: %s", error_message(result)); return ZAUTH_FAILED; } /* HOLDING: authbuf, keytabid, authctx */ result = krb5_auth_con_getflags(Z_krb5_ctx, authctx, &acflags); if (result) { krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_kt_close(Z_krb5_ctx, keytabid); free(authbuf); syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_getflags: %s", error_message(result)); return ZAUTH_FAILED; } acflags &= ~KRB5_AUTH_CONTEXT_DO_TIME; result = krb5_auth_con_setflags(Z_krb5_ctx, authctx, acflags); if (result) { krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_kt_close(Z_krb5_ctx, keytabid); free(authbuf); syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_setflags: %s", error_message(result)); return ZAUTH_FAILED; } result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm), __Zephyr_realm, SERVER_SERVICE, SERVER_INSTANCE, NULL); if (!result) { result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server, keytabid, NULL, &tkt); krb5_free_principal(Z_krb5_ctx, server); } krb5_kt_close(Z_krb5_ctx, keytabid); /* HOLDING: authbuf, authctx */ if (result) { if (result == KRB5KRB_AP_ERR_REPEAT) syslog(LOG_DEBUG, "ZCheckSrvAuthentication: k5 auth failed: %s", error_message(result)); else syslog(LOG_WARNING,"ZCheckSrvAuthentication: k5 auth failed: %s", error_message(result)); free(authbuf); krb5_auth_con_free(Z_krb5_ctx, authctx); return ZAUTH_FAILED; } /* HOLDING: authbuf, authctx, tkt */ if (tkt == 0 || !Z_tktprincp(tkt)) { if (tkt) krb5_free_ticket(Z_krb5_ctx, tkt); free(authbuf); krb5_auth_con_free(Z_krb5_ctx, authctx); syslog(LOG_WARNING, "ZCheckSrvAuthentication: No Ticket"); return ZAUTH_FAILED; } princ = Z_tktprinc(tkt); if (princ == 0) { krb5_free_ticket(Z_krb5_ctx, tkt); free(authbuf); krb5_auth_con_free(Z_krb5_ctx, authctx); syslog(LOG_WARNING, "ZCheckSrvAuthentication: No... Ticket?"); return ZAUTH_FAILED; } /* HOLDING: authbuf, authctx, tkt */ result = krb5_unparse_name(Z_krb5_ctx, princ, &name); if (result) { syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_unparse_name failed: %s", error_message(result)); free(authbuf); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_ticket(Z_krb5_ctx, tkt); return ZAUTH_FAILED; } krb5_free_ticket(Z_krb5_ctx, tkt); /* HOLDING: authbuf, authctx, name */ if (strcmp(name, sender)) { syslog(LOG_WARNING, "ZCheckSrvAuthentication: name mismatch: '%s' vs '%s'", name, sender); krb5_auth_con_free(Z_krb5_ctx, authctx); #ifdef HAVE_KRB5_FREE_UNPARSED_NAME krb5_free_unparsed_name(Z_krb5_ctx, name); #else free(name); #endif free(authbuf); return ZAUTH_FAILED; } #ifdef HAVE_KRB5_FREE_UNPARSED_NAME krb5_free_unparsed_name(Z_krb5_ctx, name); #else free(name); #endif free(authbuf); /* HOLDING: authctx */ /* Get an authenticator so we can get the keyblock */ result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx, &authenticator); if (result) { krb5_auth_con_free(Z_krb5_ctx, authctx); syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getauthenticator failed: %s", error_message(result)); return ZAUTH_FAILED; } /* HOLDING: authctx, authenticator */ result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock); if (result) { krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getkey failed: %s", error_message(result)); return (ZAUTH_FAILED); } /* HOLDING: authctx, authenticator, keyblock */ /* Figure out what checksum type to use */ key_data = Z_keydata(keyblock); key_len = Z_keylen(keyblock); result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); if (result) { krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); syslog(LOG_WARNING, "ZCheckSrvAuthentication: Z_ExtractEncCksum failed: %s", error_message(result)); return (ZAUTH_FAILED); } /* HOLDING: authctx, authenticator, keyblock */ if (realm == NULL) ZSetSession(keyblock); /* Assemble the things to be checksummed */ /* first part is from start of packet through z_default_format: * - z_version * - z_num_other_fields * - z_kind * - z_uid * - z_port * - z_auth * - z_authent_len * - z_ascii_authent * - z_class * - z_class_inst * - z_opcode * - z_sender * - z_recipient * - z_default_format */ cksum0_base = notice->z_packet; x = notice->z_default_format; cksum0_len = x + strlen(x) + 1 - cksum0_base; /* second part is from z_multinotice through other fields: * - z_multinotice * - z_multiuid * - z_sender_(sock)addr * - z_charset * - z_other_fields[] */ if (notice->z_num_hdr_fields > 15 ) { cksum1_base = notice->z_multinotice; if (notice->z_num_other_fields) x = notice->z_other_fields[notice->z_num_other_fields - 1]; else { /* see also ZCheckRealmAuthentication and lib/ZCkZaut.c:ZCheckZcodeAuthentication */ /* XXXXXXXXXXXXXXXXXXXXXXX */ if (notice->z_num_hdr_fields > 16) x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */ if (notice->z_num_hdr_fields > 17) x = x + strlen(x) + 1; /* multiuid */ if (notice->z_num_hdr_fields > 18) x = x + strlen(x) + 1; /* sender */ } cksum1_len = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */ } /* last part is the message body */ cksum2_base = notice->z_message; cksum2_len = notice->z_message_len; /*XXX we may wish to ditch this code someday?*/ if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') && key_len == 8 && (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC || enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 || enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) { /* try old-format checksum (covers cksum0 only) */ ZChecksum_t our_checksum; if (realm == NULL) our_checksum = compute_checksum(notice, key_data); else our_checksum = compute_rlm_checksum(notice, key_data); krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); if (our_checksum == notice->z_checksum) { return ZAUTH_YES; } else { syslog(LOG_DEBUG, "ZCheckSrvAuthentication: des quad checksum mismatch"); return ZAUTH_FAILED; } } /* HOLDING: authctx, authenticator */ cksumbuf.length = cksum0_len + cksum1_len + cksum2_len; cksumbuf.data = malloc(cksumbuf.length); if (!cksumbuf.data) { krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(cksumbuf.data): %m"); return ZAUTH_FAILED; } /* HOLDING: authctx, authenticator, cksumbuf.data */ cksum_data = (unsigned char *)cksumbuf.data; memcpy(cksum_data, cksum0_base, cksum0_len); if (cksum1_len) memcpy(cksum_data + cksum0_len, cksum1_base, cksum1_len); memcpy(cksum_data + cksum0_len + cksum1_len, cksum2_base, cksum2_len); /* decode zcoded checksum */ /* The encoded form is always longer than the original */ asn1_len = strlen(notice->z_ascii_checksum) + 1; asn1_data = malloc(asn1_len); if (!asn1_data) { krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); free(cksumbuf.data); syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(asn1_data): %m"); return ZAUTH_FAILED; } /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */ result = ZReadZcode((unsigned char *)notice->z_ascii_checksum, asn1_data, asn1_len, &asn1_len); if (result != ZERR_NONE) { krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); free(asn1_data); free(cksumbuf.data); syslog(LOG_WARNING, "ZCheckSrvAuthentication: ZReadZcode: %s", error_message(result)); return ZAUTH_FAILED; } /* HOLDING: asn1_data, cksumbuf.data, authctx, authenticator */ valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, Z_KEYUSAGE_CLT_CKSUM, asn1_data, asn1_len); /* XXX compatibility with unreleased interrealm krb5; drop in 3.1 */ if (!valid && realm) valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, Z_KEYUSAGE_SRV_CKSUM, asn1_data, asn1_len); free(asn1_data); krb5_auth_con_free(Z_krb5_ctx, authctx); krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); krb5_free_keyblock(Z_krb5_ctx, keyblock); free(cksumbuf.data); if (valid) { return ZAUTH_YES; } else { syslog(LOG_DEBUG, "ZCheckSrvAuthentication: Z_krb5_verify_cksum: failed"); return ZAUTH_FAILED; } #else return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO; #endif }
static int do_list(struct list_options *opt, const char *keytab_str) { krb5_error_code ret; krb5_keytab keytab; krb5_keytab_entry entry; krb5_kt_cursor cursor; rtbl_t table; /* XXX specialcase the ANY type */ if(strncasecmp(keytab_str, "ANY:", 4) == 0) { int flag = 0; char buf[1024]; keytab_str += 4; ret = 0; while (strsep_copy((const char**)&keytab_str, ",", buf, sizeof(buf)) != -1) { if(flag) printf("\n"); if(do_list(opt, buf)) ret = 1; flag = 1; } return ret; } ret = krb5_kt_resolve(context, keytab_str, &keytab); if (ret) { krb5_warn(context, ret, "resolving keytab %s", keytab_str); return ret; } ret = krb5_kt_start_seq_get(context, keytab, &cursor); if(ret) { krb5_warn(context, ret, "krb5_kt_start_seq_get %s", keytab_str); krb5_kt_close(context, keytab); return ret; } printf ("%s:\n\n", keytab_str); table = rtbl_create(); rtbl_add_column_by_id(table, 0, "Vno", RTBL_ALIGN_RIGHT); rtbl_add_column_by_id(table, 1, "Type", 0); rtbl_add_column_by_id(table, 2, "Principal", 0); if (opt->timestamp_flag) rtbl_add_column_by_id(table, 3, "Date", 0); if(opt->keys_flag) rtbl_add_column_by_id(table, 4, "Key", 0); rtbl_add_column_by_id(table, 5, "Aliases", 0); rtbl_set_separator(table, " "); while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { char buf[1024], *s; snprintf(buf, sizeof(buf), "%d", entry.vno); rtbl_add_column_entry_by_id(table, 0, buf); ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &s); if (ret != 0) { snprintf(buf, sizeof(buf), "unknown (%d)", entry.keyblock.keytype); rtbl_add_column_entry_by_id(table, 1, buf); } else { rtbl_add_column_entry_by_id(table, 1, s); free(s); } krb5_unparse_name_fixed(context, entry.principal, buf, sizeof(buf)); rtbl_add_column_entry_by_id(table, 2, buf); if (opt->timestamp_flag) { krb5_format_time(context, entry.timestamp, buf, sizeof(buf), FALSE); rtbl_add_column_entry_by_id(table, 3, buf); } if(opt->keys_flag) { size_t i; s = malloc(2 * entry.keyblock.keyvalue.length + 1); if (s == NULL) { krb5_warnx(context, "malloc failed"); ret = ENOMEM; goto out; } for(i = 0; i < entry.keyblock.keyvalue.length; i++) snprintf(s + 2 * i, 3, "%02x", ((unsigned char*)entry.keyblock.keyvalue.data)[i]); rtbl_add_column_entry_by_id(table, 4, s); free(s); } if (entry.aliases) { unsigned int i; struct rk_strpool *p = NULL; for (i = 0; i< entry.aliases->len; i++) { krb5_unparse_name_fixed(context, entry.principal, buf, sizeof(buf)); rk_strpoolprintf(p, "%s%s", buf, i + 1 < entry.aliases->len ? ", " : ""); } rtbl_add_column_entry_by_id(table, 5, rk_strpoolcollect(p)); } krb5_kt_free_entry(context, &entry); } ret = krb5_kt_end_seq_get(context, keytab, &cursor); rtbl_format(table, stdout); out: rtbl_destroy(table); krb5_kt_close(context, keytab); return ret; }
int Condor_Auth_Kerberos :: authenticate_server_kerberos() { krb5_error_code code; krb5_flags flags = 0; krb5_data request, reply; priv_state priv; krb5_keytab keytab = 0; int message, rc = FALSE; krb5_ticket * ticket = NULL; request.data = 0; reply.data = 0; keytabName_ = param(STR_KERBEROS_SERVER_KEYTAB); //------------------------------------------ // Getting keytab info //------------------------------------------ if (keytabName_) { code = krb5_kt_resolve(krb_context_, keytabName_, &keytab); } else { code = krb5_kt_default(krb_context_, &keytab); } if (code) { dprintf( D_ALWAYS, "1: Kerberos server authentication error:%s\n", error_message(code) ); goto error; } //------------------------------------------ // Get te KRB_AP_REQ message //------------------------------------------ if(read_request(&request) == FALSE) { dprintf( D_ALWAYS, "KERBEROS: Server is unable to read request\n" ); goto error; } dprintf( D_SECURITY, "Reading kerberos request object (krb5_rd_req)\n"); dprintf_krb5_principal( D_FULLDEBUG, "KERBEROS: krb_principal_ is '%s'\n", krb_principal_); priv = set_root_priv(); // Get the old privilige if ((code = krb5_rd_req(krb_context_, &auth_context_, &request, //krb_principal_, NULL, keytab, &flags, &ticket))) { set_priv(priv); // Reset dprintf( D_ALWAYS, "2: Kerberos server authentication error:%s\n", error_message(code) ); goto error; } set_priv(priv); // Reset dprintf ( D_FULLDEBUG, "KERBEROS: krb5_rd_req done.\n"); //------------------------------------------ // See if mutual authentication is required //------------------------------------------ if (flags & AP_OPTS_MUTUAL_REQUIRED) { if ((code = krb5_mk_rep(krb_context_, auth_context_, &reply))) { dprintf( D_ALWAYS, "3: Kerberos server authentication error:%s\n", error_message(code) ); goto error; } mySock_->encode(); message = KERBEROS_MUTUAL; if (!mySock_->code(message) || !mySock_->end_of_message()) { goto error; } // send the message if (send_request(&reply) != KERBEROS_GRANT) { goto cleanup; } } //------------------------------------------ // extract client addresses //------------------------------------------ if (ticket->enc_part2->caddrs) { struct in_addr in; memcpy(&(in.s_addr), ticket->enc_part2->caddrs[0]->contents, sizeof(in_addr)); setRemoteHost(inet_ntoa(in)); dprintf(D_SECURITY, "Client address is %s\n", getRemoteHost()); } // First, map the name, this has to take place before receive_tgt_creds! if (!map_kerberos_name(&(ticket->enc_part2->client))) { dprintf(D_SECURITY, "Unable to map Kerberos name\n"); goto error; } // copy the session key if ((code = krb5_copy_keyblock(krb_context_, ticket->enc_part2->session, &sessionKey_))){ dprintf(D_SECURITY, "4: Kerberos server authentication error:%s\n", error_message(code)); goto error; } // Next, see if we need client to forward the credential as well if (receive_tgt_creds(ticket)) { goto cleanup; } //------------------------------------------ // We are now authenticated! //------------------------------------------ dprintf(D_SECURITY, "User %s is now authenticated!\n", getRemoteUser()); rc = TRUE; goto cleanup; error: message = KERBEROS_DENY; mySock_->encode(); if ((!mySock_->code(message)) || (!mySock_->end_of_message())) { dprintf( D_ALWAYS, "KERBEROS: Failed to send response message!\n" ); } cleanup: //------------------------------------------ // Free up some stuff //------------------------------------------ if (ticket) { krb5_free_ticket(krb_context_, ticket); } if (keytab) { krb5_kt_close(krb_context_, keytab); } //------------------------------------------ // Free it for now, in the future, we might // need this for future secure transctions. //------------------------------------------ if (request.data) { free(request.data); } if (reply.data) { free(reply.data); } return rc; }
static void do_keytab(const char *name) { krb5_error_code ret; krb5_keytab kt; krb5_keytab_entry entry; krb5_kt_cursor cursor; unsigned int i; char buf[BUFSIZ]; /* Hopefully large enough for any type */ char *pname; if (name == NULL && use_client_keytab) { ret = krb5_kt_client_default(context, &kt); if (ret) { com_err(progname, ret, _("while getting default client keytab")); exit(1); } } else if (name == NULL) { ret = krb5_kt_default(context, &kt); if (ret) { com_err(progname, ret, _("while getting default keytab")); exit(1); } } else { ret = krb5_kt_resolve(context, name, &kt); if (ret) { com_err(progname, ret, _("while resolving keytab %s"), name); exit(1); } } ret = krb5_kt_get_name(context, kt, buf, BUFSIZ); if (ret) { com_err(progname, ret, _("while getting keytab name")); exit(1); } printf("Keytab name: %s\n", buf); ret = krb5_kt_start_seq_get(context, kt, &cursor); if (ret) { com_err(progname, ret, _("while starting keytab scan")); exit(1); } /* XXX Translating would disturb table alignment; skip for now. */ if (show_time) { printf("KVNO Timestamp"); fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' '); printf("Principal\n"); printf("---- "); fillit(stdout, timestamp_width, (int) '-'); printf(" "); fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-'); printf("\n"); } else { printf("KVNO Principal\n"); printf("---- ------------------------------------------------" "--------------------------\n"); } while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) { ret = krb5_unparse_name(context, entry.principal, &pname); if (ret) { com_err(progname, ret, _("while unparsing principal name")); exit(1); } printf("%4d ", entry.vno); if (show_time) { printtime(entry.timestamp); printf(" "); } printf("%s", pname); if (show_etype) printf(" (%s) " , etype_string(entry.key.enctype)); if (show_keys) { printf(" (0x"); for (i = 0; i < entry.key.length; i++) printf("%02x", entry.key.contents[i]); printf(")"); } printf("\n"); krb5_free_unparsed_name(context, pname); krb5_free_keytab_entry_contents(context, &entry); } if (ret && ret != KRB5_KT_END) { com_err(progname, ret, _("while scanning keytab")); exit(1); } ret = krb5_kt_end_seq_get(context, kt, &cursor); if (ret) { com_err(progname, ret, _("while ending keytab scan")); exit(1); } exit(0); }
static char * init_cc_from_keytab(const char *keytab_name, const char *user) { krb5_context context = NULL; krb5_error_code ret; krb5_creds my_creds; krb5_keytab keytab = NULL; krb5_principal me = NULL; krb5_ccache cc = NULL; char *ccname = NULL; memset((char *) &my_creds, 0, sizeof(my_creds)); ret = krb5_init_context(&context); if (ret) { syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret); goto icfk_cleanup; } ret = krb5_kt_resolve(context, keytab_name, &keytab); if (ret) { syslog(LOG_DEBUG, "krb5_kt_resolve: %d", (int)ret); goto icfk_cleanup; } ret = krb5_parse_name(context, user, &me); if (ret) { syslog(LOG_DEBUG, "krb5_parse_name: %d", (int)ret); goto icfk_cleanup; } ret = krb5_get_init_creds_keytab(context, &my_creds, me, keytab, 0, NULL, NULL); if (ret) { syslog(LOG_DEBUG, "krb5_get_init_creds_keytab: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_default(context, &cc); if (ret) { syslog(LOG_DEBUG, "krb5_cc_default: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_initialize(context, cc, me); if (ret) { syslog(LOG_DEBUG, "krb5_cc_initialize: %d", (int)ret); goto icfk_cleanup; } ret = krb5_cc_store_cred(context, cc, &my_creds); if (ret) syslog(LOG_DEBUG, "krb5_cc_store_cred: %d", (int)ret); ccname = strdup(krb5_cc_default_name(context)); if (ccname == NULL) syslog(LOG_ERR, "Unable to allocate memory"); icfk_cleanup: my_creds.client = 0; krb5_free_cred_contents(context, &my_creds); if (me) krb5_free_principal(context, me); if (cc) krb5_cc_close(context, cc); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return ccname; }
/* Perform one iteration of attempting to get credentials. This includes * searching existing ccache for requested service if INIT_CREDS. */ static kadm5_ret_t gic_iter(kadm5_server_handle_t handle, enum init_type init_type, krb5_ccache ccache, krb5_principal client, char *pass, char *svcname, char *realm, krb5_principal *server_out) { kadm5_ret_t code; krb5_context ctx; krb5_keytab kt; krb5_get_init_creds_opt *opt = NULL; krb5_creds mcreds, outcreds; *server_out = NULL; ctx = handle->context; kt = NULL; memset(&opt, 0, sizeof(opt)); memset(&mcreds, 0, sizeof(mcreds)); memset(&outcreds, 0, sizeof(outcreds)); /* Credentials for kadmin don't need to be forwardable or proxiable. */ if (init_type != INIT_CREDS) { code = krb5_get_init_creds_opt_alloc(ctx, &opt); krb5_get_init_creds_opt_set_forwardable(opt, 0); krb5_get_init_creds_opt_set_proxiable(opt, 0); krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache); if (init_type == INIT_ANONYMOUS) krb5_get_init_creds_opt_set_anonymous(opt, 1); } if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) { code = krb5_get_init_creds_password(ctx, &outcreds, client, pass, krb5_prompter_posix, NULL, 0, svcname, opt); if (code) goto error; } else if (init_type == INIT_SKEY) { if (pass) { code = krb5_kt_resolve(ctx, pass, &kt); if (code) goto error; } code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt, 0, svcname, opt); if (pass) krb5_kt_close(ctx, kt); if (code) goto error; } else if (init_type == INIT_CREDS) { mcreds.client = client; code = krb5_parse_name_flags(ctx, svcname, KRB5_PRINCIPAL_PARSE_IGNORE_REALM, &mcreds.server); if (code) goto error; code = krb5_set_principal_realm(ctx, mcreds.server, realm); if (code) goto error; code = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &outcreds); krb5_free_principal(ctx, mcreds.server); if (code) goto error; } else { code = EINVAL; goto error; } /* Steal the server principal of the creds we acquired and return it to the * caller, which needs to knows what service to authenticate to. */ *server_out = outcreds.server; outcreds.server = NULL; error: krb5_free_cred_contents(ctx, &outcreds); if (opt) krb5_get_init_creds_opt_free(ctx, opt); return code; }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) { krb5_context kcontext = NULL; krb5_keytab keytab = NULL; krb5_principal s_princ = NULL; krb5_principal c_princ = NULL; krb5_creds c_creds; krb5_ccache c_ccache = NULL; krb5_ccache ret_ccache = NULL; krb5_error_code code; int ret; buffer *sprinc; buffer *user_at_realm = NULL; plugin_data * const p = (plugin_data *)p_d; if (*pw == '\0') { log_error_write(srv, __FILE__, __LINE__, "s", "Empty passwords are not accepted"); return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); } mod_authn_gssapi_patch_connection(srv, con, p); code = krb5_init_context(&kcontext); if (code) { log_error_write(srv, __FILE__, __LINE__, "sd", "krb5_init_context():", code); return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); /*(well, should be 500)*/ } code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab); if (code) { log_error_write(srv, __FILE__, __LINE__, "sdb", "krb5_kt_resolve():", code, p->conf.auth_gssapi_keytab); return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); /*(well, should be 500)*/ } sprinc = buffer_init_buffer(p->conf.auth_gssapi_principal); if (strchr(sprinc->ptr, '/') == NULL) { /*(copy HTTP Host, omitting port if port is present)*/ /* ??? Should con->server_name be used if http_host not present? * ??? What if con->server_name is not set? * ??? Will this work below if IPv6 provided in Host? probably not */ if (!buffer_is_empty(con->request.http_host)) { buffer_append_string(sprinc, "/"); buffer_append_string_len(sprinc, con->request.http_host->ptr, strcspn(con->request.http_host->ptr, ":")); } } /*(init c_creds before anything which might krb5_free_cred_contents())*/ memset(&c_creds, 0, sizeof(c_creds)); ret = krb5_parse_name(kcontext, sprinc->ptr, &s_princ); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", sprinc->ptr, kcontext, ret); ret = -1; goto end; } if (strchr(username->ptr, '@') == NULL) { user_at_realm = buffer_init_buffer(username); BUFFER_APPEND_STRING_CONST(user_at_realm, "@"); buffer_append_string_buffer(user_at_realm, require->realm); } ret = krb5_parse_name(kcontext, (user_at_realm ? user_at_realm->ptr : username->ptr), &c_princ); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", (user_at_realm ? user_at_realm->ptr : username->ptr), kcontext, ret); if (user_at_realm) buffer_free(user_at_realm); ret = -1; goto end; } if (user_at_realm) buffer_free(user_at_realm); /* XXX: if the qualified username with @realm should be in REMOTE_USER, * then http_auth_backend_t basic interface needs to change to pass * modifiable buffer *username, but note that const char *pw follows * in the truncated buffer *username, so pw would need to be copied * before modifying buffer *username */ /* * char *name = NULL; * ret = krb5_unparse_name(kcontext, c_princ, &name); * if (ret == 0) { * log_error_write(srv, __FILE__, __LINE__, "sbss", "Trying to get TGT for user:"******"password:"******"krb5_get_init_creds_password", NULL, kcontext, ret); goto end; } ret = mod_authn_gssapi_verify_krb5_init_creds(srv, kcontext, &c_creds, s_princ, keytab); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "mod_authn_gssapi_verify_krb5_init_creds", NULL, kcontext, ret); goto end; } ret = krb5_cc_resolve(kcontext, "MEMORY:", &ret_ccache); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_resolve", NULL, kcontext, ret); goto end; } ret = krb5_cc_initialize(kcontext, ret_ccache, c_princ); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_initialize", NULL, kcontext, ret); goto end; } ret = krb5_cc_store_cred(kcontext, ret_ccache, &c_creds); if (ret) { mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_store_cred", NULL, kcontext, ret); goto end; } c_ccache = ret_ccache; ret_ccache = NULL; end: krb5_free_cred_contents(kcontext, &c_creds); if (ret_ccache) krb5_cc_destroy(kcontext, ret_ccache); if (!ret && c_ccache && (ret = mod_authn_gssapi_store_krb5_creds(srv, con, p, kcontext, c_ccache))) { log_error_write(srv, __FILE__, __LINE__, "sb", "mod_authn_gssapi_store_krb5_creds failed for", username); } buffer_free(sprinc); if (c_princ) krb5_free_principal(kcontext, c_princ); if (s_princ) krb5_free_principal(kcontext, s_princ); if (c_ccache) krb5_cc_destroy(kcontext, c_ccache); if (keytab) krb5_kt_close(kcontext, keytab); krb5_free_context(kcontext); if (0 == ret && http_auth_match_rules(require,username->ptr,NULL,NULL)){ return HANDLER_GO_ON; } else { /* ret == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN or no authz rules match */ log_error_write(srv, __FILE__, __LINE__, "sbsBsB", "password doesn't match for", con->uri.path, "username:"******", IP:", con->dst_addr_buf); return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); } }
/* returns boolean */ static int k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { char *doing; int notix = 1; krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; krb5_get_init_creds_opt options; krb5_address **addresses; krb5_get_init_creds_opt_init(&options); g_memset(&my_creds, 0, sizeof(my_creds)); /* From this point on, we can goto cleanup because my_creds is initialized. */ if (opts->lifetime) { krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } if (opts->rlife) { krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } if (opts->forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 1); } if (opts->not_forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 0); } if (opts->proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 1); } if (opts->not_proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 0); } if (opts->addresses) { addresses = NULL; code = krb5_os_localaddr(k5->ctx, &addresses); if (code != 0) { g_printf("krb5_os_localaddr failed in k5_kinit\n"); goto cleanup; } krb5_get_init_creds_opt_set_address_list(&options, addresses); } if (opts->no_addresses) { krb5_get_init_creds_opt_set_address_list(&options, NULL); } if ((opts->action == INIT_KT) && opts->keytab_name) { code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); if (code != 0) { g_printf("krb5_kt_resolve failed in k5_kinit\n"); goto cleanup; } } switch (opts->action) { case INIT_PW: code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, kinit_prompter, u_info, opts->starttime, opts->service_name, &options); break; case INIT_KT: code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, opts->starttime, opts->service_name, &options); break; case VALIDATE: code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; case RENEW: code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; } if (code != 0) { doing = 0; switch (opts->action) { case INIT_PW: case INIT_KT: doing = "getting initial credentials"; break; case VALIDATE: doing = "validating credentials"; break; case RENEW: doing = "renewing credentials"; break; } if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); } else { g_printf("sesman: error while %s in k5_kinit\n", doing); } goto cleanup; } if (!opts->lifetime) { /* We need to figure out what lifetime to use for Kerberos 4. */ opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); if (code != 0) { g_printf("krb5_cc_initialize failed in k5_kinit\n"); goto cleanup; } code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); if (code != 0) { g_printf("krb5_cc_store_cred failed in k5_kinit\n"); goto cleanup; } notix = 0; cleanup: if (my_creds.client == k5->me) { my_creds.client = 0; } krb5_free_cred_contents(k5->ctx, &my_creds); if (keytab) { krb5_kt_close(k5->ctx, keytab); } return notix ? 0 : 1; }
/* * Print a krb5 ticket in our service key, for the supplied client principal. * The path to a keytab is mandatory, but the service principal may be * guessed from the keytab contents if desired. The keytab entry must be * one of the allowed_enctypes (a zero-terminated list) if a non-NULL * parameter is passed. */ krb5_error_code get_credv5_akimpersonate(krb5_context context, char* keytab, krb5_principal service_principal, krb5_principal client_principal, time_t starttime, time_t endtime, const int *allowed_enctypes, krb5_creds** out_creds /* out */ ) { char *tmpkt = NULL; struct stat tstat; char *ktname = NULL; krb5_error_code code; krb5_keytab kt = 0; krb5_keytab_entry entry[1]; krb5_creds *creds = 0; krb5_enctype enctype; krb5_keyblock session_key[1]; #if USING_HEIMDAL Ticket *ticket_reply; EncTicketPart *enc_tkt_reply; #else krb5_ticket *ticket_reply; krb5_enc_tkt_part *enc_tkt_reply; #endif *out_creds = NULL; enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */ memset(entry, 0, sizeof *entry); memset(session_key, 0, sizeof *session_key); ticket_reply = NULL; enc_tkt_reply = NULL; creds = calloc(1, sizeof(*creds)); if (creds == NULL) { code = ENOMEM; goto cleanup; } code = alloc_ticket(&ticket_reply); if (code != 0) goto cleanup; code = alloc_enc_tkt_part(&enc_tkt_reply); if (code != 0) goto cleanup; /* Empty list of allowed etypes must fail. Do it here to avoid issues. */ if (allowed_enctypes != NULL && *allowed_enctypes == 0) { code = KRB5_BAD_ENCTYPE; goto cleanup; } if (allowed_enctypes == NULL) allowed_enctypes = any_enctype; if (keytab != NULL) { tmpkt = strdup(keytab); if (!tmpkt) code = ENOMEM; } else { tmpkt = malloc(256); if (!tmpkt) code = ENOMEM; else code = krb5_kt_default_name(context, tmpkt, 256); } if (code) goto cleanup; if (strncmp(tmpkt, "WRFILE:", 7) == 0) ktname = &(tmpkt[7]); else if (strncmp(tmpkt, "FILE:", 5) == 0) ktname = &(tmpkt[5]); if (ktname && (stat(ktname, &tstat) != 0)) { code = KRB5_KT_NOTFOUND; goto cleanup; } code = krb5_kt_resolve(context, tmpkt, &kt); if (code != 0) goto cleanup; code = pick_enctype_and_principal(context, kt, allowed_enctypes, &enctype, &service_principal, entry); if (code != 0) goto cleanup; /* Conjure up a random session key */ deref_keyblock_enctype(session_key) = enctype; #if USING_HEIMDAL code = krb5_generate_random_keyblock(context, enctype, session_key); #else code = krb5_c_make_random_key(context, enctype, session_key); #endif if (code != 0) goto cleanup; populate_enc_tkt(session_key, client_principal, starttime, endtime, enc_tkt_reply); code = encrypt_enc_tkt(context, service_principal, entry, ticket_reply, enc_tkt_reply); if (code != 0) goto cleanup; code = populate_creds(context, service_principal, client_principal, session_key, ticket_reply, enc_tkt_reply, creds); if (code != 0) goto cleanup; /* return creds */ *out_creds = creds; creds = NULL; cleanup: if (tmpkt) free(tmpkt); if (deref_enc_data(&ticket_reply->enc_part) != NULL) free(deref_enc_data(&ticket_reply->enc_part)); krb5_free_keytab_entry_contents(context, entry); if (client_principal != NULL) krb5_free_principal(context, client_principal); if (service_principal != NULL) krb5_free_principal(context, service_principal); if (kt != NULL) krb5_kt_close(context, kt); if (creds != NULL) krb5_free_creds(context, creds); krb5_free_keyblock_contents(context, session_key); free_ticket(ticket_reply); free_enc_tkt_part(enc_tkt_reply); return code; }