krb5_error_code KRB5_LIB_FUNCTION krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int fd, int flags) { krb5_error_code ret; krb5_address local_k_address, remote_k_address; krb5_address *lptr = NULL, *rptr = NULL; struct sockaddr_storage ss_local, ss_remote; struct sockaddr *local = (struct sockaddr *)&ss_local; struct sockaddr *remote = (struct sockaddr *)&ss_remote; socklen_t len; if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR) { if (auth_context->local_address == NULL) { len = sizeof(ss_local); if(getsockname(fd, local, &len) < 0) { ret = errno; krb5_set_error_message(context, ret, "getsockname: %s", strerror(ret)); goto out; } ret = krb5_sockaddr2address (context, local, &local_k_address); if(ret) goto out; if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) { krb5_sockaddr2port (context, local, &auth_context->local_port); } else auth_context->local_port = 0; lptr = &local_k_address; } } if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR) { len = sizeof(ss_remote); if(getpeername(fd, remote, &len) < 0) { ret = errno; krb5_set_error_message(context, ret, "getpeername: %s", strerror(ret)); goto out; } ret = krb5_sockaddr2address (context, remote, &remote_k_address); if(ret) goto out; if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) { krb5_sockaddr2port (context, remote, &auth_context->remote_port); } else auth_context->remote_port = 0; rptr = &remote_k_address; } ret = krb5_auth_con_setaddrs (context, auth_context, lptr, rptr); out: if (lptr) krb5_free_address (context, lptr); if (rptr) krb5_free_address (context, rptr); return ret; }
static OM_uint32 set_addresses (krb5_auth_context ac, const gss_channel_bindings_t input_chan_bindings) { /* Port numbers are expected to be in application_data.value, * initator's port first */ krb5_address initiator_addr, acceptor_addr; krb5_error_code kret; if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS || input_chan_bindings->application_data.length != 2 * sizeof(ac->local_port)) return 0; memset(&initiator_addr, 0, sizeof(initiator_addr)); memset(&acceptor_addr, 0, sizeof(acceptor_addr)); ac->local_port = *(int16_t *) input_chan_bindings->application_data.value; ac->remote_port = *((int16_t *) input_chan_bindings->application_data.value + 1); kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->acceptor_addrtype, &input_chan_bindings->acceptor_address, ac->remote_port, &acceptor_addr); if (kret) return kret; kret = _gsskrb5i_address_to_krb5addr(input_chan_bindings->initiator_addrtype, &input_chan_bindings->initiator_address, ac->local_port, &initiator_addr); if (kret) { krb5_free_address (_gsskrb5_context, &acceptor_addr); return kret; } kret = krb5_auth_con_setaddrs(_gsskrb5_context, ac, &initiator_addr, /* local address */ &acceptor_addr); /* remote address */ krb5_free_address (_gsskrb5_context, &initiator_addr); krb5_free_address (_gsskrb5_context, &acceptor_addr); #if 0 free(input_chan_bindings->application_data.value); input_chan_bindings->application_data.value = NULL; input_chan_bindings->application_data.length = 0; #endif return kret; }
static void kerberos_authenticate(krb5_context context, krb5_auth_context *auth_context, int fd, krb5_principal me, krb5_creds **new_creds) { krb5_error_code retval; krb5_error *error = NULL; krb5_ap_rep_enc_part *rep_result; retval = krb5_auth_con_init(context, auth_context); if (retval) exit(1); krb5_auth_con_setflags(context, *auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); retval = krb5_auth_con_setaddrs(context, *auth_context, sender_addr, receiver_addr); if (retval) { com_err(progname, retval, _("in krb5_auth_con_setaddrs")); exit(1); } retval = krb5_sendauth(context, auth_context, &fd, kprop_version, me, creds.server, AP_OPTS_MUTUAL_REQUIRED, NULL, &creds, NULL, &error, &rep_result, new_creds); if (retval) { com_err(progname, retval, _("while authenticating to server")); if (error != NULL) { if (error->error == KRB_ERR_GENERIC) { if (error->text.data) { fprintf(stderr, _("Generic remote error: %s\n"), error->text.data); } } else if (error->error) { com_err(progname, (krb5_error_code)error->error + ERROR_TABLE_BASE_krb5, _("signalled from server")); if (error->text.data) { fprintf(stderr, _("Error text from server: %s\n"), error->text.data); } } krb5_free_error(context, error); } exit(1); } krb5_free_ap_rep_enc_part(context, rep_result); }
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 ADS_STATUS do_krb5_kpasswd_request(krb5_context context, const char *kdc_host, uint16 pversion, krb5_creds *credsp, const char *princ, const char *newpw) { krb5_auth_context auth_context = NULL; krb5_data ap_req, chpw_req, chpw_rep; int ret, sock; socklen_t addr_len; struct sockaddr_storage remote_addr, local_addr; struct sockaddr_storage addr; krb5_address local_kaddr, remote_kaddr; bool use_tcp = False; if (!interpret_string_addr(&addr, kdc_host, 0)) { } ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, NULL, credsp, &ap_req); if (ret) { DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } do { if (!use_tcp) { sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT); if (sock == -1) { int rc = errno; SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("failed to open kpasswd socket to %s " "(%s)\n", kdc_host, strerror(errno))); return ADS_ERROR_SYSTEM(rc); } } else { NTSTATUS status; status = open_socket_out(&addr, DEFAULT_KPASSWD_PORT, LONG_CONNECT_TIMEOUT, &sock); if (!NT_STATUS_IS_OK(status)) { SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("failed to open kpasswd socket to %s " "(%s)\n", kdc_host, nt_errstr(status))); return ADS_ERROR_NT(status); } } addr_len = sizeof(remote_addr); if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) { close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("getpeername() failed (%s)\n", error_message(errno))); return ADS_ERROR_SYSTEM(errno); } addr_len = sizeof(local_addr); if (getsockname(sock, (struct sockaddr *)&local_addr, &addr_len) != 0) { close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("getsockname() failed (%s)\n", error_message(errno))); return ADS_ERROR_SYSTEM(errno); } if (!setup_kaddr(&remote_kaddr, &remote_addr) || !setup_kaddr(&local_kaddr, &local_addr)) { DEBUG(1,("do_krb5_kpasswd_request: " "Failed to setup addresses.\n")); close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); errno = EINVAL; return ADS_ERROR_SYSTEM(EINVAL); } ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL); if (ret) { close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } ret = build_kpasswd_request(pversion, context, auth_context, &ap_req, princ, newpw, use_tcp, &chpw_req); if (ret) { close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } ret = write(sock, chpw_req.data, chpw_req.length); if (ret != chpw_req.length) { close(sock); SAFE_FREE(chpw_req.data); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("send of chpw failed (%s)\n", strerror(errno))); return ADS_ERROR_SYSTEM(errno); } SAFE_FREE(chpw_req.data); chpw_rep.length = 1500; chpw_rep.data = (char *) SMB_MALLOC(chpw_rep.length); if (!chpw_rep.data) { close(sock); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("send of chpw failed (%s)\n", strerror(errno))); errno = ENOMEM; return ADS_ERROR_SYSTEM(errno); } ret = read(sock, chpw_rep.data, chpw_rep.length); if (ret < 0) { close(sock); SAFE_FREE(chpw_rep.data); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno))); return ADS_ERROR_SYSTEM(errno); } close(sock); chpw_rep.length = ret; ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr); if (ret) { SAFE_FREE(chpw_rep.data); SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } ret = parse_setpw_reply(context, use_tcp, auth_context, &chpw_rep); SAFE_FREE(chpw_rep.data); if (ret) { if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { DEBUG(5, ("Trying setpw with TCP!!!\n")); use_tcp = True; continue; } SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); DEBUG(1,("parse_setpw_reply failed (%s)\n", error_message(ret))); return ADS_ERROR_KRB5(ret); } SAFE_FREE(ap_req.data); krb5_auth_con_free(context, auth_context); } while ( ret ); return ADS_SUCCESS; }
static int proto (int sock, const char *service) { struct sockaddr_in remote, local; socklen_t addrlen; krb5_address remote_addr, local_addr; krb5_ccache ccache; krb5_auth_context auth_context; krb5_error_code status; krb5_data packet; krb5_data data; krb5_data client_name; krb5_creds in_creds, *out_creds; addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 || addrlen != sizeof(local)) err (1, "getsockname)"); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 || addrlen != sizeof(remote)) err (1, "getpeername"); status = krb5_auth_con_init (context, &auth_context); if (status) errx (1, "krb5_auth_con_init: %s", krb5_get_err_text(context, status)); local_addr.addr_type = AF_INET; local_addr.address.length = sizeof(local.sin_addr); local_addr.address.data = &local.sin_addr; remote_addr.addr_type = AF_INET; remote_addr.address.length = sizeof(remote.sin_addr); remote_addr.address.data = &remote.sin_addr; status = krb5_auth_con_setaddrs (context, auth_context, &local_addr, &remote_addr); if (status) errx (1, "krb5_auth_con_setaddr: %s", krb5_get_err_text(context, status)); status = krb5_read_message(context, &sock, &client_name); if(status) krb5_err(context, 1, status, "krb5_read_message"); memset(&in_creds, 0, sizeof(in_creds)); status = krb5_cc_default(context, &ccache); if(status) krb5_err(context, 1, status, "krb5_cc_default"); status = krb5_cc_get_principal(context, ccache, &in_creds.client); if(status) krb5_err(context, 1, status, "krb5_cc_get_principal"); status = krb5_read_message(context, &sock, &in_creds.second_ticket); if(status) krb5_err(context, 1, status, "krb5_read_message"); status = krb5_parse_name(context, client_name.data, &in_creds.server); if(status) krb5_err(context, 1, status, "krb5_parse_name"); status = krb5_get_credentials(context, KRB5_GC_USER_USER, ccache, &in_creds, &out_creds); if(status) krb5_err(context, 1, status, "krb5_get_credentials"); status = krb5_cc_default(context, &ccache); if(status) krb5_err(context, 1, status, "krb5_cc_default"); status = krb5_sendauth(context, &auth_context, &sock, VERSION, in_creds.client, in_creds.server, AP_OPTS_USE_SESSION_KEY, NULL, out_creds, ccache, NULL, NULL, NULL); if (status) krb5_err(context, 1, status, "krb5_sendauth"); { char *str; krb5_unparse_name(context, in_creds.server, &str); printf ("User is `%s'\n", str); free(str); krb5_unparse_name(context, in_creds.client, &str); printf ("Server is `%s'\n", str); free(str); } krb5_data_zero (&data); krb5_data_zero (&packet); status = krb5_read_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_read_message"); status = krb5_rd_safe (context, auth_context, &packet, &data, NULL); if (status) errx (1, "krb5_rd_safe: %s", krb5_get_err_text(context, status)); printf ("safe packet: %.*s\n", (int)data.length, (char *)data.data); status = krb5_read_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_read_message"); status = krb5_rd_priv (context, auth_context, &packet, &data, NULL); if (status) errx (1, "krb5_rd_priv: %s", krb5_get_err_text(context, status)); printf ("priv packet: %.*s\n", (int)data.length, (char *)data.data); return 0; }
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi) { krb5_error_code ret; struct gensec_krb5_state *gensec_krb5_state; struct cli_credentials *creds; const struct tsocket_address *tlocal_addr, *tremote_addr; krb5_address my_krb5_addr, peer_krb5_addr; creds = gensec_get_credentials(gensec_security); if (!creds) { return NT_STATUS_INVALID_PARAMETER; } gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state); if (!gensec_krb5_state) { return NT_STATUS_NO_MEMORY; } gensec_security->private_data = gensec_krb5_state; gensec_krb5_state->smb_krb5_context = NULL; gensec_krb5_state->auth_context = NULL; gensec_krb5_state->ticket = NULL; ZERO_STRUCT(gensec_krb5_state->enc_ticket); gensec_krb5_state->keyblock = NULL; gensec_krb5_state->gssapi = gssapi; talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); if (cli_credentials_get_krb5_context(creds, gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) { talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } tlocal_addr = gensec_get_local_address(gensec_security); if (tlocal_addr) { ssize_t socklen; struct sockaddr_storage ss; socklen = tsocket_address_bsd_sockaddr(tlocal_addr, (struct sockaddr *) &ss, sizeof(struct sockaddr_storage)); if (socklen < 0) { talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, (const struct sockaddr *) &ss, &my_krb5_addr); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } } tremote_addr = gensec_get_remote_address(gensec_security); if (tremote_addr) { ssize_t socklen; struct sockaddr_storage ss; socklen = tsocket_address_bsd_sockaddr(tremote_addr, (struct sockaddr *) &ss, sizeof(struct sockaddr_storage)); if (socklen < 0) { talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, (const struct sockaddr *) &ss, &peer_krb5_addr); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } } ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, tlocal_addr ? &my_krb5_addr : NULL, tremote_addr ? &peer_krb5_addr : NULL); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } return NT_STATUS_OK; }
krb5_error_code KRB5_CALLCONV krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int infd, int flags) { krb5_error_code retval; krb5_address * laddr; krb5_address * lport; krb5_address * raddr; krb5_address * rport; SOCKET fd = (SOCKET) infd; struct addrpair laddrs, raddrs; #ifdef HAVE_NETINET_IN_H struct sockaddr_storage lsaddr, rsaddr; GETSOCKNAME_ARG3_TYPE ssize; ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR)) { retval = getsockname(fd, ss2sa(&lsaddr), &ssize); if (retval) return retval; if (cvtaddr (&lsaddr, &laddrs)) { laddr = &laddrs.addr; if (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) lport = &laddrs.port; else lport = 0; } else return KRB5_PROG_ATYPE_NOSUPP; } else { laddr = NULL; lport = NULL; } ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR)) { retval = getpeername(fd, ss2sa(&rsaddr), &ssize); if (retval) return errno; if (cvtaddr (&rsaddr, &raddrs)) { raddr = &raddrs.addr; if (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) rport = &raddrs.port; else rport = 0; } else return KRB5_PROG_ATYPE_NOSUPP; } else { raddr = NULL; rport = NULL; } if (!(retval = krb5_auth_con_setaddrs(context, auth_context, laddr, raddr))) return (krb5_auth_con_setports(context, auth_context, lport, rport)); return retval; #else return KRB5_PROG_ATYPE_NOSUPP; #endif }
int do_krb5_comm(krb5_context context, krb5_keytab keytab, krb5_principal server, char *cmddir) { struct sockaddr_in c_saddr, s_saddr; socklen_t namelen; int sock = 0; int len; char buff[BUFFSIZE]; char *cname = NULL; krb5_error_code retval; krb5_data kdata, message; krb5_auth_context auth_context = NULL; krb5_ticket *ticket; krb5_address ckaddr, skaddr; krb5_rcache rcache; krb5_data rcache_name; long srand, rrand; int fd[2]; char rcname_piece[RC_PIECE_MAXLEN]; namelen = sizeof(c_saddr); if (getpeername(sock, (struct sockaddr *)&c_saddr, &namelen) < 0) { syslog(LOG_ERR, "getpeername: %m"); return 1; } namelen = sizeof(s_saddr); if (getsockname(sock, (struct sockaddr *)&s_saddr, &namelen) < 0) { syslog(LOG_ERR, "getsockname: %m"); return 1; } /* INIT MSG = random number */ srand = random(); /* Send it */ if (send(sock, &srand, sizeof(srand), 0) < 0) { syslog(LOG_ERR, "%m while sending init message"); return 1; } if (recv(sock, &rrand, sizeof(rrand), 0) < 0) { syslog(LOG_ERR, "%m while receiving init reply"); return 1; } /* Reply should contain the same message (number) */ if (srand != rrand) { syslog(LOG_ERR, "Bad init reply"); return 1; } /* Do authentication */ if (retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock, AFSADM_VERSION, server, 0, keytab, &ticket)) { syslog(LOG_ERR, "recvauth failed: %s", error_message(retval)); exit(1); } /* Get client name */ if (retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname)) { syslog(LOG_ERR, "unparse failed: %s", error_message(retval)); return 1; } if (ticket) krb5_free_ticket(context, ticket); if (debug) syslog(LOG_DEBUG, "Principal %s", cname); /*******************************************************************/ ckaddr.addrtype = ADDRTYPE_IPPORT; ckaddr.length = sizeof(c_saddr.sin_port); ckaddr.contents = (krb5_octet *)&c_saddr.sin_port; skaddr.addrtype = ADDRTYPE_IPPORT; skaddr.length = sizeof(s_saddr.sin_port); skaddr.contents = (krb5_octet *)&s_saddr.sin_port; if ((retval = krb5_auth_con_setports(context, auth_context, &skaddr, &ckaddr))) { syslog(LOG_ERR, "%s while setting ports", error_message(retval)); return 1; } /* Set foreign_addr for rd_priv() */ ckaddr.addrtype = ADDRTYPE_INET; ckaddr.length = sizeof(c_saddr.sin_addr); ckaddr.contents = (krb5_octet *)&c_saddr.sin_addr; /* Set local_addr */ skaddr.addrtype = ADDRTYPE_INET; skaddr.length = sizeof(s_saddr.sin_addr); skaddr.contents = (krb5_octet *)&s_saddr.sin_addr; if ((retval = krb5_auth_con_setaddrs(context, auth_context, &skaddr, &ckaddr))) { syslog(LOG_ERR, "%s while setting addrs", error_message(retval)); return 1; } /* Receive a request */ if ((len = recv(sock, (char *)buff, sizeof(buff), 0)) < 0) { syslog(LOG_ERR, "%m while receiving datagram"); return 1; } kdata.length = len; kdata.data = buff; if (debug) syslog(LOG_DEBUG, "Received %d bytes", len); /* Decrypt it */ if ((retval = krb5_rd_priv(context, auth_context, &kdata, &message, NULL))) { syslog(LOG_ERR, "%s while verifying PRIV message", error_message(retval)); return 1; } if (message.length > 0) { #ifdef __osf__ sprintf(rcname_piece, "afsadmd_%d", getpid()); #else snprintf(rcname_piece, RC_PIECE_MAXLEN, "afsadmd_%d", getpid()); #endif rcache_name.data = rcname_piece; rcache_name.length = strlen(rcache_name.data); if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) { syslog(LOG_ERR, "%s while getting server rcache", error_message(retval)); return 1; } /* set auth_context rcache */ if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { syslog(LOG_ERR, "%s while setting rcache", error_message(retval)); return 1; } /********************************************************************* * Call the desired command, read stdout/stderr, send it *********************************************************************/ /* create fork */ if (pipe(fd) == -1) printf("Failed create fork with pipe().\n"); if (fork() == 0) { close(fd[0]); close(1); close(2); dup2(fd[1], 1); dup2(fd[1], 2); /* Call required command */ do_command(context, keytab, server, cname, message.data, cmddir ); krb5_xfree(message.data); exit(0); } else { /* Read stdout/stderr from pipe, store it to the buffer, encrypt it a send to the client */ krb5_data message, kdata; char buff[PIPEBUFF]; int n = 0; int len = 0; int sent = 0; int counter = 0; int end = 0; short netlen; time_t starttime, oldtime, newtime; FILE *pipedes; close(fd[1]); pipedes = fdopen(fd[0], "r"); starttime = oldtime = time(NULL); for (n = 0; end == 0; ) { /* Read line from pipe */ if (fgets(buff + n, PIPEBUFF - n, pipedes) == NULL) end++; else n = strlen(buff); /* Get time */ newtime = time(NULL); /* Send buffer when * a) buffer is full * b) buffer contains data and * 1) end-of-file encountered (end flag) * 2) buffer sent before 1s */ if ((n == PIPEBUFF) || (((newtime > oldtime) || end ) && (n != 0))) { /* Prepare data for sending */ message.data = buff; message.length = n; kdata.data = NULL; /* Make the encrypted message */ if ((retval = krb5_mk_priv(context, auth_context, &message, &kdata, NULL))) { syslog(LOG_ERR, "%s while making KRB_PRIV message", error_message(retval)); return 1; } /* Convert byte order */ netlen = htons((short)kdata.length); /* Send len of encrypted data */ if ((len = send(sock, (char *)&netlen, sizeof(netlen), 0)) != sizeof(netlen)) { krb5_xfree(kdata.data); syslog(LOG_ERR, "%m while sending len of PRIV message"); return 1; } /* Send it */ if ((len = send(sock, (char *)kdata.data, kdata.length, 0)) != kdata.length) { syslog(LOG_ERR, "%m while sending PRIV message"); krb5_xfree(kdata.data); return 1; } /* Statistics */ sent += len; counter++; /* Timestanmp */ oldtime = newtime; n = 0; krb5_xfree(kdata.data); } } newtime = time(NULL); if (debug) syslog(LOG_DEBUG, "Sent %d bytes in %ds [%d fragment(s)]", sent, (int)(newtime - starttime), counter); } } //FIXME: There is no way to close or destroy rcache declared in krb5 headers //krb5_rc_destroy(context, rcache); /* set auth_context rcache */ if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { syslog(LOG_ERR, "%s while setting rcache to NULL", error_message(retval)); return 1; } free(cname); krb5_auth_con_free(context, auth_context); return 0; }
/* ** The logic for setting and changing a password is mostly the same ** change_set_password handles both cases ** if set_password_for is NULL, then a password change is performed, ** otherwise, the password is set for the principal indicated in set_password_for */ static krb5_error_code change_set_password(krb5_context context, krb5_creds *creds, char *newpw, krb5_principal set_password_for, int *result_code, krb5_data *result_code_string, krb5_data *result_string) { krb5_data chpw_rep; krb5_address remote_kaddr; krb5_boolean use_tcp = 0; GETSOCKNAME_ARG3_TYPE addrlen; krb5_error_code code = 0; char *code_string; int local_result_code; struct sendto_callback_context callback_ctx; struct sendto_callback_info callback_info; struct sockaddr_storage remote_addr; struct serverlist sl = SERVERLIST_INIT; memset(&chpw_rep, 0, sizeof(krb5_data)); memset( &callback_ctx, 0, sizeof(struct sendto_callback_context)); callback_ctx.context = context; callback_ctx.newpw = newpw; callback_ctx.set_password_for = set_password_for; if ((code = krb5_auth_con_init(callback_ctx.context, &callback_ctx.auth_context))) goto cleanup; if ((code = krb5_mk_req_extended(callback_ctx.context, &callback_ctx.auth_context, AP_OPTS_USE_SUBKEY, NULL, creds, &callback_ctx.ap_req))) goto cleanup; callback_ctx.remote_seq_num = callback_ctx.auth_context->remote_seq_number; callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number; do { int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM); code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl, socktype); if (code) break; addrlen = sizeof(remote_addr); callback_info.data = &callback_ctx; callback_info.pfn_callback = kpasswd_sendto_msg_callback; callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup; krb5_free_data_contents(callback_ctx.context, &chpw_rep); code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0, &callback_info, &chpw_rep, ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL); if (code) { /* * Here we may want to switch to TCP on some errors. * right? */ break; } if (remote_addr.ss_family == AF_INET) { remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr); remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr; } else if (remote_addr.ss_family == AF_INET6) { remote_kaddr.addrtype = ADDRTYPE_INET6; remote_kaddr.length = sizeof(ss2sin6(&remote_addr)->sin6_addr); remote_kaddr.contents = (krb5_octet *) &ss2sin6(&remote_addr)->sin6_addr; } else { break; } if ((code = krb5_auth_con_setaddrs(callback_ctx.context, callback_ctx.auth_context, NULL, &remote_kaddr))) break; code = krb5int_rd_chpw_rep(callback_ctx.context, callback_ctx.auth_context, &chpw_rep, &local_result_code, result_string); if (code) { if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { k5_free_serverlist(&sl); use_tcp = 1; continue; } break; } if (result_code) *result_code = local_result_code; if (result_code_string) { code = krb5_chpw_result_code_string(callback_ctx.context, local_result_code, &code_string); if (code) goto cleanup; result_code_string->length = strlen(code_string); result_code_string->data = malloc(result_code_string->length); if (result_code_string->data == NULL) { code = ENOMEM; goto cleanup; } strncpy(result_code_string->data, code_string, result_code_string->length); } if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { k5_free_serverlist(&sl); use_tcp = 1; } else { break; } } while (TRUE); cleanup: if (callback_ctx.auth_context != NULL) krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context); k5_free_serverlist(&sl); krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req); krb5_free_data_contents(callback_ctx.context, &chpw_rep); return(code); }
static int kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message) { krb5_error_code code = 0; struct sockaddr_storage local_addr; krb5_address local_kaddr; struct sendto_callback_context *ctx = data; GETSOCKNAME_ARG3_TYPE addrlen; krb5_data output; memset (message, 0, sizeof(krb5_data)); /* * We need the local addr from the connection socket */ addrlen = sizeof(local_addr); if (getsockname(fd, ss2sa(&local_addr), &addrlen) < 0) { code = SOCKET_ERRNO; goto cleanup; } /* some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (local_addr.ss_family == AF_INET && ss2sin(&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr); local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr; } else if (local_addr.ss_family == AF_INET6 && memcmp(ss2sin6(&local_addr)->sin6_addr.s6_addr, in6addr_any.s6_addr, sizeof(in6addr_any.s6_addr)) != 0) { local_kaddr.addrtype = ADDRTYPE_INET6; local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr); local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr; } else { krb5_address **addrs; code = krb5_os_localaddr(ctx->context, &addrs); if (code) goto cleanup; local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length, &code); krb5_free_addresses(ctx->context, addrs); if (local_kaddr.contents == NULL) goto cleanup; } /* * TBD: Does this tamper w/ the auth context in such a way * to break us? Yes - provide 1 per conn-state / host... */ if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context, &local_kaddr, NULL))) goto cleanup; ctx->auth_context->remote_seq_number = ctx->remote_seq_num; ctx->auth_context->local_seq_number = ctx->local_seq_num; if (ctx->set_password_for) code = krb5int_mk_setpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->set_password_for, ctx->newpw, &output); else code = krb5int_mk_chpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->newpw, &output); if (code) goto cleanup; message->length = output.length; message->data = output.data; cleanup: return code; }
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi) { krb5_error_code ret; struct gensec_krb5_state *gensec_krb5_state; struct cli_credentials *creds; const struct socket_address *my_addr, *peer_addr; krb5_address my_krb5_addr, peer_krb5_addr; creds = gensec_get_credentials(gensec_security); if (!creds) { return NT_STATUS_INVALID_PARAMETER; } gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state); if (!gensec_krb5_state) { return NT_STATUS_NO_MEMORY; } gensec_security->private_data = gensec_krb5_state; gensec_krb5_state->smb_krb5_context = NULL; gensec_krb5_state->auth_context = NULL; gensec_krb5_state->ticket = NULL; ZERO_STRUCT(gensec_krb5_state->enc_ticket); gensec_krb5_state->keyblock = NULL; gensec_krb5_state->session_key = data_blob(NULL, 0); gensec_krb5_state->pac = data_blob(NULL, 0); gensec_krb5_state->gssapi = gssapi; talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); if (cli_credentials_get_krb5_context(creds, gensec_security->event_ctx, gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) { talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } my_addr = gensec_get_my_addr(gensec_security); if (my_addr && my_addr->sockaddr) { ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, my_addr->sockaddr, &my_krb5_addr); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } } peer_addr = gensec_get_peer_addr(gensec_security); if (peer_addr && peer_addr->sockaddr) { ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, peer_addr->sockaddr, &peer_krb5_addr); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } } ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, my_addr ? &my_krb5_addr : NULL, peer_addr ? &peer_krb5_addr : NULL); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } return NT_STATUS_OK; }
/* * Serialize krb5_auth_context. */ static krb5_error_code ser_acontext_test(krb5_context kcontext, int verbose) { krb5_error_code kret; krb5_auth_context actx; krb5_address local_address; krb5_address remote_address; krb5_octet laddr_bytes[16]; krb5_octet raddr_bytes[16]; krb5_keyblock ukeyblock; krb5_octet keydata[8]; krb5_authenticator aent; char clname[128]; krb5_authdata *adatalist[3]; krb5_authdata adataent; actx = (krb5_auth_context) NULL; if (!(kret = krb5_auth_con_init(kcontext, &actx)) && !(kret = ser_data(verbose, "> Vanilla auth context", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { memset(&local_address, 0, sizeof(local_address)); memset(&remote_address, 0, sizeof(remote_address)); memset(laddr_bytes, 0, sizeof(laddr_bytes)); memset(raddr_bytes, 0, sizeof(raddr_bytes)); local_address.addrtype = ADDRTYPE_INET; local_address.length = sizeof(laddr_bytes); local_address.contents = laddr_bytes; laddr_bytes[0] = 6; laddr_bytes[1] = 2; laddr_bytes[2] = 69; laddr_bytes[3] = 16; laddr_bytes[4] = 1; laddr_bytes[5] = 0; laddr_bytes[6] = 0; laddr_bytes[7] = 127; remote_address.addrtype = ADDRTYPE_INET; remote_address.length = sizeof(raddr_bytes); remote_address.contents = raddr_bytes; raddr_bytes[0] = 6; raddr_bytes[1] = 2; raddr_bytes[2] = 70; raddr_bytes[3] = 16; raddr_bytes[4] = 1; raddr_bytes[5] = 0; raddr_bytes[6] = 0; raddr_bytes[7] = 127; if (!(kret = krb5_auth_con_setaddrs(kcontext, actx, &local_address, &remote_address)) && !(kret = krb5_auth_con_setports(kcontext, actx, &local_address, &remote_address)) && !(kret = ser_data(verbose, "> Auth context with addrs/ports", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { memset(&ukeyblock, 0, sizeof(ukeyblock)); memset(keydata, 0, sizeof(keydata)); ukeyblock.enctype = ENCTYPE_DES_CBC_MD5; ukeyblock.length = sizeof(keydata); ukeyblock.contents = keydata; keydata[0] = 0xde; keydata[1] = 0xad; keydata[2] = 0xbe; keydata[3] = 0xef; keydata[4] = 0xfe; keydata[5] = 0xed; keydata[6] = 0xf0; keydata[7] = 0xd; if (!(kret = krb5_auth_con_setuseruserkey(kcontext, actx, &ukeyblock)) && !(kret = ser_data(verbose, "> Auth context with user key", (krb5_pointer) actx, KV5M_AUTH_CONTEXT)) && !(kret = krb5_auth_con_initivector(kcontext, actx)) && !(kret = ser_data(verbose, "> Auth context with new vector", (krb5_pointer) actx, KV5M_AUTH_CONTEXT)) && (krb5_xfree(actx->i_vector), actx->i_vector) && !(kret = krb5_auth_con_setivector(kcontext, actx, (krb5_pointer) print_erep) ) && !(kret = ser_data(verbose, "> Auth context with set vector", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { /* * Finally, add an authenticator. */ memset(&aent, 0, sizeof(aent)); aent.magic = KV5M_AUTHENTICATOR; snprintf(clname, sizeof(clname), "help/me/%[email protected]", (int) getpid()); actx->authentp = &aent; if (!(kret = krb5_parse_name(kcontext, clname, &aent.client)) && !(kret = ser_data(verbose, "> Auth context with authenticator", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { adataent.magic = KV5M_AUTHDATA; adataent.ad_type = 123; adataent.length = 128; adataent.contents = (krb5_octet *) stuff; adatalist[0] = &adataent; adatalist[1] = &adataent; adatalist[2] = (krb5_authdata *) NULL; aent.authorization_data = adatalist; if (!(kret = ser_data(verbose, "> Auth context with full auth", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { if (verbose) printf("* krb5_auth_context test succeeded\n"); } krb5_free_principal(kcontext, aent.client); } actx->authentp = (krb5_authenticator *) NULL; } } } if (actx) krb5_auth_con_free(kcontext, actx); if (kret) printf("* krb5_auth_context test failed\n"); return(kret); }
static krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, krb5_keytab keytab, const krb5_fulladdr *local_faddr, const krb5_fulladdr *remote_faddr, krb5_data *req, krb5_data *rep) { krb5_error_code ret; char *ptr; unsigned int plen, vno; krb5_data ap_req, ap_rep = empty_data(); krb5_data cipher = empty_data(), clear = empty_data(); krb5_auth_context auth_context = NULL; krb5_principal changepw = NULL; krb5_principal client, target = NULL; krb5_ticket *ticket = NULL; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; char *clientstr = NULL, *targetstr = NULL; const char *errmsg = NULL; size_t clen; char *cdots; struct sockaddr_storage ss; socklen_t salen; char addrbuf[100]; krb5_address *addr = remote_faddr->address; *rep = empty_data(); if (req->length < 4) { /* either this, or the server is printing bad messages, or the caller passed in garbage */ ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request was truncated", sizeof(strresult)); goto bailout; } ptr = req->data; /* verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request length was inconsistent", sizeof(strresult)); goto bailout; } /* verify version number */ vno = (*ptr++ & 0xff) ; vno = (vno<<8) | (*ptr++ & 0xff); if (vno != 1 && vno != RFC3244_VERSION) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_BAD_VERSION; snprintf(strresult, sizeof(strresult), "Request contained unknown protocol version number %d", vno); goto bailout; } /* read, check ap-req length */ ap_req.length = (*ptr++ & 0xff); ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff); if (ptr + ap_req.length >= req->data + req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request was truncated in AP-REQ", sizeof(strresult)); goto bailout; } /* verify ap_req */ ap_req.data = ptr; ptr += ap_req.length; ret = krb5_auth_con_init(context, &auth_context); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed initializing auth context", sizeof(strresult)); goto chpwfail; } ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed initializing auth context", sizeof(strresult)); goto chpwfail; } ret = krb5_build_principal(context, &changepw, strlen(realm), realm, "kadmin", "changepw", NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed building kadmin/changepw principal", sizeof(strresult)); goto chpwfail; } ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab, NULL, &ticket); if (ret) { numresult = KRB5_KPASSWD_AUTHERROR; strlcpy(strresult, "Failed reading application request", sizeof(strresult)); goto chpwfail; } /* construct the ap-rep */ ret = krb5_mk_rep(context, auth_context, &ap_rep); if (ret) { numresult = KRB5_KPASSWD_AUTHERROR; strlcpy(strresult, "Failed replying to application request", sizeof(strresult)); goto chpwfail; } /* decrypt the ChangePasswdData */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; /* * Don't set a remote address in auth_context before calling krb5_rd_priv, * so that we can work against clients behind a NAT. Reflection attacks * aren't a concern since we use sequence numbers and since our requests * don't look anything like our responses. Also don't set a local address, * since we don't know what interface the request was received on. */ ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed decrypting request", sizeof(strresult)); goto chpwfail; } client = ticket->enc_part2->client; /* decode ChangePasswdData for setpw requests */ if (vno == RFC3244_VERSION) { krb5_data *clear_data; ret = decode_krb5_setpw_req(&clear, &clear_data, &target); if (ret != 0) { numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Failed decoding ChangePasswdData", sizeof(strresult)); goto chpwfail; } zapfree(clear.data, clear.length); clear = *clear_data; free(clear_data); if (target != NULL) { ret = krb5_unparse_name(context, target, &targetstr); if (ret != 0) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed unparsing target name for log", sizeof(strresult)); goto chpwfail; } } } ret = krb5_unparse_name(context, client, &clientstr); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed unparsing client name for log", sizeof(strresult)); goto chpwfail; } /* for cpw, verify that this is an AS_REQ ticket */ if (vno == 1 && (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) { numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED; strlcpy(strresult, "Ticket must be derived from a password", sizeof(strresult)); goto chpwfail; } /* change the password */ ptr = k5memdup0(clear.data, clear.length, &ret); ret = schpw_util_wrapper(server_handle, client, target, (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0, ptr, NULL, strresult, sizeof(strresult)); if (ret) errmsg = krb5_get_error_message(context, ret); /* zap the password */ zapfree(clear.data, clear.length); zapfree(ptr, clear.length); clear = empty_data(); clen = strlen(clientstr); trunc_name(&clen, &cdots); switch (addr->addrtype) { case ADDRTYPE_INET: { struct sockaddr_in *sin = ss2sin(&ss); sin->sin_family = AF_INET; memcpy(&sin->sin_addr, addr->contents, addr->length); sin->sin_port = htons(remote_faddr->port); salen = sizeof(*sin); break; } case ADDRTYPE_INET6: { struct sockaddr_in6 *sin6 = ss2sin6(&ss); sin6->sin6_family = AF_INET6; memcpy(&sin6->sin6_addr, addr->contents, addr->length); sin6->sin6_port = htons(remote_faddr->port); salen = sizeof(*sin6); break; } default: { struct sockaddr *sa = ss2sa(&ss); sa->sa_family = AF_UNSPEC; salen = sizeof(*sa); break; } } if (getnameinfo(ss2sa(&ss), salen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0) strlcpy(addrbuf, "<unprintable>", sizeof(addrbuf)); if (vno == RFC3244_VERSION) { size_t tlen; char *tdots; const char *targetp; if (target == NULL) { tlen = clen; tdots = cdots; targetp = targetstr; } else { tlen = strlen(targetstr); trunc_name(&tlen, &tdots); targetp = clientstr; } krb5_klog_syslog(LOG_NOTICE, _("setpw request from %s by %.*s%s for " "%.*s%s: %s"), addrbuf, (int) clen, clientstr, cdots, (int) tlen, targetp, tdots, errmsg ? errmsg : "success"); } else { krb5_klog_syslog(LOG_NOTICE, _("chpw request from %s for %.*s%s: %s"), addrbuf, (int) clen, clientstr, cdots, errmsg ? errmsg : "success"); } switch (ret) { case KADM5_AUTH_CHANGEPW: numresult = KRB5_KPASSWD_ACCESSDENIED; break; case KADM5_PASS_Q_TOOSHORT: case KADM5_PASS_REUSE: case KADM5_PASS_Q_CLASS: case KADM5_PASS_Q_DICT: case KADM5_PASS_Q_GENERIC: case KADM5_PASS_TOOSOON: numresult = KRB5_KPASSWD_SOFTERROR; break; case 0: numresult = KRB5_KPASSWD_SUCCESS; strlcpy(strresult, "", sizeof(strresult)); break; default: numresult = KRB5_KPASSWD_HARDERROR; break; } chpwfail: ret = alloc_data(&clear, 2 + strlen(strresult)); if (ret) goto bailout; ptr = clear.data; *ptr++ = (numresult>>8) & 0xff; *ptr++ = numresult & 0xff; memcpy(ptr, strresult, strlen(strresult)); cipher = empty_data(); if (ap_rep.length) { ret = krb5_auth_con_setaddrs(context, auth_context, local_faddr->address, NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed storing client and server internet addresses", sizeof(strresult)); } else { ret = krb5_mk_priv(context, auth_context, &clear, &cipher, &replay); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed encrypting reply", sizeof(strresult)); } } } /* if no KRB-PRIV was constructed, then we need a KRB-ERROR. if this fails, just bail. there's nothing else we can do. */ if (cipher.length == 0) { /* clear out ap_rep now, so that it won't be inserted in the reply */ if (ap_rep.length) { free(ap_rep.data); ap_rep = empty_data(); } krberror.ctime = 0; krberror.cusec = 0; krberror.susec = 0; ret = krb5_timeofday(context, &krberror.stime); if (ret) goto bailout; /* this is really icky. but it's what all the other callers to mk_error do. */ krberror.error = ret; krberror.error -= ERROR_TABLE_BASE_krb5; if (krberror.error < 0 || krberror.error > KRB_ERR_MAX) krberror.error = KRB_ERR_GENERIC; krberror.client = NULL; ret = krb5_build_principal(context, &krberror.server, strlen(realm), realm, "kadmin", "changepw", NULL); if (ret) goto bailout; krberror.text.length = 0; krberror.e_data = clear; ret = krb5_mk_error(context, &krberror, &cipher); krb5_free_principal(context, krberror.server); if (ret) goto bailout; } /* construct the reply */ ret = alloc_data(rep, 6 + ap_rep.length + cipher.length); if (ret) goto bailout; ptr = rep->data; /* length */ *ptr++ = (rep->length>>8) & 0xff; *ptr++ = rep->length & 0xff; /* version == 0x0001 big-endian */ *ptr++ = 0; *ptr++ = 1; /* ap_rep length, big-endian */ *ptr++ = (ap_rep.length>>8) & 0xff; *ptr++ = ap_rep.length & 0xff; /* ap-rep data */ if (ap_rep.length) { memcpy(ptr, ap_rep.data, ap_rep.length); ptr += ap_rep.length; } /* krb-priv or krb-error */ memcpy(ptr, cipher.data, cipher.length); bailout: krb5_auth_con_free(context, auth_context); krb5_free_principal(context, changepw); krb5_free_ticket(context, ticket); free(ap_rep.data); free(clear.data); free(cipher.data); krb5_free_principal(context, target); krb5_free_unparsed_name(context, targetstr); krb5_free_unparsed_name(context, clientstr); krb5_free_error_message(context, errmsg); return ret; }
static int cifs_krb5_get_req(const char *host, const char *ccname, DATA_BLOB * mechtoken, DATA_BLOB * sess_key) { krb5_error_code ret; krb5_keyblock *tokb; krb5_context context; krb5_ccache ccache; krb5_creds in_creds, *out_creds; krb5_data apreq_pkt, in_data; krb5_auth_context auth_context = NULL; #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) static const uint8_t gss_cksum[24] = { 0x10, 0x00, /* ... */}; #endif ret = krb5_init_context(&context); if (ret) { syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); return ret; } ret = krb5_cc_resolve(context, ccname, &ccache); if (ret) { syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n", __func__, ccname); goto out_free_context; } memset(&in_creds, 0, sizeof(in_creds)); ret = krb5_cc_get_principal(context, ccache, &in_creds.client); if (ret) { syslog(LOG_DEBUG, "%s: unable to get client principal name", __func__); goto out_free_ccache; } ret = krb5_sname_to_principal(context, host, "cifs", KRB5_NT_UNKNOWN, &in_creds.server); if (ret) { syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).", __func__, host); goto out_free_principal; } ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); krb5_free_principal(context, in_creds.server); if (ret) { syslog(LOG_DEBUG, "%s: unable to get credentials for %s", __func__, host); goto out_free_principal; } in_data.length = 0; in_data.data = NULL; ret = krb5_auth_con_init(context, &auth_context); if (ret) { syslog(LOG_DEBUG, "%s: unable to create auth_context: %d", __func__, ret); goto out_free_creds; } #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) /* Ensure we will get an addressless ticket. */ ret = krb5_auth_con_setaddrs(context, auth_context, NULL, NULL); if (ret) { syslog(LOG_DEBUG, "%s: unable to set NULL addrs: %d", __func__, ret); goto out_free_auth; } /* * Create a GSSAPI checksum (0x8003), see RFC 4121. * * The current layout is * * 0x10, 0x00, 0x00, 0x00 - length = 16 * 0x00, 0x00, 0x00, 0x00 - channel binding info - 16 zero bytes * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 - flags * * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes, * this is needed to work against some closed source * SMB servers. * * See https://bugzilla.samba.org/show_bug.cgi?id=7890 */ in_data.data = discard_const_p(char, gss_cksum); in_data.length = 24; /* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */ #if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE krb5_error_code krb5_auth_con_set_req_cksumtype( krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype); #endif ret = krb5_auth_con_set_req_cksumtype(context, auth_context, 0x8003); if (ret) { syslog(LOG_DEBUG, "%s: unable to set 0x8003 checksum", __func__); goto out_free_auth; } #endif apreq_pkt.length = 0; apreq_pkt.data = NULL; ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, &in_data, out_creds, &apreq_pkt); if (ret) { syslog(LOG_DEBUG, "%s: unable to make AP-REQ for %s", __func__, host); goto out_free_auth; } ret = krb5_auth_con_getsendsubkey(context, auth_context, &tokb); if (ret) { syslog(LOG_DEBUG, "%s: unable to get session key for %s", __func__, host); goto out_free_auth; } *mechtoken = data_blob(apreq_pkt.data, apreq_pkt.length); *sess_key = data_blob(KRB5_KEY_DATA(tokb), KRB5_KEY_LENGTH(tokb)); krb5_free_keyblock(context, tokb); out_free_auth: krb5_auth_con_free(context, auth_context); out_free_creds: krb5_free_creds(context, out_creds); out_free_principal: krb5_free_principal(context, in_creds.client); out_free_ccache: #if defined(KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); #endif krb5_cc_close(context, ccache); out_free_context: krb5_free_context(context); return ret; }
/* XXX - check for cleanup */ krb5_error_code setup_auth_context(krb5_context context, krb5_auth_context auth_context, struct sockaddr_in *localaddr, struct sockaddr_in *remoteaddr, char *uniq) { krb5_address laddr, raddr, *portlocal_addr; krb5_rcache rcache; krb5_data rcache_name; char *outaddr; krb5_error_code retval; #ifndef HEIMDAL /* Setting ports isn't compatible with Heimdal, if this code is enabled, it's not possible to have an interoperable setup */ #if 0 laddr.addrtype = ADDRTYPE_IPPORT; laddr.length = sizeof(localaddr->sin_port); laddr.contents = (krb5_octet *)&(localaddr->sin_port); raddr.addrtype = ADDRTYPE_IPPORT; raddr.length = sizeof(remoteaddr->sin_port); raddr.contents = (krb5_octet *)&(remoteaddr->sin_port); if (retval = krb5_auth_con_setports(context, auth_context, &laddr, &raddr)) { sprintf(auth_con_error, "%s while setting auth_con ports\n", error_message(retval)); return retval; } #endif #endif #ifdef HEIMDAL laddr.addr_type = KRB5_ADDRESS_INET; laddr.address.length = sizeof(localaddr->sin_addr); laddr.address.data = (void *)&(localaddr->sin_addr); raddr.addr_type = KRB5_ADDRESS_INET; raddr.address.length = sizeof(remoteaddr->sin_addr); raddr.address.data = (void *)&(remoteaddr->sin_addr); #else laddr.addrtype = ADDRTYPE_INET; laddr.length = sizeof(localaddr->sin_addr); laddr.contents = (krb5_octet *)&(localaddr->sin_addr); raddr.addrtype = ADDRTYPE_INET; raddr.length = sizeof(remoteaddr->sin_addr); raddr.contents = (krb5_octet *)&(remoteaddr->sin_addr); #endif if (retval = krb5_auth_con_setaddrs(context, auth_context, &laddr, &raddr)) { sprintf(auth_con_error, "%s while setting auth_con addresses\n", error_message(retval)); return retval; } #ifdef HEIMDAL #else /* Set up replay cache */ if ((retval = krb5_gen_portaddr(context, &laddr, (krb5_pointer) &(localaddr->sin_port), &portlocal_addr))) { sprintf(auth_con_error, "%s while generating port address", error_message(retval)); return retval; } if ((retval = krb5_gen_replay_name(context, portlocal_addr, uniq, &outaddr))) { sprintf(auth_con_error, "%s while generating replay cache name", error_message(retval)); return retval; } rcache_name.length = strlen(outaddr); rcache_name.data = outaddr; if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) { sprintf(auth_con_error, "%s while getting server rcache", error_message(retval)); return retval; } if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { sprintf(auth_con_error, "%s setting rcache", error_message(retval)); return retval; } #endif return retval; }
static int verify (krb5_auth_context *auth_context, krb5_realm *realms, krb5_keytab keytab, krb5_ticket **ticket, krb5_data *out_data, uint16_t *version, int s, struct sockaddr *sa, int sa_size, u_char *msg, size_t len, krb5_address *client_addr) { krb5_error_code ret; uint16_t pkt_len, pkt_ver, ap_req_len; krb5_data ap_req_data; krb5_data krb_priv_data; krb5_realm *r; /* * Only send an error reply if the request passes basic length * verification. Otherwise, kpasswdd would reply to every UDP packet, * allowing an attacker to set up a ping-pong DoS attack via a spoofed UDP * packet with a source address of another UDP service that also replies * to every packet. * * Also suppress the error reply if ap_req_len is 0, which indicates * either an invalid request or an error packet. An error packet may be * the result of a ping-pong attacker pointing us at another kpasswdd. */ pkt_len = (msg[0] << 8) | (msg[1]); pkt_ver = (msg[2] << 8) | (msg[3]); ap_req_len = (msg[4] << 8) | (msg[5]); if (pkt_len != len) { krb5_warnx (context, "Strange len: %ld != %ld", (long)pkt_len, (long)len); return 1; } if (ap_req_len == 0) { krb5_warnx (context, "Request is error packet (ap_req_len == 0)"); return 1; } if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW && pkt_ver != KRB5_KPASSWD_VERS_SETPW) { krb5_warnx (context, "Bad version (%d)", pkt_ver); reply_error (NULL, s, sa, sa_size, 0, 1, "Wrong program version"); return 1; } *version = pkt_ver; ap_req_data.data = msg + 6; ap_req_data.length = ap_req_len; ret = krb5_rd_req (context, auth_context, &ap_req_data, NULL, keytab, NULL, ticket); if (ret) { krb5_warn (context, ret, "krb5_rd_req"); reply_error (NULL, s, sa, sa_size, ret, 3, "Authentication failed"); return 1; } /* verify realm and principal */ for (r = realms; *r != NULL; r++) { krb5_principal principal; krb5_boolean same; ret = krb5_make_principal (context, &principal, *r, "kadmin", "changepw", NULL); if (ret) krb5_err (context, 1, ret, "krb5_make_principal"); same = krb5_principal_compare(context, principal, (*ticket)->server); krb5_free_principal(context, principal); if (same == TRUE) break; } if (*r == NULL) { char *str; krb5_unparse_name(context, (*ticket)->server, &str); krb5_warnx (context, "client used not valid principal %s", str); free(str); reply_error (NULL, s, sa, sa_size, ret, 1, "Bad request"); goto out; } if (strcmp((*ticket)->server->realm, (*ticket)->client->realm) != 0) { krb5_warnx (context, "server realm (%s) not same a client realm (%s)", (*ticket)->server->realm, (*ticket)->client->realm); reply_error ((*ticket)->server->realm, s, sa, sa_size, ret, 1, "Bad request"); goto out; } if (!(*ticket)->ticket.flags.initial) { krb5_warnx (context, "initial flag not set"); reply_error ((*ticket)->server->realm, s, sa, sa_size, ret, 1, "Bad request"); goto out; } krb_priv_data.data = msg + 6 + ap_req_len; krb_priv_data.length = len - 6 - ap_req_len; /* * Only enforce client addresses on on tickets with addresses. If * its addressless, we are guessing its behind NAT and really * can't know this information. */ if ((*ticket)->ticket.caddr && (*ticket)->ticket.caddr->len > 0) { ret = krb5_auth_con_setaddrs (context, *auth_context, NULL, client_addr); if (ret) { krb5_warn (context, ret, "krb5_auth_con_setaddr(this)"); goto out; } } ret = krb5_rd_priv (context, *auth_context, &krb_priv_data, out_data, NULL); if (ret) { krb5_warn (context, ret, "krb5_rd_priv"); reply_error ((*ticket)->server->realm, s, sa, sa_size, ret, 3, "Bad request"); goto out; } return 0; out: krb5_free_ticket (context, *ticket); ticket = NULL; return 1; }
static int proto (int sock, const char *hostname, const char *service) { struct sockaddr_in remote, local; socklen_t addrlen; krb5_address remote_addr, local_addr; krb5_context context; krb5_ccache ccache; krb5_auth_context auth_context; krb5_error_code status; krb5_principal client; krb5_data data; krb5_data packet; krb5_creds mcred, cred; krb5_ticket *ticket; addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 || addrlen != sizeof(local)) err (1, "getsockname(%s)", hostname); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 || addrlen != sizeof(remote)) err (1, "getpeername(%s)", hostname); status = krb5_init_context(&context); if (status) errx(1, "krb5_init_context failed: %d", status); status = krb5_cc_default (context, &ccache); if (status) krb5_err(context, 1, status, "krb5_cc_default"); status = krb5_auth_con_init (context, &auth_context); if (status) krb5_err(context, 1, status, "krb5_auth_con_init"); local_addr.addr_type = AF_INET; local_addr.address.length = sizeof(local.sin_addr); local_addr.address.data = &local.sin_addr; remote_addr.addr_type = AF_INET; remote_addr.address.length = sizeof(remote.sin_addr); remote_addr.address.data = &remote.sin_addr; status = krb5_auth_con_setaddrs (context, auth_context, &local_addr, &remote_addr); if (status) krb5_err(context, 1, status, "krb5_auth_con_setaddr"); krb5_cc_clear_mcred(&mcred); status = krb5_cc_get_principal(context, ccache, &client); if(status) krb5_err(context, 1, status, "krb5_cc_get_principal"); status = krb5_make_principal(context, &mcred.server, krb5_principal_get_realm(context, client), "krbtgt", krb5_principal_get_realm(context, client), NULL); if(status) krb5_err(context, 1, status, "krb5_make_principal"); mcred.client = client; status = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred); if(status) krb5_err(context, 1, status, "krb5_cc_retrieve_cred"); { char *client_name; krb5_data data; status = krb5_unparse_name(context, cred.client, &client_name); if(status) krb5_err(context, 1, status, "krb5_unparse_name"); data.data = client_name; data.length = strlen(client_name) + 1; status = krb5_write_message(context, &sock, &data); if(status) krb5_err(context, 1, status, "krb5_write_message"); free(client_name); } status = krb5_write_message(context, &sock, &cred.ticket); if(status) krb5_err(context, 1, status, "krb5_write_message"); status = krb5_auth_con_setuserkey(context, auth_context, &cred.session); if(status) krb5_err(context, 1, status, "krb5_auth_con_setuserkey"); status = krb5_recvauth(context, &auth_context, &sock, VERSION, client, 0, NULL, &ticket); if (status) krb5_err(context, 1, status, "krb5_recvauth"); if (ticket->ticket.authorization_data) { AuthorizationData *authz; int i; printf("Authorization data:\n"); authz = ticket->ticket.authorization_data; for (i = 0; i < authz->len; i++) { printf("\ttype %d, length %lu\n", authz->val[i].ad_type, (unsigned long)authz->val[i].ad_data.length); } } data.data = "hej"; data.length = 3; krb5_data_zero (&packet); status = krb5_mk_safe (context, auth_context, &data, &packet, NULL); if (status) krb5_err(context, 1, status, "krb5_mk_safe"); status = krb5_write_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_write_message"); data.data = "hemligt"; data.length = 7; krb5_data_free (&packet); status = krb5_mk_priv (context, auth_context, &data, &packet, NULL); if (status) krb5_err(context, 1, status, "krb5_mk_priv"); status = krb5_write_message(context, &sock, &packet); if(status) krb5_err(context, 1, status, "krb5_write_message"); return 0; }
static void process (krb5_realm *realms, krb5_keytab keytab, int s, krb5_address *this_addr, struct sockaddr *sa, int sa_size, u_char *msg, int len) { krb5_error_code ret; krb5_auth_context auth_context = NULL; krb5_data out_data; krb5_ticket *ticket; krb5_address other_addr; uint16_t version; memset(&other_addr, 0, sizeof(other_addr)); krb5_data_zero (&out_data); ret = krb5_auth_con_init (context, &auth_context); if (ret) { krb5_warn (context, ret, "krb5_auth_con_init"); return; } krb5_auth_con_setflags (context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); ret = krb5_sockaddr2address (context, sa, &other_addr); if (ret) { krb5_warn (context, ret, "krb5_sockaddr2address"); goto out; } ret = krb5_auth_con_setaddrs (context, auth_context, this_addr, NULL); if (ret) { krb5_warn (context, ret, "krb5_auth_con_setaddr(this)"); goto out; } if (verify (&auth_context, realms, keytab, &ticket, &out_data, &version, s, sa, sa_size, msg, len, &other_addr) == 0) { /* * We always set the client_addr, to assume that the client * can ignore it if it choose to do so (just the server does * so for addressless tickets). */ ret = krb5_auth_con_setaddrs (context, auth_context, this_addr, &other_addr); if (ret) { krb5_warn (context, ret, "krb5_auth_con_setaddr(other)"); goto out; } change (auth_context, ticket->client, version, s, sa, sa_size, &out_data); memset (out_data.data, 0, out_data.length); krb5_free_ticket (context, ticket); } out: krb5_free_address(context, &other_addr); krb5_data_free(&out_data); krb5_auth_con_free(context, auth_context); }
OM_uint32 gss_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_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 tmp; int32_t flags; OM_uint32 minor; int is_cfx = 0; GSSAPI_KRB5_INIT (); localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } *context_handle = malloc(sizeof(**context_handle)); if (*context_handle == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } memset (*context_handle, 0, sizeof(**context_handle)); HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex); kret = krb5_auth_con_init (gssapi_krb5_context, &(*context_handle)->auth_context); if (kret) { gssapi_krb5_set_error_string (); *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 = (*context_handle)->auth_context; krb5_ret_int32 (sp, &ac->flags); 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 (gssapi_krb5_context, ac, localp, remotep); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_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 (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (krb5_ret_int32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_int32 (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 = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->source); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->source); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->target); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->target); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp) == 0) (*context_handle)->lifetime = tmp; else (*context_handle)->lifetime = GSS_C_INDEFINITE; gsskrb5_is_cfx(*context_handle, &is_cfx); ret = _gssapi_msg_order_create(minor_status, &(*context_handle)->order, _gssapi_msg_order_f((*context_handle)->flags), 0, 0, is_cfx); if (ret) goto failure; krb5_storage_free (sp); return GSS_S_COMPLETE; failure: krb5_auth_con_free (gssapi_krb5_context, (*context_handle)->auth_context); if ((*context_handle)->source != NULL) gss_release_name(&minor, &(*context_handle)->source); if ((*context_handle)->target != NULL) gss_release_name(&minor, &(*context_handle)->target); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_context, remotep); if((*context_handle)->order) _gssapi_msg_order_destroy(&(*context_handle)->order); HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); krb5_storage_free (sp); free (*context_handle); *context_handle = GSS_C_NO_CONTEXT; return ret; }
static krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, int s, krb5_keytab keytab, struct sockaddr_in *sin, krb5_data *req, krb5_data *rep) { krb5_error_code ret; char *ptr; int plen, vno; krb5_address local_kaddr, remote_kaddr; int allocated_mem = 0; krb5_data ap_req, ap_rep; krb5_auth_context auth_context; krb5_principal changepw; krb5_ticket *ticket; krb5_data cipher, clear; struct sockaddr local_addr, remote_addr; int addrlen; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; ret = 0; rep->length = 0; auth_context = NULL; changepw = NULL; ap_rep.length = 0; ap_rep.data = NULL; ticket = NULL; clear.length = 0; clear.data = NULL; cipher.length = 0; cipher.data = NULL; if (req->length < 4) { /* * either this, or the server is printing bad messages, * or the caller passed in garbage */ ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated", sizeof (strresult)); goto chpwfail; } ptr = req->data; /* * Verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != req->length) return (KRB5KRB_AP_ERR_MODIFIED); /* * Verify version number */ vno = (*ptr++ & 0xff); vno = (vno<<8) | (*ptr++ & 0xff); if (vno != 1) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_MALFORMED; (void) snprintf(strresult, sizeof (strresult), "Request contained unknown protocol version number %d", vno); goto chpwfail; } /* * Read, check ap-req length */ ap_req.length = (*ptr++ & 0xff); ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff); if (ptr + ap_req.length >= req->data + req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated in AP-REQ", sizeof (strresult)); goto chpwfail; } /* * Verify ap_req */ ap_req.data = ptr; ptr += ap_req.length; if (ret = krb5_auth_con_init(context, &auth_context)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed initializing auth context: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed setting auth " "context flags: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm, "kadmin", "changepw", NULL)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed " "Failed to build kadmin/changepw " "principal: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed building kadmin/changepw principal", sizeof (strresult)); goto chpwfail; } ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab, NULL, &ticket); if (ret) { char kt_name[MAX_KEYTAB_NAME_LEN]; if (krb5_kt_get_name(context, keytab, kt_name, sizeof (kt_name))) strncpy(kt_name, "default keytab", sizeof (kt_name)); switch (ret) { case KRB5_KT_NOTFOUND: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab entry \"kadmin/changepw\" " "is missing from \"%s\""), kt_name); break; case ENOENT: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab file \"%s\" does not exist"), kt_name); break; default: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed to parse Kerberos AP_REQ message: %s"), error_message(ret)); } numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed reading application request", sizeof (strresult)); goto chpwfail; } /* * Set up address info */ addrlen = sizeof (local_addr); if (getsockname(s, &local_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting server internet address", sizeof (strresult)); goto chpwfail; } /* * Some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof (((struct sockaddr_in *) &local_addr)->sin_addr); /* CSTYLED */ local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&local_addr)->sin_addr); } else { krb5_address **addrs; krb5_os_localaddr(context, &addrs); local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for local_kaddr", sizeof (strresult)); goto chpwfail; } (void) memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); allocated_mem++; krb5_free_addresses(context, addrs); } addrlen = sizeof (remote_addr); if (getpeername(s, &remote_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting client internet address", sizeof (strresult)); goto chpwfail; } remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (((struct sockaddr_in *) &remote_addr)->sin_addr); /* CSTYLED */ remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr); remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (sin->sin_addr); remote_kaddr.contents = (krb5_octet *) &sin->sin_addr; /* * mk_priv requires that the local address be set. * getsockname is used for this. rd_priv requires that the * remote address be set. recvfrom is used for this. If * rd_priv is given a local address, and the message has the * recipient addr in it, this will be checked. However, there * is simply no way to know ahead of time what address the * message will be delivered *to*. Therefore, it is important * that either no recipient address is in the messages when * mk_priv is called, or that no local address is passed to * rd_priv. Both is a better idea, and I have done that. In * summary, when mk_priv is called, *only* a local address is * specified. when rd_priv is called, *only* a remote address * is specified. Are we having fun yet? */ if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL, &remote_kaddr)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client internet address", sizeof (strresult)); goto chpwfail; } /* * Verify that this is an AS_REQ ticket */ if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Ticket must be derived from a password", sizeof (strresult)); goto chpwfail; } /* * Construct the ap-rep */ if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed replying to application request", sizeof (strresult)); goto chpwfail; } /* * Decrypt the new password */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; if (ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed decrypting request", sizeof (strresult)); goto chpwfail; } /* * Change the password */ if ((ptr = (char *)malloc(clear.length + 1)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for ptr", sizeof (strresult)); goto chpwfail; } (void) memcpy(ptr, clear.data, clear.length); ptr[clear.length] = '\0'; ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle, ticket->enc_part2->client, ptr, NULL, strresult, sizeof (strresult)); /* * Zap the password */ (void) memset(clear.data, 0, clear.length); (void) memset(ptr, 0, clear.length); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } free(ptr); clear.length = 0; if (ret) { if ((ret != KADM5_PASS_Q_TOOSHORT) && (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON)) numresult = KRB5_KPASSWD_HARDERROR; else numresult = KRB5_KPASSWD_SOFTERROR; /* * strresult set by kadb5_chpass_principal_util() */ goto chpwfail; } /* * Success! */ numresult = KRB5_KPASSWD_SUCCESS; (void) strlcpy(strresult, "", sizeof (strresult)); chpwfail: clear.length = 2 + strlen(strresult); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } if ((clear.data = (char *)malloc(clear.length)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for clear.data", sizeof (strresult)); } cipher.length = 0; if (ap_rep.length) { if (ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client and server internet addresses", sizeof (strresult)); } else { if (ret = krb5_mk_priv(context, auth_context, &clear, &cipher, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed encrypting reply", sizeof (strresult)); } } } ptr = clear.data; *ptr++ = (numresult>>8) & 0xff; *ptr++ = numresult & 0xff; (void) memcpy(ptr, strresult, strlen(strresult)); /* * If no KRB-PRIV was constructed, then we need a KRB-ERROR. * If this fails, just bail. There's nothing else we can do. */ if (cipher.length == 0) { /* * Clear out ap_rep now, so that it won't be inserted * in the reply */ if (ap_rep.length) { if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); ap_rep.data = NULL; ap_rep.length = 0; } krberror.ctime = 0; krberror.cusec = 0; krberror.susec = 0; if (ret = krb5_timeofday(context, &krberror.stime)) goto bailout; /* * This is really icky. but it's what all the other callers * to mk_error do. */ krberror.error = ret; krberror.error -= ERROR_TABLE_BASE_krb5; if (krberror.error < 0 || krberror.error > 128) krberror.error = KRB_ERR_GENERIC; krberror.client = NULL; if (ret = krb5_build_principal(context, &krberror.server, strlen(realm), realm, "kadmin", "changepw", NULL)) { goto bailout; } krberror.text.length = 0; krberror.e_data = clear; ret = krb5_mk_error(context, &krberror, &cipher); krb5_free_principal(context, krberror.server); if (ret) goto bailout; } /* * Construct the reply */ rep->length = 6 + ap_rep.length + cipher.length; if ((rep->data = (char *)malloc(rep->length)) == NULL) { ret = errno; goto bailout; } ptr = rep->data; /* * Length */ *ptr++ = (rep->length>>8) & 0xff; *ptr++ = rep->length & 0xff; /* * Version == 0x0001 big-endian */ *ptr++ = 0; *ptr++ = 1; /* * ap_rep length, big-endian */ *ptr++ = (ap_rep.length>>8) & 0xff; *ptr++ = ap_rep.length & 0xff; /* * ap-rep data */ if (ap_rep.length) { (void) memcpy(ptr, ap_rep.data, ap_rep.length); ptr += ap_rep.length; } /* * krb-priv or krb-error */ (void) memcpy(ptr, cipher.data, cipher.length); bailout: if (auth_context) krb5_auth_con_free(context, auth_context); if (changepw) krb5_free_principal(context, changepw); if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); if (ticket) krb5_free_ticket(context, ticket); if (clear.data != NULL) krb5_xfree(clear.data); if (cipher.data != NULL) krb5_xfree(cipher.data); if (allocated_mem) krb5_xfree(local_kaddr.contents); return (ret); }