krb5_error_code KRB5_CALLCONV krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context) { if (auth_context == NULL) return 0; if (auth_context->local_addr) krb5_free_address(context, auth_context->local_addr); if (auth_context->remote_addr) krb5_free_address(context, auth_context->remote_addr); if (auth_context->local_port) krb5_free_address(context, auth_context->local_port); if (auth_context->remote_port) krb5_free_address(context, auth_context->remote_port); if (auth_context->authentp) krb5_free_authenticator(context, auth_context->authentp); if (auth_context->key) krb5_k_free_key(context, auth_context->key); if (auth_context->send_subkey) krb5_k_free_key(context, auth_context->send_subkey); if (auth_context->recv_subkey) krb5_k_free_key(context, auth_context->recv_subkey); if (auth_context->rcache) krb5_rc_close(context, auth_context->rcache); if (auth_context->permitted_etypes) free(auth_context->permitted_etypes); if (auth_context->ad_context) krb5_authdata_context_free(context, auth_context->ad_context); free(auth_context); return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_rc_resolve_full(krb5_context context, krb5_rcache *id, const char *string_name) { krb5_error_code ret; *id = NULL; if(strncmp(string_name, "FILE:", 5)) { krb5_set_error_message(context, KRB5_RC_TYPE_NOTFOUND, N_("replay cache type %s not supported", ""), string_name); return KRB5_RC_TYPE_NOTFOUND; } ret = krb5_rc_resolve_type(context, id, "FILE"); if(ret) return ret; ret = krb5_rc_resolve(context, *id, string_name + 5); if (ret) { krb5_rc_close(context, *id); *id = NULL; } return ret; }
/* * krb5_rcache_internalize() - Internalize the krb5_rcache. */ static krb5_error_code krb5_rcache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_rcache rcache; krb5_int32 ibuf; krb5_octet *bp; size_t remain; char *rcname; bp = *buffer; remain = *lenremain; kret = EINVAL; /* Read our magic number */ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) ibuf = 0; if (ibuf == KV5M_RCACHE) { kret = ENOMEM; /* Get the length of the rcache name */ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (!kret && (rcname = (char *) malloc((size_t) (ibuf+1))) && !(kret = krb5_ser_unpack_bytes((krb5_octet *) rcname, (size_t) ibuf, &bp, &remain))) { rcname[ibuf] = '\0'; if (!(kret = krb5_rc_resolve_full(kcontext, &rcache, rcname))) { (void) krb5_rc_close(kcontext, rcache); (void) krb5_rc_recover(kcontext, rcache); if (!kret && !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) && (ibuf == KV5M_RCACHE)) { *buffer = bp; *lenremain = remain; *argp = (krb5_pointer) rcache; } else (void)krb5_rc_close(kcontext, rcache); } free(rcname); } } return(kret); }
/* * krb5_rcache_internalize() - Internalize the krb5_rcache. */ static krb5_error_code krb5_rcache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_rcache rcache = NULL; krb5_int32 ibuf; krb5_octet *bp; size_t remain; char *rcname = NULL; bp = *buffer; remain = *lenremain; /* Read our magic number */ if (krb5_ser_unpack_int32(&ibuf, &bp, &remain) || ibuf != KV5M_RCACHE) return EINVAL; /* Get the length of the rcache name */ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (kret) return kret; /* Get the rcache name. */ rcname = malloc(ibuf + 1); if (!rcname) return ENOMEM; kret = krb5_ser_unpack_bytes((krb5_octet*)rcname, (size_t) ibuf, &bp, &remain); if (kret) goto cleanup; rcname[ibuf] = '\0'; /* Resolve and recover the rcache. */ kret = krb5_rc_resolve_full(kcontext, &rcache, rcname); if (kret) goto cleanup; krb5_rc_recover(kcontext, rcache); /* Read our magic number again. */ kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); if (kret) goto cleanup; if (ibuf != KV5M_RCACHE) { kret = EINVAL; goto cleanup; } *buffer = bp; *lenremain = remain; *argp = (krb5_pointer) rcache; cleanup: free(rcname); if (kret != 0 && rcache) krb5_rc_close(kcontext, rcache); return kret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_rc_destroy(krb5_context context, krb5_rcache id) { int ret; if(remove(id->name) < 0) { ret = errno; krb5_set_error_string (context, "remove(%s): %s", id->name, strerror(ret)); return ret; } return krb5_rc_close(context, id); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_rc_destroy(krb5_context context, krb5_rcache id) { int ret; if(remove(id->name) < 0) { char buf[128]; ret = errno; rk_strerror_r(ret, buf, sizeof(buf)); krb5_set_error_message(context, ret, "remove(%s): %s", id->name, buf); return ret; } return krb5_rc_close(context, id); }
/* Convert a JSON value to an rcache handle or to NULL. */ static int json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out) { krb5_rcache rcache; *rcache_out = NULL; if (k5_json_get_tid(v) == K5_JSON_TID_NULL) return 0; if (k5_json_get_tid(v) != K5_JSON_TID_STRING) return -1; if (krb5_rc_resolve_full(context, &rcache, (char *)k5_json_string_utf8(v))) return -1; if (krb5_rc_recover_or_initialize(context, rcache, context->clockskew)) { krb5_rc_close(context, rcache); return -1; } *rcache_out = rcache; return 0; }
static void store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg, krb5_timestamp timestamp, krb5_int32 usec, krb5_timestamp now_timestamp, krb5_int32 now_usec) { krb5_rcache rc = NULL; krb5_error_code retval = 0; char *hash = NULL; krb5_donot_replay rep; krb5_data d; if (now_timestamp != 0) krb5_set_debugging_time(ctx, now_timestamp, now_usec); if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec))) goto cleanup; if ((retval = krb5_rc_recover_or_initialize(ctx, rc, ctx->clockskew))) goto cleanup; if (msg) { d.data = msg; d.length = strlen(msg); if ((retval = krb5_rc_hash_message(ctx, &d, &hash))) goto cleanup; } rep.client = client; rep.server = server; rep.msghash = hash; rep.cusec = usec; rep.ctime = timestamp; retval = krb5_rc_store(ctx, rc, &rep); cleanup: if (retval == KRB5KRB_AP_ERR_REPEAT) printf("Replay\n"); else if (!retval) printf("Entry successfully stored\n"); else fprintf(stderr, "Failure: %s\n", krb5_get_error_message(ctx, retval)); if (rc) krb5_rc_close(ctx, rc); if (hash) free(hash); }
static void expunge(krb5_context ctx, char *rcspec, krb5_timestamp now_timestamp, krb5_int32 now_usec) { krb5_rcache rc = NULL; krb5_error_code retval = 0; if (now_timestamp > 0) krb5_set_debugging_time(ctx, now_timestamp, now_usec); if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec))) goto cleanup; if ((retval = krb5_rc_recover_or_initialize(ctx, rc, ctx->clockskew))) goto cleanup; retval = krb5_rc_expunge(ctx, rc); cleanup: if (!retval) printf("Cache successfully expunged\n"); else fprintf(stderr, "Failure: %s\n", krb5_get_error_message(ctx, retval)); if (rc) krb5_rc_close(ctx, rc); }
krb5_error_code KRB5_CALLCONV krb5_get_server_rcache(krb5_context context, const krb5_data *piece, krb5_rcache *rcptr) { krb5_rcache rcache = 0; char *cachename = 0, *def_env = 0, *cachetype; char tmp[4], *full_name; krb5_error_code retval; int p, i; unsigned int len; #ifdef HAVE_GETEUID unsigned long tens; unsigned long uid = geteuid(); #endif if (piece == NULL) return ENOMEM; cachetype = krb5_rc_default_type(context); /* * Solaris Kerberos: Check to see if something other than the default replay * cache name will be used. If so then skip over the construction of * said name. */ if ((def_env = krb5_rc_default_name(context)) != 0) { cachename = strdup(def_env); if (cachename == NULL) return (ENOMEM); /* * We expect to have the fully qualified rcache name (<type>:<name>), * so we populate the default type here if the type is missing. */ if (strchr(cachename, ':') == NULL) { full_name = malloc(strlen(cachetype) + 1 + strlen(cachename) + 1); if (full_name == NULL) { free(cachename); return(ENOMEM); } (void) sprintf(full_name, "%s:%s", cachetype, cachename); free(cachename); cachename = full_name; } goto skip_create; } len = piece->length + 3 + 1; for (i = 0; i < piece->length; i++) { if (piece->data[i] == '-') len++; else if (!isvalidrcname((int) piece->data[i])) len += 3; } #ifdef HAVE_GETEUID len += 2; /* _<uid> */ for (tens = 1; (uid / tens) > 9 ; tens *= 10) len++; #endif cachename = malloc(strlen(cachetype) + 5 + len); if (!cachename) { retval = ENOMEM; goto cleanup; } strcpy(cachename, cachetype); p = strlen(cachename); cachename[p++] = ':'; for (i = 0; i < piece->length; i++) { if (piece->data[i] == '-') { cachename[p++] = '-'; cachename[p++] = '-'; continue; } if (!isvalidrcname((int) piece->data[i])) { sprintf(tmp, "%03o", piece->data[i]); cachename[p++] = '-'; cachename[p++] = tmp[0]; cachename[p++] = tmp[1]; cachename[p++] = tmp[2]; continue; } cachename[p++] = piece->data[i]; } #ifdef HAVE_GETEUID cachename[p++] = '_'; while (tens) { cachename[p++] = '0' + ((uid / tens) % 10); tens /= 10; } #endif cachename[p++] = '\0'; skip_create: retval = krb5_rc_resolve_full(context, &rcache, cachename); if (retval) { rcache = 0; goto cleanup; } /* * First try to recover the replay cache; if that doesn't work, * initialize it. */ retval = krb5_rc_recover_or_initialize(context, rcache, context->clockskew); if (retval) { krb5_rc_close(context, rcache); rcache = 0; goto cleanup; } *rcptr = rcache; rcache = 0; retval = 0; cleanup: if (rcache) krb5_xfree(rcache); if (cachename) krb5_xfree(cachename); return retval; }
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const char *realm, time_t time_offset, const DATA_BLOB *ticket, char **principal, struct PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key, bool use_replay_cache) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; NTSTATUS pac_ret; DATA_BLOB auth_data; krb5_context context = NULL; krb5_auth_context auth_context = NULL; krb5_data packet; krb5_ticket *tkt = NULL; krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; krb5_error_code ret = 0; int flags = 0; krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; bool auth_ok = False; bool got_auth_data = False; struct named_mutex *mutex = NULL; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); *principal = NULL; *pac_data = NULL; *ap_rep = data_blob_null; *session_key = data_blob_null; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); return NT_STATUS_LOGON_FAILURE; } if (time_offset != 0) { krb5_set_real_time(context, time(NULL) + time_offset, 0); } ret = krb5_set_default_realm(context, realm); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); goto out; } /* This whole process is far more complex than I would like. We have to go through all this to allow us to store the secret internally, instead of using /etc/krb5.keytab */ ret = krb5_auth_con_init(context, &auth_context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); goto out; } krb5_auth_con_getflags( context, auth_context, &flags ); if ( !use_replay_cache ) { /* Disable default use of a replay cache */ flags &= ~KRB5_AUTH_CONTEXT_DO_TIME; krb5_auth_con_setflags( context, auth_context, flags ); } if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) { goto out; } strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret))); goto out; } if ( use_replay_cache ) { /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 code surrounding the replay cache... */ mutex = grab_named_mutex(talloc_tos(), "replay cache mutex", 10); if (mutex == NULL) { DEBUG(1,("ads_verify_ticket: unable to protect " "replay cache with mutex.\n")); ret = KRB5_CC_IO; goto out; } /* JRA. We must set the rcache here. This will prevent replay attacks. */ ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache " "failed (%s)\n", error_message(ret))); goto out; } ret = krb5_auth_con_setrcache(context, auth_context, rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache " "failed (%s)\n", error_message(ret))); goto out; } } /* Try secrets.tdb first and fallback to the krb5.keytab if necessary */ auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, ticket, &tkt, &keyblock, &ret); if (!auth_ok && (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW)) { goto auth_failed; } if (!auth_ok && lp_use_kerberos_keytab()) { auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if ( use_replay_cache ) { TALLOC_FREE(mutex); #if 0 /* Heimdal leaks here, if we fix the leak, MIT crashes */ if (rcache) { krb5_rc_close(context, rcache); } #endif } auth_failed: if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); /* Try map the error return in case it's something like * a clock skew error. */ sret = krb5_to_nt_status(ret); if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { sret = NT_STATUS_LOGON_FAILURE; } DEBUG(10,("ads_verify_ticket: returning error %s\n", nt_errstr(sret) )); goto out; } authtime = get_authtime_from_tkt(tkt); client_principal = get_principal_from_tkt(tkt); ret = krb5_mk_rep(context, auth_context, &packet); if (ret) { DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", error_message(ret))); goto out; } *ap_rep = data_blob(packet.data, packet.length); if (packet.data) { kerberos_free_data_contents(context, &packet); ZERO_STRUCT(packet); } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); #if 0 file_save("/tmp/ticket.dat", ticket->data, ticket->length); #endif /* continue when no PAC is retrieved or we couldn't decode the PAC (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or Kerberos tickets encrypted using a DES key) - Guenther */ got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); if (!got_auth_data) { DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); } if (got_auth_data) { pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data); if (!NT_STATUS_IS_OK(pac_ret)) { DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret))); *pac_data = NULL; } data_blob_free(&auth_data); } #if 0 #if defined(HAVE_KRB5_TKT_ENC_PART2) /* MIT */ if (tkt->enc_part2) { file_save("/tmp/authdata.dat", tkt->enc_part2->authorization_data[0]->contents, tkt->enc_part2->authorization_data[0]->length); } #else /* Heimdal */ if (tkt->ticket.authorization_data) { file_save("/tmp/authdata.dat", tkt->ticket.authorization_data->val->ad_data.data, tkt->ticket.authorization_data->val->ad_data.length); } #endif #endif if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) { DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); sret = NT_STATUS_LOGON_FAILURE; goto out; } sret = NT_STATUS_OK; out: TALLOC_FREE(mutex); if (!NT_STATUS_IS_OK(sret)) { data_blob_free(&auth_data); } if (!NT_STATUS_IS_OK(sret)) { data_blob_free(ap_rep); } if (host_princ) { krb5_free_principal(context, host_princ); } if (keyblock) { krb5_free_keyblock(context, keyblock); } if (tkt != NULL) { krb5_free_ticket(context, tkt); } SAFE_FREE(host_princ_s); if (auth_context) { krb5_auth_con_free(context, auth_context); } if (context) { krb5_free_context(context); } return sret; }
static krb5_error_code recvauth(int f, krb5_context krb_context, unsigned int *valid_checksum, krb5_ticket **ticket, int *auth_type, krb5_principal *client, int encr_flag, krb5_keytab keytab) { krb5_error_code status = 0; krb5_auth_context auth_context = NULL; krb5_rcache rcache; krb5_authenticator *authenticator; krb5_data inbuf; krb5_data auth_version; *valid_checksum = 0; if ((status = krb5_auth_con_init(krb_context, &auth_context))) return (status); /* Only need remote address for rd_cred() to verify client */ if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) return (status); status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache); if (status) return (status); if (!rcache) { krb5_principal server; status = krb5_sname_to_principal(krb_context, 0, 0, KRB5_NT_SRV_HST, &server); if (status) return (status); status = krb5_get_server_rcache(krb_context, krb5_princ_component(krb_context, server, 0), &rcache); krb5_free_principal(krb_context, server); if (status) return (status); status = krb5_auth_con_setrcache(krb_context, auth_context, rcache); if (status) return (status); } if ((status = krb5_compat_recvauth(krb_context, &auth_context, &f, NULL, /* Specify daemon principal */ 0, /* no flags */ keytab, /* NULL to use v5srvtab */ ticket, /* return ticket */ auth_type, /* authentication system */ &auth_version))) { if (*auth_type == KRB5_RECVAUTH_V5) { /* * clean up before exiting */ getstr(f, rusername, sizeof (rusername), "remuser"); getstr(f, lusername, sizeof (lusername), "locuser"); getstr(f, term, sizeof (term), "Terminal type"); } return (status); } getstr(f, lusername, sizeof (lusername), "locuser"); getstr(f, term, sizeof (term), "Terminal type"); kcmd_protocol = KCMD_UNKNOWN_PROTOCOL; if (auth_version.length != 9 || auth_version.data == NULL) { syslog(LOG_ERR, "Bad application protocol version length in " "KRB5 exchange, exiting"); fatal(f, "Bad application version length, exiting."); } /* * Determine which Kerberos CMD protocol was used. */ if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) { kcmd_protocol = KCMD_OLD_PROTOCOL; } else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) { kcmd_protocol = KCMD_NEW_PROTOCOL; } else { syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting", (char *)auth_version.data); fatal(f, "Unrecognized KCMD protocol, exiting"); } if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag && kcmd_protocol == KCMD_OLD_PROTOCOL) { if ((status = krb5_auth_con_getauthenticator(krb_context, auth_context, &authenticator))) return (status); if (authenticator->checksum) { struct sockaddr_storage adr; int adr_length = sizeof (adr); int buflen; krb5_data input; krb5_keyblock key; char *chksumbuf; /* * Define the lenght of the chksum buffer. * chksum string = "[portnum]:termstr:username" * The extra 32 is to hold a integer string for * the portnumber. */ buflen = strlen(term) + strlen(lusername) + 32; chksumbuf = (char *)malloc(buflen); if (chksumbuf == 0) { krb5_free_authenticator(krb_context, authenticator); fatal(f, "Out of memory error"); } if (getsockname(f, (struct sockaddr *)&adr, &adr_length) != 0) { krb5_free_authenticator(krb_context, authenticator); fatal(f, "getsockname error"); } (void) snprintf(chksumbuf, buflen, "%u:%s%s", ntohs(SOCK_PORT(adr)), term, lusername); input.data = chksumbuf; input.length = strlen(chksumbuf); key.contents = (*ticket)->enc_part2->session->contents; key.length = (*ticket)->enc_part2->session->length; status = krb5_c_verify_checksum(krb_context, &key, 0, &input, authenticator->checksum, valid_checksum); if (status == 0 && *valid_checksum == 0) status = KRB5KRB_AP_ERR_BAD_INTEGRITY; if (chksumbuf) krb5_xfree(chksumbuf); if (status) { krb5_free_authenticator(krb_context, authenticator); return (status); } } krb5_free_authenticator(krb_context, authenticator); } if ((status = krb5_copy_principal(krb_context, (*ticket)->enc_part2->client, client))) return (status); /* Get the Unix username of the remote user */ getstr(f, rusername, sizeof (rusername), "remuser"); /* Get the Kerberos principal name string of the remote user */ if ((status = krb5_unparse_name(krb_context, *client, &krusername))) return (status); #ifdef DEBUG syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s", (krusername != NULL ? krusername : "******")); #endif if (encr_flag) { status = krb5_auth_con_getremotesubkey(krb_context, auth_context, &session_key); if (status) { syslog(LOG_ERR, "Error getting KRB5 session " "subkey, exiting"); fatal(f, "Error getting KRB5 session subkey, exiting"); } /* * The "new" protocol requires that a subkey be sent. */ if (session_key == NULL && kcmd_protocol == KCMD_NEW_PROTOCOL) { syslog(LOG_ERR, "No KRB5 session subkey sent, exiting"); fatal(f, "No KRB5 session subkey sent, exiting"); } /* * The "old" protocol does not permit an authenticator subkey. * The key is taken from the ticket instead (see below). */ if (session_key != NULL && kcmd_protocol == KCMD_OLD_PROTOCOL) { syslog(LOG_ERR, "KRB5 session subkey not permitted " "with old KCMD protocol, exiting"); fatal(f, "KRB5 session subkey not permitted " "with old KCMD protocol, exiting"); } /* * If no key at this point, use the session key from * the ticket. */ if (session_key == NULL) { /* * Save the session key so we can configure the crypto * module later. */ status = krb5_copy_keyblock(krb_context, (*ticket)->enc_part2->session, &session_key); if (status) { syslog(LOG_ERR, "krb5_copy_keyblock failed"); fatal(f, "krb5_copy_keyblock failed"); } } /* * If session key still cannot be found, we must * exit because encryption is required here * when encr_flag (-x) is set. */ if (session_key == NULL) { syslog(LOG_ERR, "Could not find an encryption key," "exiting"); fatal(f, "Encryption required but key not found, " "exiting"); } } /* * Use krb5_read_message to read the principal stuff. */ if ((status = krb5_read_message(krb_context, (krb5_pointer)&f, &inbuf))) fatal(f, "Error reading krb5 message"); if (inbuf.length) { /* Forwarding being done, read creds */ krb5_creds **creds = NULL; if (status = krb5_rd_cred(krb_context, auth_context, &inbuf, &creds, NULL)) { if (rcache) (void) krb5_rc_close(krb_context, rcache); krb5_free_creds(krb_context, *creds); fatal(f, "Can't get forwarded credentials"); } /* Store the forwarded creds in the ccache */ if (status = store_forw_creds(krb_context, creds, *ticket, lusername, &ccache)) { if (rcache) (void) krb5_rc_close(krb_context, rcache); krb5_free_creds(krb_context, *creds); fatal(f, "Can't store forwarded credentials"); } krb5_free_creds(krb_context, *creds); } if (rcache) (void) krb5_rc_close(krb_context, rcache); return (status); }
int main(int argc, char **argv) { krb5_error_code retval; krb5_context kcontext; int errout = 0; krb5_boolean log_stderr_set; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "KRB5KDC_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS))) { fprintf(stderr, gettext("%s: cannot get memory for realm list\n"), argv[0]); exit(1); } memset((char *) kdc_realmlist, 0, (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS)); /* * A note about Kerberos contexts: This context, "kcontext", is used * for the KDC operations, i.e. setup, network connection and error * reporting. The per-realm operations use the "realm_context" * associated with each realm. */ retval = krb5int_init_context_kdc(&kcontext); if (retval) { com_err(argv[0], retval, gettext("while initializing krb5")); exit(1); } krb5_klog_init(kcontext, "kdc", argv[0], 1); /* * Solaris Kerberos: * In the early stages of krb5kdc it is desirable to log error messages * to stderr as well as any other logging locations specified in config * files. */ log_stderr_set = krb5_klog_logging_to_stderr(); if (log_stderr_set != TRUE) { krb5_klog_add_stderr(); } /* initialize_kdc5_error_table(); SUNWresync121 XXX */ /* * Scan through the argument list */ initialize_realms(kcontext, argc, argv); setup_signal_handlers(); load_preauth_plugins(kcontext); retval = setup_sam(); if (retval) { com_err(argv[0], retval, gettext("while initializing SAM")); finish_realms(argv[0]); return 1; } if ((retval = setup_network(argv[0]))) { com_err(argv[0], retval, gettext("while initializing network")); finish_realms(argv[0]); return 1; } /* Solaris Kerberos: Remove the extra stderr logging */ if (log_stderr_set != TRUE) krb5_klog_remove_stderr(); /* * Solaris Kerberos: * List the logs (FILE, STDERR, etc) which are currently being * logged to and print that to stderr. Useful when trying to * track down a failure via SMF. */ if (retval = krb5_klog_list_logs(argv[0])) { com_err(argv[0], retval, gettext("while listing logs")); if (log_stderr_set != TRUE) { fprintf(stderr, gettext("%s: %s while listing logs\n"), argv[0], error_message(retval)); } } if (!nofork && daemon(0, 0)) { com_err(argv[0], errno, gettext("while detaching from tty")); if (log_stderr_set != TRUE) { fprintf(stderr, gettext("%s: %s while detaching from tty\n"), argv[0], strerror(errno)); } finish_realms(argv[0]); return 1; } if (retval = krb5_klog_syslog(LOG_INFO, "commencing operation")) { com_err(argv[0], retval, gettext("while logging message")); errout++; }; if ((retval = listen_and_process(argv[0]))) { com_err(argv[0], retval, gettext("while processing network requests")); errout++; } if ((retval = closedown_network(argv[0]))) { com_err(argv[0], retval, gettext("while shutting down network")); errout++; } krb5_klog_syslog(LOG_INFO, "shutting down"); unload_preauth_plugins(kcontext); krb5_klog_close(kdc_context); finish_realms(argv[0]); if (kdc_realmlist) free(kdc_realmlist); #ifdef USE_RCACHE (void) krb5_rc_close(kcontext, kdc_rcache); #endif #ifndef NOCACHE kdc_free_lookaside(kcontext); #endif krb5_free_context(kcontext); return errout; }
/* * Do a serialization test. */ static krb5_error_code ser_data(int verbose, char *msg, krb5_pointer ctx, krb5_magic dtype) { krb5_error_code kret; krb5_context ser_ctx; krb5_pointer nctx; krb5_octet *outrep, *ibuf, *outrep2; size_t outlen, ilen, outlen2; /* Initialize context and initialize all Kerberos serializers */ if ((kret = krb5_init_context(&ser_ctx))) { printf("Couldn't initialize krb5 library: %s\n", error_message(kret)); exit(1); } krb5_ser_context_init(ser_ctx); krb5_ser_auth_context_init(ser_ctx); krb5_ser_ccache_init(ser_ctx); krb5_ser_rcache_init(ser_ctx); krb5_ser_keytab_init(ser_ctx); /* Externalize the data */ kret = krb5_externalize_data(ser_ctx, ctx, &outrep, &outlen); if (!kret) { if (verbose) { printf("%s: externalized in %d bytes\n", msg, outlen); print_erep(outrep, outlen); } /* Now attempt to re-constitute it */ ibuf = outrep; ilen = outlen; kret = krb5_internalize_opaque(ser_ctx, dtype, (krb5_pointer *) &nctx, &ibuf, &ilen); if (!kret) { if (ilen) printf("%s: %d bytes left over after internalize\n", msg, ilen); /* Now attempt to re-externalize it */ kret = krb5_externalize_data(ser_ctx, nctx, &outrep2, &outlen2); if (!kret) { /* Compare the results. */ if ((outlen2 != outlen) || memcmp(outrep, outrep2, outlen)) { printf("%s: comparison failed\n", msg); print_erep(outrep2, outlen2); } else { if (verbose) printf("%s: compare succeeded\n", msg); } krb5_xfree(outrep2); } else printf("%s: second externalize returned %d\n", msg, kret); /* Free the data */ switch (dtype) { case KV5M_CONTEXT: krb5_free_context((krb5_context) nctx); break; case KV5M_AUTH_CONTEXT: if (nctx) { krb5_auth_context actx; actx = (krb5_auth_context) nctx; if (actx->i_vector) krb5_xfree(actx->i_vector); } krb5_auth_con_free(ser_ctx, (krb5_auth_context) nctx); break; case KV5M_CCACHE: krb5_cc_close(ser_ctx, (krb5_ccache) nctx); break; case KV5M_RCACHE: krb5_rc_close(ser_ctx, (krb5_rcache) nctx); break; case KV5M_KEYTAB: krb5_kt_close(ser_ctx, (krb5_keytab) nctx); break; case KV5M_ENCRYPT_BLOCK: if (nctx) { krb5_encrypt_block *eblock; eblock = (krb5_encrypt_block *) nctx; #if 0 if (eblock->priv && eblock->priv_size) krb5_xfree(eblock->priv); #endif if (eblock->key) krb5_free_keyblock(ser_ctx, eblock->key); krb5_xfree(eblock); } break; case KV5M_PRINCIPAL: krb5_free_principal(ser_ctx, (krb5_principal) nctx); break; case KV5M_CHECKSUM: krb5_free_checksum(ser_ctx, (krb5_checksum *) nctx); break; default: printf("don't know how to free %d\n", dtype); break; } } else printf("%s: internalize returned %d\n", msg, kret); krb5_xfree(outrep); } else printf("%s: externalize_data returned %d\n", msg, kret); krb5_free_context(ser_ctx); return(kret); }