static krb5_error_code decode_rx_header (krb5_storage *sp, struct rx_header *h) { krb5_error_code ret; ret = krb5_ret_uint32(sp, &h->epoch); if (ret) return ret; ret = krb5_ret_uint32(sp, &h->connid); if (ret) return ret; ret = krb5_ret_uint32(sp, &h->callid); if (ret) return ret; ret = krb5_ret_uint32(sp, &h->seqno); if (ret) return ret; ret = krb5_ret_uint32(sp, &h->serialno); if (ret) return ret; ret = krb5_ret_uint8(sp, &h->type); if (ret) return ret; ret = krb5_ret_uint8(sp, &h->flags); if (ret) return ret; ret = krb5_ret_uint8(sp, &h->status); if (ret) return ret; ret = krb5_ret_uint8(sp, &h->secindex); if (ret) return ret; ret = krb5_ret_uint16(sp, &h->reserved); if (ret) return ret; ret = krb5_ret_uint16(sp, &h->serviceid); if (ret) return ret; return 0; }
static krb5_error_code KRB5_CALLCONV akf_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *c) { int32_t ret; struct akf_data *d = id->data; c->fd = open (d->filename, O_RDONLY | O_BINARY | O_CLOEXEC, 0600); if (c->fd < 0) { ret = errno; krb5_set_error_message(context, ret, N_("keytab afs keyfile open %s failed: %s", ""), d->filename, strerror(ret)); return ret; } c->sp = krb5_storage_from_fd(c->fd); ret = krb5_ret_uint32(c->sp, &d->num_entries); if(ret) { krb5_storage_free(c->sp); close(c->fd); krb5_clear_error_message (context); if(ret == KRB5_KT_END) return KRB5_KT_NOTFOUND; return ret; } return 0; }
/* * Request: * NameZ * UID * GID * * Response: * */ static krb5_error_code kcm_op_chown(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { uint32_t uid; uint32_t gid; krb5_error_code ret; kcm_ccache ccache; char *name; ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_uint32(request, &uid); if (ret) { free(name); return ret; } ret = krb5_ret_uint32(request, &gid); if (ret) { free(name); return ret; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret) { free(name); return ret; } ret = kcm_chown(context, client, ccache, uid, gid); free(name); kcm_release_ccache(context, ccache); return ret; }
krb5_error_code _kadm5_xdr_ret_auth_opaque(krb5_storage *msg, struct _kadm5_xdr_opaque_auth *ao) { krb5_error_code ret; ret = krb5_ret_uint32(msg, &ao->flavor); if (ret) return ret; ret = _kadm5_xdr_ret_data_xdr(msg, &ao->data); return ret; }
krb5_error_code _kadm5_xdr_ret_gacred(krb5_data *data, struct _kadm5_xdr_gacred *gacred) { krb5_storage *sp; memset(gacred, 0, sizeof(*gacred)); sp = krb5_storage_from_data(data); INSIST(sp != NULL); CHECK(krb5_ret_uint32(sp, &gacred->version)); CHECK(krb5_ret_uint32(sp, &gacred->auth_msg)); CHECK(_kadm5_xdr_ret_data_xdr(sp, &gacred->handle)); krb5_storage_free(sp); return 0; }
krb5_error_code _kadm5_xdr_ret_gss_init_res(krb5_storage *sp, krb5_data *handle, OM_uint32 *maj_stat, OM_uint32 *min_stat, uint32_t *seq_window, krb5_data *out) { krb5_error_code ret; ret = _kadm5_xdr_ret_data_xdr(sp, handle); if (ret) return ret; ret = krb5_ret_uint32(sp, maj_stat); if (ret) return ret; ret = krb5_ret_uint32(sp, min_stat); if (ret) return ret; ret = krb5_ret_uint32(sp, seq_window); if (ret) return ret; ret = _kadm5_xdr_ret_data_xdr(sp, out); return ret; }
kadm5_ret_t kadm5_c_get_privs(void *server_handle, uint32_t *privs) { kadm5_client_context *context = server_handle; kadm5_ret_t ret; krb5_storage *sp; unsigned char buf[1024]; int32_t tmp; krb5_data reply; *privs = 0; ret = _kadm5_connect(server_handle); if (ret) return ret; krb5_data_zero(&reply); sp = krb5_storage_from_mem(buf, sizeof(buf)); if (sp == NULL) { ret = krb5_enomem(context->context); goto out_keep_error; } ret = krb5_store_int32(sp, kadm_get_privs); if (ret) goto out; ret = _kadm5_client_send(context, sp); if (ret) goto out_keep_error; ret = _kadm5_client_recv(context, &reply); if (ret) goto out_keep_error; krb5_storage_free(sp); sp = krb5_storage_from_data(&reply); if (sp == NULL) { ret = krb5_enomem(context->context); goto out_keep_error; } ret = krb5_ret_int32(sp, &tmp); if (ret == 0) ret = tmp; if (ret == 0) krb5_ret_uint32(sp, privs); out: krb5_clear_error_message(context->context); out_keep_error: krb5_storage_free(sp); krb5_data_free (&reply); return ret; }
void _gss_scram_iter_creds_f(OM_uint32 flags, void *userctx , void (*cred_iter)(void *, gss_OID, gss_cred_id_t)) { krb5_error_code ret; krb5_context context = NULL; krb5_storage *request, *response; krb5_data response_data; ret = krb5_init_context(&context); if (ret) goto done; ret = krb5_kcm_storage_request(context, KCM_OP_GET_SCRAM_USER_LIST, &request); if (ret) goto done; ret = krb5_kcm_call(context, request, &response, &response_data); krb5_storage_free(request); if (ret) goto done; while (1) { uint32_t morep; kcmuuid_t uuid; char *user = NULL; krb5_ssize_t sret; ret = krb5_ret_uint32(response, &morep); if (ret) goto out; if (!morep) goto out; ret = krb5_ret_stringz(response, &user); if (ret) goto out; sret = krb5_storage_read(response, uuid, sizeof(uuid)); if (sret != sizeof(uuid)) goto out; cred_iter(userctx, GSS_SCRAM_MECHANISM, (gss_cred_id_t)user); } out: krb5_storage_free(response); krb5_data_free(&response_data); done: if (context) krb5_free_context(context); (*cred_iter)(userctx, NULL, NULL); }
/* * Request: * NameZ * WhichFields * MatchCreds * * Response: * */ static krb5_error_code kcm_op_remove_cred(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { uint32_t whichfields; krb5_creds mcreds; krb5_error_code ret; kcm_ccache ccache; char *name; ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_uint32(request, &whichfields); if (ret) { free(name); return ret; } ret = krb5_ret_creds_tag(request, &mcreds); if (ret) { free(name); return ret; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret) { free(name); krb5_free_cred_contents(context, &mcreds); return ret; } ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds); /* XXX need to remove any events that match */ free(name); krb5_free_cred_contents(context, &mcreds); kcm_release_ccache(context, ccache); return ret; }
/* * Request: * NameZ * Flags * * Response: * */ static krb5_error_code kcm_op_set_flags(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { uint32_t flags; krb5_error_code ret; kcm_ccache ccache; char *name; ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_uint32(request, &flags); if (ret) { free(name); return ret; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret) { free(name); return ret; } /* we don't really support any flags yet */ free(name); kcm_release_ccache(context, ccache); return 0; }
static void test_uint32(krb5_context context, krb5_storage *sp) { krb5_error_code ret; int i; uint32_t val[] = { 0, 1, 4294967295UL }, v; krb5_storage_truncate(sp, 0); for (i = 0; i < sizeof(val[0])/sizeof(val); i++) { ret = krb5_store_uint32(sp, val[i]); if (ret) krb5_err(context, 1, ret, "krb5_store_uint32"); krb5_storage_seek(sp, 0, SEEK_SET); ret = krb5_ret_uint32(sp, &v); if (ret) krb5_err(context, 1, ret, "krb5_ret_uint32"); if (v != val[i]) krb5_errx(context, 1, "store and ret mismatch"); } }
/* * Request: * NameZ * ServerPrincipal * KDCFlags * EncryptionType * * Repsonse: * */ static krb5_error_code kcm_op_get_ticket(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { krb5_error_code ret; kcm_ccache ccache; char *name; krb5_principal server = NULL; krb5_ccache_data ccdata; krb5_creds in, *out; krb5_kdc_flags flags; memset(&in, 0, sizeof(in)); ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_uint32(request, &flags.i); if (ret) { free(name); return ret; } ret = krb5_ret_int32(request, &in.session.keytype); if (ret) { free(name); return ret; } ret = krb5_ret_principal(request, &server); if (ret) { free(name); return ret; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret) { krb5_free_principal(context, server); free(name); return ret; } HEIMDAL_MUTEX_lock(&ccache->mutex); /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); in.client = ccache->client; in.server = server; in.times.endtime = 0; /* glue cc layer will store creds */ ret = krb5_get_credentials_with_flags(context, 0, flags, &ccdata, &in, &out); HEIMDAL_MUTEX_unlock(&ccache->mutex); krb5_free_principal(context, server); if (ret == 0) krb5_free_cred_contents(context, out); kcm_release_ccache(context, ccache); free(name); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_pac_parse(krb5_context context, const void *ptr, size_t len, krb5_pac *pac) { krb5_error_code ret; krb5_pac p; krb5_storage *sp = NULL; uint32_t i, tmp, tmp2, header_end; p = calloc(1, sizeof(*p)); if (p == NULL) { ret = krb5_enomem(context); goto out; } sp = krb5_storage_from_readonly_mem(ptr, len); if (sp == NULL) { ret = krb5_enomem(context); goto out; } krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &tmp), out); CHECK(ret, krb5_ret_uint32(sp, &tmp2), out); if (tmp < 1) { ret = EINVAL; /* Too few buffers */ krb5_set_error_message(context, ret, N_("PAC have too few buffer", "")); goto out; } if (tmp2 != 0) { ret = EINVAL; /* Wrong version */ krb5_set_error_message(context, ret, N_("PAC have wrong version %d", ""), (int)tmp2); goto out; } p->pac = calloc(1, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1))); if (p->pac == NULL) { ret = krb5_enomem(context); goto out; } p->pac->numbuffers = tmp; p->pac->version = tmp2; header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); if (header_end > len) { ret = EINVAL; goto out; } for (i = 0; i < p->pac->numbuffers; i++) { CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out); CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out); CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out); CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out); /* consistency checks */ if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC out of allignment", "")); goto out; } if (p->pac->buffers[i].offset_hi) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC high offset set", "")); goto out; } if (p->pac->buffers[i].offset_lo > len) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC offset off end", "")); goto out; } if (p->pac->buffers[i].offset_lo < header_end) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC offset inside header: %lu %lu", ""), (unsigned long)p->pac->buffers[i].offset_lo, (unsigned long)header_end); goto out; } if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){ ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC length off end", "")); goto out; } /* let save pointer to data we need later */ if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { if (p->server_checksum) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC have two server checksums", "")); goto out; } p->server_checksum = &p->pac->buffers[i]; } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { if (p->privsvr_checksum) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC have two KDC checksums", "")); goto out; } p->privsvr_checksum = &p->pac->buffers[i]; } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { if (p->logon_name) { ret = EINVAL; krb5_set_error_message(context, ret, N_("PAC have two logon names", "")); goto out; } p->logon_name = &p->pac->buffers[i]; } } ret = krb5_data_copy(&p->data, ptr, len); if (ret) goto out; krb5_storage_free(sp); *pac = p; return 0; out: if (sp) krb5_storage_free(sp); if (p) { if (p->pac) free(p->pac); free(p); } *pac = NULL; return ret; }
void GSSAPI_CALLCONV _gss_ntlm_iter_creds_f(OM_uint32 flags, void *userctx , void (*cred_iter)(void *, gss_OID, gss_cred_id_t)) { #ifdef HAVE_KCM krb5_error_code ret; krb5_context context = NULL; krb5_storage *request, *response; krb5_data response_data; ret = krb5_init_context(&context); if (ret) goto done; ret = krb5_kcm_storage_request(context, KCM_OP_GET_NTLM_USER_LIST, &request); if (ret) goto done; ret = krb5_kcm_call(context, request, &response, &response_data); krb5_storage_free(request); if (ret) goto done; while (1) { uint32_t morep; char *user = NULL, *domain = NULL; ntlm_cred dn; ret = krb5_ret_uint32(response, &morep); if (ret) goto out; if (!morep) goto out; ret = krb5_ret_stringz(response, &user); if (ret) goto out; ret = krb5_ret_stringz(response, &domain); if (ret) { free(user); goto out; } dn = calloc(1, sizeof(*dn)); if (dn == NULL) { free(user); free(domain); goto out; } dn->username = user; dn->domain = domain; cred_iter(userctx, GSS_NTLM_MECHANISM, (gss_cred_id_t)dn); } out: krb5_storage_free(response); krb5_data_free(&response_data); done: if (context) krb5_free_context(context); #endif /* HAVE_KCM */ (*cred_iter)(userctx, NULL, NULL); }
int main(int argc, char **argv) { krb5_error_code ret, ret2; krb5_context context; krb5_auth_context auth_context; void *kadm_handle; kadm5_server_context *server_context; kadm5_config_params conf; int master_fd; krb5_ccache ccache; krb5_principal server; char **files; int optidx = 0; time_t reconnect_min; time_t backoff; time_t reconnect_max; time_t reconnect; time_t before = 0; int restarter_fd = -1; const char *master; setprogname(argv[0]); if (getarg(args, num_args, argc, argv, &optidx)) usage(1); if (help_flag) usage(0); 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) { if (asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)) == -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"); argc -= optidx; argv += optidx; if (argc != 1) usage(1); master = argv[0]; if (status_file == NULL) { if (asprintf(&status_file, "%s/ipropd-slave-status", hdb_db_dir(context)) < 0 || status_file == NULL) krb5_errx(context, 1, "can't allocate status file buffer"); } krb5_openlog(context, "ipropd-slave", &log_facility); krb5_set_warn_dest(context, log_facility); slave_status(context, status_file, "bootstrapping"); ret = krb5_kt_register(context, &hdb_get_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); time_before_lost = parse_time (server_time_lost, "s"); if (time_before_lost < 0) krb5_errx (context, 1, "couldn't parse time: %s", server_time_lost); slave_status(context, status_file, "getting credentials from keytab/database"); memset(&conf, 0, sizeof(conf)); if(realm) { conf.mask |= KADM5_CONFIG_REALM; conf.realm = realm; } ret = kadm5_init_with_password_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; slave_status(context, status_file, "creating log file"); ret = server_context->db->hdb_open(context, server_context->db, O_RDWR | O_CREAT, 0600); if (ret) krb5_err (context, 1, ret, "db->open"); ret = kadm5_log_init (server_context); if (ret) krb5_err (context, 1, ret, "kadm5_log_init"); ret = server_context->db->hdb_close (context, server_context->db); if (ret) krb5_err (context, 1, ret, "db->close"); get_creds(context, keytab_str, &ccache, master); ret = krb5_sname_to_principal (context, master, IPROP_NAME, KRB5_NT_SRV_HST, &server); if (ret) krb5_err (context, 1, ret, "krb5_sname_to_principal"); auth_context = NULL; master_fd = -1; krb5_appdefault_time(context, config_name, NULL, "reconnect-min", 10, &reconnect_min); krb5_appdefault_time(context, config_name, NULL, "reconnect-max", 300, &reconnect_max); krb5_appdefault_time(context, config_name, NULL, "reconnect-backoff", 10, &backoff); reconnect = reconnect_min; slave_status(context, status_file, "ipropd-slave started"); roken_detach_finish(NULL, daemon_child); restarter_fd = restarter(context, NULL); while (!exit_flag) { struct timeval to; time_t now, elapsed; fd_set readset; int connected = FALSE; #ifndef NO_LIMIT_FD_SETSIZE if (restarter_fd >= FD_SETSIZE) krb5_errx(context, IPROPD_RESTART, "fd too large"); #endif FD_ZERO(&readset); if (restarter_fd > -1) FD_SET(restarter_fd, &readset); now = time(NULL); elapsed = now - before; if (elapsed < reconnect) { time_t left = reconnect - elapsed; krb5_warnx(context, "sleeping %d seconds before " "retrying to connect", (int)left); to.tv_sec = left; to.tv_usec = 0; if (select(restarter_fd + 1, &readset, NULL, NULL, &to) == 1) { exit_flag = SIGTERM; continue; } } before = now; slave_status(context, status_file, "connecting to master: %s\n", master); master_fd = connect_to_master (context, master, port_str); if (master_fd < 0) goto retry; reconnect = reconnect_min; if (auth_context) { krb5_auth_con_free(context, auth_context); auth_context = NULL; krb5_cc_destroy(context, ccache); get_creds(context, keytab_str, &ccache, master); } if (verbose) krb5_warnx(context, "authenticating to master"); ret = krb5_sendauth (context, &auth_context, &master_fd, IPROP_VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, ccache, NULL, NULL, NULL); if (ret) { krb5_warn (context, ret, "krb5_sendauth"); goto retry; } krb5_warnx(context, "ipropd-slave started at version: %ld", (long)server_context->log_context.version); ret = ihave(context, auth_context, master_fd, server_context->log_context.version); if (ret) goto retry; connected = TRUE; if (verbose) krb5_warnx(context, "connected to master"); slave_status(context, status_file, "connected to master, waiting instructions"); while (connected && !exit_flag) { krb5_data out; krb5_storage *sp; uint32_t tmp; int max_fd; #ifndef NO_LIMIT_FD_SETSIZE if (master_fd >= FD_SETSIZE) krb5_errx(context, IPROPD_RESTART, "fd too large"); if (restarter_fd >= FD_SETSIZE) krb5_errx(context, IPROPD_RESTART, "fd too large"); max_fd = max(restarter_fd, master_fd); #endif FD_ZERO(&readset); FD_SET(master_fd, &readset); if (restarter_fd != -1) FD_SET(restarter_fd, &readset); to.tv_sec = time_before_lost; to.tv_usec = 0; ret = select (max_fd + 1, &readset, NULL, NULL, &to); if (ret < 0) { if (errno == EINTR) continue; else krb5_err (context, 1, errno, "select"); } if (ret == 0) { krb5_warnx(context, "server didn't send a message " "in %d seconds", time_before_lost); connected = FALSE; continue; } if (restarter_fd > -1 && FD_ISSET(restarter_fd, &readset)) { if (verbose) krb5_warnx(context, "slave restarter exited"); exit_flag = SIGTERM; } if (!FD_ISSET(master_fd, &readset)) continue; if (verbose) krb5_warnx(context, "message from master"); ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); if (ret) { krb5_warn(context, ret, "krb5_read_priv_message"); connected = FALSE; continue; } sp = krb5_storage_from_mem (out.data, out.length); if (sp == NULL) krb5_err(context, IPROPD_RESTART, errno, "krb5_storage_from_mem"); ret = krb5_ret_uint32(sp, &tmp); if (ret == HEIM_ERR_EOF) { krb5_warn(context, ret, "master sent zero-length message"); connected = FALSE; continue; } if (ret != 0) { krb5_warn(context, ret, "couldn't read master's message"); connected = FALSE; continue; } ret = server_context->db->hdb_open(context, server_context->db, O_RDWR | O_CREAT, 0600); if (ret) krb5_err (context, 1, ret, "db->open while handling a " "message from the master"); ret = kadm5_log_init(server_context); if (ret) { krb5_err(context, IPROPD_RESTART, ret, "kadm5_log_init while " "handling a message from the master"); } ret = server_context->db->hdb_close (context, server_context->db); if (ret) krb5_err (context, 1, ret, "db->close while handling a " "message from the master"); switch (tmp) { case FOR_YOU : if (verbose) krb5_warnx(context, "master sent us diffs"); ret2 = receive(context, sp, server_context); if (ret2) krb5_warn(context, ret2, "receive from ipropd-master had errors"); ret = ihave(context, auth_context, master_fd, server_context->log_context.version); if (ret || ret2) connected = FALSE; /* * If it returns an error, receive() may nonetheless * have committed some entries successfully, so we must * update the slave_status even if there were errors. */ is_up_to_date(context, status_file, server_context); break; case TELL_YOU_EVERYTHING : if (verbose) krb5_warnx(context, "master sent us a full dump"); ret = receive_everything(context, master_fd, server_context, auth_context); if (ret == 0) { ret = ihave(context, auth_context, master_fd, server_context->log_context.version); } if (ret) connected = FALSE; else is_up_to_date(context, status_file, server_context); break; case ARE_YOU_THERE : if (verbose) krb5_warnx(context, "master sent us a ping"); is_up_to_date(context, status_file, server_context); ret = ihave(context, auth_context, master_fd, server_context->log_context.version); if (ret) connected = FALSE; send_im_here(context, master_fd, auth_context); break; case YOU_HAVE_LAST_VERSION: if (verbose) krb5_warnx(context, "master tells us we are up to date"); is_up_to_date(context, status_file, server_context); break; case NOW_YOU_HAVE : case I_HAVE : case ONE_PRINC : case I_AM_HERE : default : krb5_warnx (context, "Ignoring command %d", tmp); break; } krb5_storage_free (sp); krb5_data_free (&out); } slave_status(context, status_file, "disconnected from master"); retry: if (connected == FALSE) krb5_warnx (context, "disconnected for server"); if (exit_flag) krb5_warnx (context, "got an exit signal"); if (master_fd >= 0) close(master_fd); reconnect += backoff; if (reconnect > reconnect_max) { slave_status(context, status_file, "disconnected from master for a long time"); reconnect = reconnect_max; } } if (status_file) { /* XXX It'd be better to leave it saying we're not here */ unlink(status_file); } if (0); #ifndef NO_SIGXCPU else if(exit_flag == SIGXCPU) krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); #endif else if(exit_flag == SIGINT || exit_flag == SIGTERM) krb5_warnx(context, "%s terminated", getprogname()); else krb5_warnx(context, "%s unexpected exit reason: %ld", getprogname(), (long)exit_flag); return 0; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_sec_context ( OM_uint32 * minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t * context_handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_context context; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; krb5_address local, remote; krb5_address *localp, *remotep; krb5_data data; gss_buffer_desc buffer; krb5_keyblock keyblock; int32_t flags, tmp; gsskrb5_ctx ctx; gss_name_t name; GSSAPI_KRB5_INIT (&context); *context_handle = GSS_C_NO_CONTEXT; localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* flags */ *minor_status = 0; if (krb5_ret_int32 (sp, &flags) != 0) goto failure; /* retrieve the auth context */ ac = ctx->auth_context; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->flags = tmp; if (flags & SC_LOCAL_ADDRESS) { if (krb5_ret_address (sp, localp = &local) != 0) goto failure; } if (flags & SC_REMOTE_ADDRESS) { if (krb5_ret_address (sp, remotep = &remote) != 0) goto failure; } krb5_auth_con_setaddrs (context, ac, localp, remotep); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) goto failure; if (krb5_ret_int16 (sp, &ac->remote_port) != 0) goto failure; if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_uint32 (sp, &ac->remote_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->keytype = tmp; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->cksumtype = tmp; /* names */ if (krb5_ret_data (sp, &data)) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->source = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->target = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->endtime = tmp; ret = _gssapi_msg_order_import(minor_status, sp, &ctx->gk5c.order); if (ret) goto failure; krb5_storage_free (sp); _gsskrb5i_is_cfx(context, ctx, (ctx->more_flags & LOCAL) == 0); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; failure: krb5_auth_con_free (context, ctx->auth_context); if (ctx->source != NULL) krb5_free_principal(context, ctx->source); if (ctx->target != NULL) krb5_free_principal(context, ctx->target); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); if(ctx->gk5c.order) _gssapi_msg_order_destroy(&ctx->gk5c.order); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); krb5_storage_free (sp); free (ctx); *context_handle = GSS_C_NO_CONTEXT; return ret; }
static krb5_error_code mdb_value2entry(krb5_context context, krb5_data *data, hdb_entry *entry) { krb5_error_code ret; krb5_storage *sp; uint32_t u32; uint16_t u16, num_keys, num_tl; size_t i, j; char *p = NULL; sp = krb5_storage_from_data(data); if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "out of memory"); return ENOMEM; } krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); /* 16: baselength */ CHECK(ret = krb5_ret_uint16(sp, &u16)); if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } /* 32: attributes */ CHECK(ret = krb5_ret_uint32(sp, &u32)); entry->flags.postdate = !(u16 & KRB5_KDB_DISALLOW_POSTDATED); entry->flags.forwardable = !(u16 & KRB5_KDB_DISALLOW_FORWARDABLE); entry->flags.initial = !!(u16 & KRB5_KDB_DISALLOW_TGT_BASED); entry->flags.renewable = !(u16 & KRB5_KDB_DISALLOW_RENEWABLE); entry->flags.proxiable = !(u16 & KRB5_KDB_DISALLOW_PROXIABLE); /* DUP_SKEY */ entry->flags.invalid = !!(u16 & KRB5_KDB_DISALLOW_ALL_TIX); entry->flags.require_preauth =!!(u16 & KRB5_KDB_REQUIRES_PRE_AUTH); entry->flags.require_hwauth =!!(u16 & KRB5_KDB_REQUIRES_HW_AUTH); entry->flags.server = !(u16 & KRB5_KDB_DISALLOW_SVR); entry->flags.change_pw = !!(u16 & KRB5_KDB_PWCHANGE_SERVICE); entry->flags.client = 1; /* XXX */ /* 32: max time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->max_life = malloc(sizeof(*entry->max_life)); *entry->max_life = u32; } /* 32: max renewable time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->max_renew = malloc(sizeof(*entry->max_renew)); *entry->max_renew = u32; } /* 32: client expire */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->valid_end = malloc(sizeof(*entry->valid_end)); *entry->valid_end = u32; } /* 32: passwd expire */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->pw_end = malloc(sizeof(*entry->pw_end)); *entry->pw_end = u32; } /* 32: last successful passwd */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 32: last failed attempt */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 32: num of failed attempts */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 16: num tl data */ CHECK(ret = krb5_ret_uint16(sp, &u16)); num_tl = u16; /* 16: num key data */ CHECK(ret = krb5_ret_uint16(sp, &u16)); num_keys = u16; /* 16: principal length */ CHECK(ret = krb5_ret_uint16(sp, &u16)); /* length: principal */ { p = malloc(u16 + 1); krb5_storage_read(sp, p, u16); p[u16] = '\0'; CHECK(ret = krb5_parse_name(context, p, &entry->principal)); free(p); p = NULL; } /* for num tl data times 16: tl data type 16: tl data length length: length */ for (i = 0; i < num_tl; i++) { CHECK(ret = krb5_ret_uint16(sp, &u16)); CHECK(ret = krb5_ret_uint16(sp, &u16)); krb5_storage_seek(sp, u16, SEEK_CUR); } /* for num key data times 16: version (num keyblocks) 16: kvno for version times: 16: type 16: length length: keydata */ for (i = 0; i < num_keys; i++) { int keep = 0; uint16_t version; void *ptr; CHECK(ret = krb5_ret_uint16(sp, &u16)); version = u16; CHECK(ret = krb5_ret_uint16(sp, &u16)); if (entry->kvno < u16) { keep = 1; entry->kvno = u16; for (j = 0; j < entry->keys.len; j++) { free_Key(&entry->keys.val[j]); free(entry->keys.val); entry->keys.len = 0; entry->keys.val = NULL; } } else if (entry->kvno == u16) keep = 1; if (keep) { Key *k; ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1)); if (ptr == NULL) { ret = ENOMEM; goto out; } entry->keys.val = ptr; /* k points to current Key */ k = &entry->keys.val[entry->keys.len]; memset(k, 0, sizeof(*k)); entry->keys.len += 1; entry->keys.val[i].mkvno = malloc(sizeof(*entry->keys.val[i].mkvno)); if (entry->keys.val[i].mkvno == NULL) { ret = ENOMEM; goto out; } *entry->keys.val[i].mkvno = 1; for (j = 0; j < version; j++) { uint16_t type; CHECK(ret = krb5_ret_uint16(sp, &type)); CHECK(ret = krb5_ret_uint16(sp, &u16)); if (j == 0) { /* key */ k->key.keytype = type; if (u16 < 2) { ret = EINVAL; goto out; } krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ k->key.keyvalue.length = u16 - 2; k->key.keyvalue.data = malloc(k->key.keyvalue.length); krb5_storage_read(sp, k->key.keyvalue.data, k->key.keyvalue.length); } else if (j == 1) { /* salt */ k->salt = calloc(1, sizeof(*k->salt)); if (k->salt == NULL) { ret = ENOMEM; goto out; } k->salt->type = type; if (u16 != 0) { k->salt->salt.data = malloc(u16); if (k->salt->salt.data == NULL) { ret = ENOMEM; goto out; } k->salt->salt.length = u16; krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); } fix_salt(context, entry, entry->keys.len - 1); } else { krb5_storage_seek(sp, u16, SEEK_CUR); } } } else { /* skip */ for (j = 0; j < version; j++) { CHECK(ret = krb5_ret_uint16(sp, &u16)); CHECK(ret = krb5_ret_uint16(sp, &u16)); krb5_storage_seek(sp, u16, u16); } } } return 0; out: if (p) free(p); free_hdb_entry(entry); return ret; }
static int send_complete (krb5_context context, slave *s, const char *database, uint32_t current_version, uint32_t oldest_version, uint32_t initial_log_tstamp) { krb5_error_code ret; krb5_storage *dump = NULL; uint32_t vno = 0; krb5_data data; int fd = -1; struct stat st; char *dfn; ret = asprintf(&dfn, "%s/ipropd.dumpfile", hdb_db_dir(context)); if (ret == -1 || !dfn) { krb5_warn(context, ENOMEM, "Cannot allocate memory"); return ENOMEM; } fd = open(dfn, O_CREAT|O_RDWR, 0600); if (fd == -1) { ret = errno; krb5_warn(context, ret, "Cannot open/create iprop dumpfile %s", dfn); free(dfn); return ret; } free(dfn); dump = krb5_storage_from_fd(fd); if (!dump) { ret = errno; krb5_warn(context, ret, "krb5_storage_from_fd"); goto done; } for (;;) { ret = flock(fd, LOCK_SH); if (ret == -1) { ret = errno; krb5_warn(context, ret, "flock(fd, LOCK_SH)"); goto done; } if (krb5_storage_seek(dump, 0, SEEK_SET) == (off_t)-1) { ret = errno; krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); goto done; } vno = 0; ret = krb5_ret_uint32(dump, &vno); if (ret && ret != HEIM_ERR_EOF) { krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); goto done; } if (fstat(fd, &st) == -1) { ret = errno; krb5_warn(context, ret, "send_complete: could not stat dump file"); goto done; } /* * If the current dump has an appropriate version, then we can * break out of the loop and send the file below. */ if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && vno >= oldest_version && vno <= current_version) break; if (verbose) krb5_warnx(context, "send_complete: dumping HDB"); /* * Otherwise, we may need to write a new dump file. We * obtain an exclusive lock on the fd. Because this is * not guaranteed to be an upgrade of our existing shared * lock, someone else may have written a new dumpfile while * we were waiting and so we must first check the vno of * the dump to see if that happened. If it did, we need * to go back to the top of the loop so that we can downgrade * our lock to a shared one. */ ret = flock(fd, LOCK_EX); if (ret == -1) { ret = errno; krb5_warn(context, ret, "flock(fd, LOCK_EX)"); goto done; } ret = krb5_storage_seek(dump, 0, SEEK_SET); if (ret == -1) { ret = errno; krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); goto done; } vno = 0; ret = krb5_ret_uint32(dump, &vno); if (ret && ret != HEIM_ERR_EOF) { krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); goto done; } if (fstat(fd, &st) == -1) { ret = errno; krb5_warn(context, ret, "send_complete: could not stat dump file"); goto done; } /* check if someone wrote a better version for us */ if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && vno >= oldest_version && vno <= current_version) continue; /* Now, we know that we must write a new dump file. */ ret = write_dump(context, dump, database, current_version); if (ret) goto done; /* * And we must continue to the top of the loop so that we can * downgrade to a shared lock. */ } /* * Leaving the above loop, dump should have a ptr right after the initial * 4 byte DB version number and we should have a shared lock on the file * (which we may have just created), so we are reading to simply blast * the data down the wire. */ for (;;) { ret = krb5_ret_data(dump, &data); if (ret == HEIM_ERR_EOF) { ret = 0; /* EOF is not an error, it's success */ goto done; } if (ret) { krb5_warn(context, ret, "krb5_ret_data(dump, &data)"); slave_dead(context, s); goto done; } ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); krb5_data_free(&data); if (ret) { krb5_warn (context, ret, "krb5_write_priv_message"); slave_dead(context, s); goto done; } } done: if (!ret) { s->version = vno; slave_seen(s); } if (fd != -1) close(fd); if (dump) krb5_storage_free(dump); return ret; }
static krb5_error_code fkt_next_entry_int(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor, off_t *start, off_t *end) { struct fkt_data *d = id->data; int32_t len; int ret; int8_t tmp8; int32_t tmp32; uint32_t utmp32; off_t pos, curpos; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); loop: ret = krb5_ret_int32(cursor->sp, &len); if (ret) return ret; if(len < 0) { pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); goto loop; } ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); if (ret) goto out; ret = krb5_ret_uint32(cursor->sp, &utmp32); entry->timestamp = utmp32; if (ret) goto out; ret = krb5_ret_int8(cursor->sp, &tmp8); if (ret) goto out; entry->vno = tmp8; ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock); if (ret) goto out; /* there might be a 32 bit kvno here * if it's zero, assume that the 8bit one was right, * otherwise trust the new value */ curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if(len + 4 + pos - curpos >= 4) { ret = krb5_ret_int32(cursor->sp, &tmp32); if (ret == 0 && tmp32 != 0) entry->vno = tmp32; } /* there might be a flags field here */ if(len + 4 + pos - curpos >= 8) { ret = krb5_ret_uint32(cursor->sp, &utmp32); if (ret == 0) entry->flags = utmp32; } else entry->flags = 0; entry->aliases = NULL; if(start) *start = pos; if(end) *end = pos + 4 + len; out: if (ret) krb5_kt_free_entry(context, entry); krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); return ret; }
krb5_error_code KRB5_LIB_FUNCTION _krb5_krb_decomp_ticket(krb5_context context, const krb5_data *enc_ticket, const krb5_keyblock *key, const char *local_realm, char **sname, char **sinstance, struct _krb5_krb_auth_data *ad) { krb5_error_code ret; krb5_ssize_t size; krb5_storage *sp = NULL; krb5_data ticket; unsigned char des_key[8]; memset(ad, 0, sizeof(*ad)); krb5_data_zero(&ticket); *sname = NULL; *sinstance = NULL; RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error); sp = krb5_storage_from_data(&ticket); if (sp == NULL) { krb5_data_free(&ticket); krb5_set_error_string(context, "alloc: out of memory"); return ENOMEM; } krb5_storage_set_eof_code(sp, EINVAL); /* XXX */ RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error); RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error); RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error); RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error); RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error); size = krb5_storage_read(sp, des_key, sizeof(des_key)); if (size != sizeof(des_key)) { ret = EINVAL; /* XXX */ goto error; } RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error); if (ad->k_flags & 1) krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); else krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error); RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error); RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error); ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE, des_key, sizeof(des_key), &ad->session); if (ret) goto error; if (strlen(ad->prealm) == 0) { free(ad->prealm); ad->prealm = strdup(local_realm); if (ad->prealm == NULL) { ret = ENOMEM; goto error; } } error: memset(des_key, 0, sizeof(des_key)); if (sp) krb5_storage_free(sp); krb5_data_free(&ticket); if (ret) { if (*sname) { free(*sname); *sname = NULL; } if (*sinstance) { free(*sinstance); *sinstance = NULL; } _krb5_krb_free_auth_data(context, ad); krb5_set_error_string(context, "Failed to decode v4 ticket"); } return ret; }
krb5_error_code KRB5_LIB_FUNCTION _krb5_krb_rd_req(krb5_context context, krb5_data *authent, const char *service, const char *instance, const char *local_realm, int32_t from_addr, const krb5_keyblock *key, struct _krb5_krb_auth_data *ad) { krb5_error_code ret; krb5_storage *sp; krb5_data ticket, eaut, aut; krb5_ssize_t size; int little_endian; int8_t pvno; int8_t type; int8_t s_kvno; uint8_t ticket_length; uint8_t eaut_length; uint8_t time_5ms; char *realm = NULL; char *sname = NULL; char *sinstance = NULL; char *r_realm = NULL; char *r_name = NULL; char *r_instance = NULL; uint32_t r_time_sec; /* Coarse time from authenticator */ unsigned long delta_t; /* Time in authenticator - local time */ long tkt_age; /* Age of ticket */ struct timeval tv; krb5_data_zero(&ticket); krb5_data_zero(&eaut); krb5_data_zero(&aut); sp = krb5_storage_from_data(authent); if (sp == NULL) { krb5_set_error_string(context, "alloc: out of memory"); return ENOMEM; } krb5_storage_set_eof_code(sp, EINVAL); /* XXX */ ret = krb5_ret_int8(sp, &pvno); if (ret) goto error; if (pvno != KRB_PROT_VERSION) { ret = EINVAL; /* XXX */ goto error; } ret = krb5_ret_int8(sp, &type); if (ret) goto error; little_endian = type & 1; type &= ~1; if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) { ret = EINVAL; /* RD_AP_MSG_TYPE */ goto error; } RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error); RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error); RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error); RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error); RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error); size = krb5_storage_read(sp, ticket.data, ticket.length); if (size != ticket.length) { ret = EINVAL; goto error; } /* Decrypt and take apart ticket */ ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm, &sname, &sinstance, ad); if (ret) goto error; RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error); size = krb5_storage_read(sp, eaut.data, eaut.length); if (size != eaut.length) { ret = EINVAL; goto error; } krb5_storage_free(sp); sp = NULL; ret = decrypt_etext(context, &ad->session, &eaut, &aut); if (ret) goto error; sp = krb5_storage_from_data(&aut); if (sp == NULL) { krb5_set_error_string(context, "alloc: out of memory"); ret = ENOMEM; goto error; } if (little_endian) krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); else krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error); RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error); RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error); RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error); RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error); RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error); if (strcmp(ad->pname, r_name) != 0 || strcmp(ad->pinst, r_instance) != 0 || strcmp(ad->prealm, r_realm) != 0) { ret = EINVAL; /* RD_AP_INCON */ goto error; } if (from_addr && from_addr != ad->address) { ret = EINVAL; /* RD_AP_BADD */ goto error; } gettimeofday(&tv, NULL); delta_t = abs((int)(tv.tv_sec - r_time_sec)); if (delta_t > CLOCK_SKEW) { ret = EINVAL; /* RD_AP_TIME */ goto error; } /* Now check for expiration of ticket */ tkt_age = tv.tv_sec - ad->time_sec; if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) { ret = EINVAL; /* RD_AP_NYV */ goto error; } if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) { ret = EINVAL; /* RD_AP_EXP */ goto error; } ret = 0; error: krb5_data_free(&ticket); krb5_data_free(&eaut); krb5_data_free(&aut); if (realm) free(realm); if (sname) free(sname); if (sinstance) free(sinstance); if (r_name) free(r_name); if (r_instance) free(r_instance); if (r_realm) free(r_realm); if (sp) krb5_storage_free(sp); if (ret) krb5_clear_error_string(context); return ret; }
static krb5_error_code receive_everything(krb5_context context, int fd, kadm5_server_context *server_context, krb5_auth_context auth_context) { int ret; krb5_data data; uint32_t vno = 0; uint32_t opcode; krb5_storage *sp; char *dbname; HDB *mydb; krb5_warnx(context, "receive complete database"); ret = asprintf(&dbname, "%s-NEW", server_context->db->hdb_name); if (ret == -1) krb5_err(context, IPROPD_RESTART, ENOMEM, "asprintf"); ret = hdb_create(context, &mydb, dbname); if(ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_create"); free(dbname); ret = hdb_set_master_keyfile(context, mydb, server_context->config.stash_file); if(ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_set_master_keyfile"); /* I really want to use O_EXCL here, but given that I can't easily clean up on error, I won't */ ret = mydb->hdb_open(context, mydb, O_RDWR | O_CREAT | O_TRUNC, 0600); if (ret) krb5_err(context, IPROPD_RESTART, ret, "db->open"); (void) mydb->hdb_set_sync(context, mydb, 0); sp = NULL; krb5_data_zero(&data); do { ret = krb5_read_priv_message(context, auth_context, &fd, &data); if (ret) { krb5_warn(context, ret, "krb5_read_priv_message"); goto cleanup; } sp = krb5_storage_from_data(&data); if (sp == NULL) krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_data"); krb5_ret_uint32(sp, &opcode); if (opcode == ONE_PRINC) { krb5_data fake_data; hdb_entry_ex entry; krb5_storage_free(sp); fake_data.data = (char *)data.data + 4; fake_data.length = data.length - 4; memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry(context, &fake_data, &entry.entry); if (ret) krb5_err(context, IPROPD_RESTART, ret, "hdb_value2entry"); ret = mydb->hdb_store(server_context->context, mydb, 0, &entry); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "hdb_store"); hdb_free_entry(context, &entry); krb5_data_free(&data); } else if (opcode == NOW_YOU_HAVE) ; else krb5_errx(context, 1, "strange opcode %d", opcode); } while (opcode == ONE_PRINC); if (opcode != NOW_YOU_HAVE) krb5_errx(context, IPROPD_RESTART_SLOW, "receive_everything: strange %d", opcode); krb5_ret_uint32(sp, &vno); krb5_storage_free(sp); reinit_log(context, server_context, vno); ret = mydb->hdb_set_sync(context, mydb, 1); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "failed to sync the received HDB"); ret = mydb->hdb_close(context, mydb); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); ret = mydb->hdb_rename(context, mydb, server_context->db->hdb_name); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->rename"); return 0; cleanup: krb5_data_free(&data); if (ret) krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); ret = mydb->hdb_destroy(context, mydb); if (ret) krb5_err(context, IPROPD_RESTART, ret, "db->destroy"); krb5_warnx(context, "receive complete database, version %ld", (long)vno); return ret; }
krb5_error_code _kdc_do_kaserver(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, size_t len, krb5_data *reply, const char *from, struct sockaddr_in *addr) { krb5_error_code ret = 0; struct rx_header hdr; uint32_t op; krb5_storage *sp; if (len < RX_HEADER_SIZE) return -1; sp = krb5_storage_from_mem (buf, len); ret = decode_rx_header (sp, &hdr); if (ret) goto out; buf += RX_HEADER_SIZE; len -= RX_HEADER_SIZE; switch (hdr.type) { case HT_DATA : break; case HT_ACK : case HT_BUSY : case HT_ABORT : case HT_ACKALL : case HT_CHAL : case HT_RESP : case HT_DEBUG : default: /* drop */ goto out; } if (hdr.serviceid != KA_AUTHENTICATION_SERVICE && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) { ret = -1; goto out; } ret = krb5_ret_uint32(sp, &op); if (ret) goto out; switch (op) { case AUTHENTICATE : case AUTHENTICATE_V2 : do_authenticate (context, config, &hdr, sp, addr, from, reply); break; case GETTICKET : do_getticket (context, config, &hdr, sp, addr, from, reply); break; case AUTHENTICATE_OLD : case CHANGEPASSWORD : case GETTICKET_OLD : case SETPASSWORD : case SETFIELDS : case CREATEUSER : case DELETEUSER : case GETENTRY : case LISTENTRY : case GETSTATS : case DEBUG : case GETPASSWORD : case GETRANDOMKEY : default : make_error_reply (&hdr, RXGEN_OPCODE, reply); break; } out: krb5_storage_free (sp); return ret; }
OM_uint32 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, OM_uint32 version, void **rctx) { krb5_context context = NULL; krb5_error_code ret; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 major_status; gss_krb5_lucid_context_v1_t *ctx = NULL; krb5_storage *sp = NULL; uint32_t num; if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT || version != 1) { ret = EINVAL; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, *context_handle, GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } ret = krb5_init_context(&context); if (ret) goto out; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { ret = ENOMEM; goto out; } sp = krb5_storage_from_mem(data_set->elements[0].value, data_set->elements[0].length); if (sp == NULL) { ret = ENOMEM; goto out; } ret = krb5_ret_uint32(sp, &num); if (ret) goto out; if (num != 1) { ret = EINVAL; goto out; } ctx->version = 1; /* initiator */ ret = krb5_ret_uint32(sp, &ctx->initiate); if (ret) goto out; /* endtime */ ret = krb5_ret_uint32(sp, &ctx->endtime); if (ret) goto out; /* send_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq |= num; /* recv_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq |= num; /* protocol */ ret = krb5_ret_uint32(sp, &ctx->protocol); if (ret) goto out; if (ctx->protocol == 0) { krb5_keyblock key; /* sign_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); if (ret) goto out; /* seal_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } else if (ctx->protocol == 1) { krb5_keyblock key; /* acceptor_subkey */ ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; /* acceptor_subkey */ if (ctx->cfx_kd.have_acceptor_subkey) { ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } } else { ret = EINVAL; goto out; } *rctx = ctx; out: gss_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (context) krb5_free_context(context); if (ret) { if (ctx) gss_krb5_free_lucid_sec_context(NULL, ctx); *minor_status = ret; return GSS_S_FAILURE; } *minor_status = 0; return GSS_S_COMPLETE; }
static krb5_error_code verify_checksum(krb5_context context, const struct PAC_INFO_BUFFER *sig, const krb5_data *data, void *ptr, size_t len, const krb5_keyblock *key) { krb5_storage *sp = NULL; uint32_t type; krb5_error_code ret; Checksum cksum; memset(&cksum, 0, sizeof(cksum)); sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo, sig->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &type), out); cksum.cksumtype = type; cksum.checksum.length = sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR); cksum.checksum.data = malloc(cksum.checksum.length); if (cksum.checksum.data == NULL) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length); if (ret != cksum.checksum.length) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC checksum missing checksum"); goto out; } if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) { ret = EINVAL; krb5_set_error_message(context, ret, "Checksum type %d not keyed", cksum.cksumtype); goto out; } /* If the checksum is HMAC-MD5, the checksum type is not tied to * the key type, instead the HMAC-MD5 checksum is applied blindly * on whatever key is used for this connection, avoiding issues * with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See * http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743 * for the same issue in MIT, and * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx * for Microsoft's explaination */ if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) { Checksum local_checksum; memset(&local_checksum, 0, sizeof(local_checksum)); ret = HMAC_MD5_any_checksum(context, key, ptr, len, KRB5_KU_OTHER_CKSUM, &local_checksum); if (ret != 0 || krb5_data_ct_cmp(&local_checksum.checksum, &cksum.checksum) != 0) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; krb5_set_error_message(context, ret, N_("PAC integrity check failed for " "hmac-md5 checksum", "")); } krb5_data_free(&local_checksum.checksum); } else { krb5_crypto crypto = NULL; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) goto out; ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, ptr, len, &cksum); krb5_crypto_destroy(context, crypto); } free(cksum.checksum.data); krb5_storage_free(sp); return ret; out: if (cksum.checksum.data) free(cksum.checksum.data); if (sp) krb5_storage_free(sp); return ret; }
static int process_msg (kadm5_server_context *server_context, slave *s, int log_fd, const char *database, uint32_t current_version, uint32_t current_tstamp) { krb5_context context = server_context->context; int ret = 0; krb5_data out; krb5_storage *sp; uint32_t tmp; ret = krb5_read_priv_message(context, s->ac, &s->fd, &out); if(ret) { krb5_warn(context, ret, "error reading message from %s", s->name); return 1; } sp = krb5_storage_from_mem(out.data, out.length); if (sp == NULL) { krb5_warnx(context, "process_msg: no memory"); krb5_data_free(&out); return 1; } if (krb5_ret_uint32(sp, &tmp) != 0) { krb5_warnx(context, "process_msg: client send too short command"); krb5_data_free(&out); return 1; } switch (tmp) { case I_HAVE : ret = krb5_ret_uint32(sp, &tmp); if (ret != 0) { krb5_warnx(context, "process_msg: client send too little I_HAVE data"); break; } /* new started slave that have old log */ if (s->version == 0 && tmp != 0) { if (current_version < tmp) { krb5_warnx(context, "Slave %s (version %u) have later version " "the master (version %u) OUT OF SYNC", s->name, tmp, current_version); } if (verbose) krb5_warnx(context, "slave %s updated from %u to %u", s->name, s->version, tmp); s->version = tmp; } if (tmp < s->version) { krb5_warnx(context, "Slave %s claims to not have " "version we already sent to it", s->name); s->version = tmp; } ret = send_diffs(server_context, s, log_fd, database, current_version, current_tstamp); break; case I_AM_HERE : if (verbose) krb5_warnx(context, "slave %s is there", s->name); break; case ARE_YOU_THERE: case FOR_YOU : default : krb5_warnx(context, "Ignoring command %d", tmp); break; } krb5_data_free(&out); krb5_storage_free(sp); slave_seen(s); return ret; }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; krb5_principal p2; uint32_t time1, time2; krb5_storage *sp; uint16_t len; char *s; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; if (t1 != t2) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ s = malloc(u8len); if (s == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); free(ucs2); if (ret) { free(s); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } } ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); free(s); if (ret) return ret; if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name mismatch"); } krb5_free_principal(context, p2); return ret; out: return ret; }
/* * Request: * NameZ * WhichFields * MatchCreds * * Response: * Creds * */ static krb5_error_code kcm_op_retrieve(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *request, krb5_storage *response) { uint32_t flags; krb5_creds mcreds; krb5_error_code ret; kcm_ccache ccache; char *name; krb5_creds *credp; int free_creds = 0; ret = krb5_ret_stringz(request, &name); if (ret) return ret; KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = krb5_ret_uint32(request, &flags); if (ret) { free(name); return ret; } ret = krb5_ret_creds_tag(request, &mcreds); if (ret) { free(name); return ret; } if (disallow_getting_krbtgt && mcreds.server->name.name_string.len == 2 && strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0) { free(name); krb5_free_cred_contents(context, &mcreds); return KRB5_FCC_PERM; } ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); if (ret) { free(name); krb5_free_cred_contents(context, &mcreds); return ret; } ret = kcm_ccache_retrieve_cred(context, ccache, flags, &mcreds, &credp); if (ret && ((flags & KRB5_GC_CACHED) == 0) && !krb5_is_config_principal(context, mcreds.server)) { krb5_ccache_data ccdata; /* try and acquire */ HEIMDAL_MUTEX_lock(&ccache->mutex); /* Fake up an internal ccache */ kcm_internal_ccache(context, ccache, &ccdata); /* glue cc layer will store creds */ ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp); if (ret == 0) free_creds = 1; HEIMDAL_MUTEX_unlock(&ccache->mutex); } if (ret == 0) { ret = krb5_store_creds(response, credp); } free(name); krb5_free_cred_contents(context, &mcreds); kcm_release_ccache(context, ccache); if (free_creds) krb5_free_cred_contents(context, credp); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_kdc_configuration *config; krb5_storage *sp; int fd, optidx = 0; setprogname(argv[0]); if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); if(version_flag){ print_version(NULL); exit(0); } ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed to parse configuration file"); ret = krb5_kdc_get_config(context, &config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_default_config"); kdc_openlog(context, "kdc-replay", config); ret = krb5_kdc_set_dbinfo(context, config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); #ifdef PKINIT if (config->enable_pkinit) { if (config->pkinit_kdc_identity == NULL) krb5_errx(context, 1, "pkinit enabled but no identity"); if (config->pkinit_kdc_anchors == NULL) krb5_errx(context, 1, "pkinit enabled but no X509 anchors"); krb5_kdc_pk_initialize(context, config, config->pkinit_kdc_identity, config->pkinit_kdc_anchors, config->pkinit_kdc_cert_pool, config->pkinit_kdc_revoke); } #endif /* PKINIT */ if (argc != 2) errx(1, "argc != 2"); printf("kdc replay\n"); fd = open(argv[1], O_RDONLY); if (fd < 0) err(1, "open: %s", argv[1]); sp = krb5_storage_from_fd(fd); if (sp == NULL) krb5_errx(context, 1, "krb5_storage_from_fd"); while(1) { struct sockaddr_storage sa; krb5_socklen_t salen = sizeof(sa); struct timeval tv; krb5_address a; krb5_data d, r; uint32_t t, clty, tag; char astr[80]; ret = krb5_ret_uint32(sp, &t); if (ret == HEIM_ERR_EOF) break; else if (ret) krb5_errx(context, 1, "krb5_ret_uint32(version)"); if (t != 1) krb5_errx(context, 1, "version not 1"); ret = krb5_ret_uint32(sp, &t); if (ret) krb5_errx(context, 1, "krb5_ret_uint32(time)"); ret = krb5_ret_address(sp, &a); if (ret) krb5_errx(context, 1, "krb5_ret_address"); ret = krb5_ret_data(sp, &d); if (ret) krb5_errx(context, 1, "krb5_ret_data"); ret = krb5_ret_uint32(sp, &clty); if (ret) krb5_errx(context, 1, "krb5_ret_uint32(class|type)"); ret = krb5_ret_uint32(sp, &tag); if (ret) krb5_errx(context, 1, "krb5_ret_uint32(tag)"); ret = krb5_addr2sockaddr (context, &a, (struct sockaddr *)&sa, &salen, 88); if (ret == KRB5_PROG_ATYPE_NOSUPP) goto out; else if (ret) krb5_err(context, 1, ret, "krb5_addr2sockaddr"); ret = krb5_print_address(&a, astr, sizeof(astr), NULL); if (ret) krb5_err(context, 1, ret, "krb5_print_address"); printf("processing request from %s, %lu bytes\n", astr, (unsigned long)d.length); r.length = 0; r.data = NULL; tv.tv_sec = t; tv.tv_usec = 0; krb5_kdc_update_time(&tv); krb5_set_real_time(context, tv.tv_sec, 0); ret = krb5_kdc_process_request(context, config, d.data, d.length, &r, NULL, astr, (struct sockaddr *)&sa, 0); if (ret) krb5_err(context, 1, ret, "krb5_kdc_process_request"); if (r.length) { Der_class cl; Der_type ty; unsigned int tag2; ret = der_get_tag (r.data, r.length, &cl, &ty, &tag2, NULL); if (MAKE_TAG(cl, ty, 0) != clty) krb5_errx(context, 1, "class|type mismatch: %d != %d", (int)MAKE_TAG(cl, ty, 0), (int)clty); if (tag != tag2) krb5_errx(context, 1, "tag mismatch"); krb5_data_free(&r); } else { if (clty != 0xffffffff) krb5_errx(context, 1, "clty not invalid"); if (tag != 0xffffffff) krb5_errx(context, 1, "tag not invalid"); } out: krb5_data_free(&d); krb5_free_address(context, &a); } krb5_storage_free(sp); krb5_free_context(context); printf("done\n"); return 0; }
krb5_error_code _kadm5_xdr_ret_principal_ent(krb5_context context, krb5_storage *sp, kadm5_principal_ent_rec *ent) { uint32_t flag, num, dataver; size_t i; memset(ent, 0, sizeof(*ent)); CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->principal)); CHECK(krb5_ret_uint32(sp, &flag)); ent->princ_expire_time = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->pw_expiration = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->last_pwd_change = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->max_life = flag; if (ent->max_life >= LARGETIME) ent->max_life = 0; CHECK(krb5_ret_uint32(sp, &flag)); if (flag == 0) { CHECK(_kadm5_xdr_ret_principal_xdr(context, sp, &ent->mod_name)); } CHECK(krb5_ret_uint32(sp, &flag)); ent->mod_date = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->attributes = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->kvno = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->mkvno = flag; CHECK(_kadm5_xdr_ret_string_xdr(sp, &ent->policy)); CHECK(krb5_ret_uint32(sp, &flag)); ent->aux_attributes = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->max_renewable_life = flag; if (ent->max_renewable_life >= LARGETIME) ent->max_renewable_life = 0; CHECK(krb5_ret_uint32(sp, &flag)); ent->last_success = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->last_failed = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->fail_auth_count = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->n_key_data = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->n_tl_data = flag; CHECK(krb5_ret_uint32(sp, &flag)); if (flag == 0) { krb5_tl_data **tp = &ent->tl_data; size_t count = 0; while(1) { krb5_data c; CHECK(krb5_ret_uint32(sp, &flag)); /* last item */ if (flag) break; *tp = calloc(1, sizeof(**tp)); INSIST(*tp != NULL); CHECK(krb5_ret_uint32(sp, &flag)); (*tp)->tl_data_type = flag; CHECK(_kadm5_xdr_ret_data_xdr(sp, &c)); (*tp)->tl_data_length = c.length; (*tp)->tl_data_contents = c.data; tp = &(*tp)->tl_data_next; count++; INSIST(count < 2000); } INSIST((size_t)ent->n_tl_data == count); } else { INSIST(ent->n_tl_data == 0); } CHECK(krb5_ret_uint32(sp, &num)); INSIST(num == (uint32_t)ent->n_key_data); ent->key_data = calloc(num, sizeof(ent->key_data[0])); INSIST(ent->key_data != NULL); for (i = 0; i < num; i++) { CHECK(krb5_ret_uint32(sp, &dataver)); CHECK(krb5_ret_uint32(sp, &flag)); ent->kvno = flag; CHECK(krb5_ret_uint32(sp, &flag)); ent->key_data[i].key_data_type[0] = flag; if (dataver > 1) { CHECK(krb5_ret_uint32(sp, &flag)); ent->key_data[i].key_data_type[1] = flag; } } return 0; }