diff --git a/kdc/Makefile.am b/kdc/Makefile.am index c7f57251f..48248d824 100644 --- a/kdc/Makefile.am +++ b/kdc/Makefile.am @@ -44,6 +44,7 @@ bx509d_LDADD = -ldl \ $(MICROHTTPD_LIBS) \ $(LIB_roken) \ $(LIB_heimbase) \ + $(LIB_hcrypto) \ $(top_builddir)/lib/sl/libsl.la \ $(top_builddir)/lib/asn1/libasn1.la \ $(top_builddir)/lib/krb5/libkrb5.la \ diff --git a/kdc/bx509d.8 b/kdc/bx509d.8 index 512d0545e..f94015568 100644 --- a/kdc/bx509d.8 +++ b/kdc/bx509d.8 @@ -40,7 +40,11 @@ .Op Fl Fl version .Op Fl H Ar HOSTNAME .Op Fl d | Fl Fl daemon -.Op Fl Fl daemon-child +.Op Fl Fl allow-GET +.Op Fl Fl no-allow-GET +.Op Fl Fl csrf-protection-type= Ns Ar CSRF-PROTECTION-TYPE +.Op Fl Fl csrf-header= Ns Ar HEADER-NAME +.Op Fl Fl csrf-key-file= Ns Ar FILE .Op Fl Fl reverse-proxied .Op Fl p Ar port number (default: 443) .Op Fl Fl cache-dir= Ns Ar DIRECTORY @@ -53,11 +57,24 @@ .Oc .Sh DESCRIPTION Serves RESTful (HTTPS) GETs of -.Ar /bx509 and -.Ar /bnegotiate , -end-points -performing corresponding kx509 and, possibly, PKINIT requests -to the KDCs of the requested realms (or just the given REALM). +.Ar /get-cert , +.Ar /get-tgt , +.Ar /get-tgts , +and +.Ar /get-negotiate-token , +end-points that implement various experimental Heimdal features: +.Bl -bullet -compact -offset indent +.It +.Li an online CA service over HTTPS, +.It +.Li a kinit-over-HTTPS service, and +.It +.Li a Negotiate token over HTTPS service. +.El +.Pp +As well, a +.Ar /health +service can be used for checking service status. .Pp Supported options: .Bl -tag -width Ds @@ -75,6 +92,64 @@ Print version. .Xc Expected audience(s) of bearer tokens (i.e., acceptor name). .It Xo +.Fl Fl allow-GET +.Xc +If given, then HTTP GET will be allowed for the various +end-points other than +.Ar /health . +Otherwise only HEAD and POST will be allowed. +By default GETs are allowed, but this will change soon. +.It Xo +.Fl Fl no-allow-GET +.Xc +If given then HTTP GETs will be rejected for the various +end-points other than +.Ar /health . +.It Xo +.Fl Fl csrf-protection-type= Ns Ar CSRF-PROTECTION-TYPE +.Xc +Possible values of +.Ar CSRF-PROTECTION-TYPE +are +.Bl -bullet -compact -offset indent +.It +.Li GET-with-header +.It +.Li GET-with-token +.It +.Li POST-with-header +.It +.Li POST-with-token +.El +This may be given multiple times. +The default is to require CSRF tokens for POST requests, and to +require neither a non-simple header nor a CSRF token for GET +requests. +.Pp +See +.Sx CROSS-SITE REQUEST FORGERY PROTECTION . +.It Xo +.Fl Fl csrf-header= Ns Ar HEADER-NAME +.Xc +If given, then all requests other than to the +.Ar /health +service must have the given request +.Ar HEADER-NAME +set (the value is irrelevant). +The +.Ar HEADER-NAME +must be a request header name such that a request having it makes +it not a +.Dq simple +request (see the Cross-Origin Resource Sharing specification). +Defaults to +.Ar X-CSRF . +.It Xo +.Fl Fl csrf-key-file= Ns Ar FILE +.Xc +If given, this file must contain a 16 byte binary key for keying +the HMAC used in CSRF token construction. +.It Xo .Fl d , .Fl Fl daemon .Xc @@ -82,7 +157,8 @@ Detach from TTY and run in the background. .It Xo .Fl Fl reverse-proxied .Xc -Serves HTTP instead of HTTPS, accepting only looped-back connections. +Serves HTTP instead of HTTPS, accepting only looped-back +connections. .It Xo .Fl p Ar port number (default: 443) .Xc @@ -90,29 +166,106 @@ PORT .It Xo .Fl Fl cache-dir= Ns Ar DIRECTORY .Xc -Directory for various caches. If not specified then a temporary directory will -be made. +Directory for various caches. +If not specified then a temporary directory will be made. .It Xo .Fl Fl cert= Ns Ar HX509-STORE .Xc -Certificate file path (PEM) for HTTPS service. May contain private key as -well. +Certificate file path (PEM) for HTTPS service. +May contain private key as well. .It Xo .Fl Fl private-key= Ns Ar HX509-STORE .Xc -Private key file path (PEM), if the private key is not stored along with the -certificiate. +Private key file path (PEM), if the private key is not stored +along with the certificiate. .It Xo .Fl t , .Fl Fl thread-per-client .Xc -Uses a thread per-client instead of as many threads as there are CPUs. +Uses a thread per-client instead of as many threads as there are +CPUs. .It Xo .Fl v , .Fl Fl verbose= Ns Ar run verbosely .Xc verbose .El +.Sh HTTP APIS +All HTTP APIs served by this program accept POSTs, with all +request parameters given as URI query parameters and/or as +form data in the POST request body, in either +.Ar application/x-www-form-urlencoded +or +.Ar multipart/formdata . +If request parameters are given both as URI query parameters +and as POST forms, then they are merged into a set. +.Pp +If GETs are enabled, then request parameters must be supplied +only as URI query parameters, as GET requests do not have request +bodies. +.Pp +URI query parameters must be of the form +.Ar param0=value¶m1=value... +.Pp +Some request parameters can only have one value. +If multiple values are given for such parameters, then either an +error will be produced, or only the first URI query parameter +value will be used, or the first POST form data parameter will be +used. +Other request parameters can have multiple values. +See below. +.Sh CROSS-SITE REQUEST FORGERY PROTECTION +.Em None +of the resources service by this service are intended to be +executed by web pages. +.Pp +All the resources provided by this service are +.Dq safe +in the sense that they do not change server-side state besides +logging, and in that they are idempotent, but they are +only safe to execute +.Em if and only if +the requesting party is trusted to see the response. +Since none of these resources are intended to be used from web +pages, it is important that web pages not be able to execute them +.Em and +observe the responses. +.Pp +In a web browser context, pages from other origins will be able +to attempt requests to this service, but should never be able to +see the responses because browsers normally wouldn't allow that. +Nonetheless, anti cross site request forgery (CSRF) protection +may be desirable. +.Pp +This service provides the following CSRF protection features: +.Bl -tag -width Ds -offset indent +.It requests are rejected if they have a +.Dq Referer +(except the experimental /get-negotiate-token end-point) +.It the service can be configured to require a header that would make the +request not Dq simple +.It GETs can be disabled (see options), thus requiring POSTs +.It GETs can be required to have a CSRF token (see below) +.It POSTs can be required to have a CSRF token +.El +.Pp +The experimental +.Ar /get-negotiate-token +end-point, however, always accepts +.Dq Referer +requests. +.Pp +To obtain a CSRF token, first execute the request without the +CSRF token, and the resulting error +response will include a +.Ar X-CSRF-Token +response header. +.Pp +To execute a request with a CSRF token, first obtain a CSRF token +as described above, then copy the token to the request as the +value of the request's +.Ar X-CSRF-Token +header. .Sh ONLINE CERTIFICATION AUTHORITY HTTP API This service provides an HTTP-based Certification Authority (CA). CA credentials and configuration are specified in the @@ -128,8 +281,8 @@ with the base-63 encoding of a DER encoding of a PKCS#10 .Ar CertificationRequest (Certificate Signing Request, or CSR) in a .Ar csr -required query parameter. -In a successful query, the response body will contain a PEM +required request parameter. +In a successful request, the response body will contain a PEM encoded end entity certificate and certification chain. .Pp Or @@ -146,9 +299,9 @@ Unauthorized requests will elicit a 403 response. .Pp Subject Alternative Names (SANs) and Extended Key Usage values may be requested, both in-band in the CSR as a requested -extensions attribute, and/or via optional query parameters. +extensions attribute, and/or via optional request parameters. .Pp -Supported query parameters (separated by ampersands) +Supported request parameters: .Bl -tag -width Ds -offset indent .It Li csr = Va base64-encoded-DER-encoded-CSR .It Li dNSName = Va hostname @@ -178,20 +331,20 @@ of .Ar /get-negotiate-token with a .Ar target = Ar service@host -query parameter. +request parameter. .Pp -In a successful query, the response body will contain a Negotiate -token for the authenticated client principal to the requested -target. +In a successful request, the response body will contain a +Negotiate token for the authenticated client principal to the +requested target. .Pp Authentication is required. Unauthenticated requests will elicit a 401 response. .Pp Subject Alternative Names (SANs) and Extended Key Usage values may be requested, both in-band in the CSR as a requested -extensions attribute, and/or via optional query parameters. +extensions attribute, and/or via optional request parameters. .Pp -Supported query parameters (separated by ampersands) +Supported request parameters: .Bl -tag -width Ds -offset indent .It Li target = Va service@hostname .It Li redirect = Va URI @@ -221,13 +374,14 @@ The protocol consists of a of .Ar /get-tgt . .Pp -Supported query parameters (separated by ampersands) +Supported request parameters: .Bl -tag -width Ds -offset indent .It Li cname = Va principal-name .It Li address = Va IP-address +.It Li lifetime = Va relative-time .El .Pp -In a successful query, the response body will contain a TGT and +In a successful request, the response body will contain a TGT and its session key encoded as a "ccache" file contents. .Pp Authentication is required. @@ -239,13 +393,14 @@ same as for by the authenticated client principal to get a certificate with a PKINIT SAN for itself or the requested principal if a .Va cname -query parameter was included. +request parameter was included. .Pp Unauthorized requests will elicit a 403 response. .Pp -Requested IP addresses will be added to the issued TGT if allowed. -The IP address of the client will be included if address-less TGTs -are not allowed. +Requested IP addresses will be added to the issued TGT if +allowed. +The IP address of the client will be included if address-less +TGTs are not allowed. See the .Va [get-tgt] section of @@ -257,6 +412,48 @@ end-point, but as configured in the .Va [get-tgt] section of .Xr krb5.conf 5 . +.Sh BATCH TGT HTTP API +Some sites may have special users that operate batch jobs systems +and that can impersonate many others by obtaining TGTs for them, +and which +.Dq prestash +credentials for those users in their credentials caches. +To support these sytems, a +.Ar GET +of +.Ar /get-tgts +with multiple +.Ar cname +request parameters will return those principals' TGTs (if the +caller is authorized). +.Pp +This is similar to the +.Ar /get-tgt +end-point, but a) multiple +.Ar cname +request parameter values may be given, and b) the caller's +principal name is not used as a default for the +.Ar cname +request parameter. +The +.Ar address +and +.Ar lifetime +request parameters are honored. +.Pp +For successful +.Ar GETs +the response body is a sequence of JSON texts each of which is a +JSON object with two keys: +.Bl -tag -width Ds -offset indent +.It Ar ccache +with a base64-encoded FILE-type ccache; +.It Ar name +the name of the principal whose credentials are in that ccache. +.El +.Sh NOTES +A future release may split all these end-points into separate +services. .Sh ENVIRONMENT .Bl -tag -width Ds .It Ev KRB5_CONFIG diff --git a/kdc/bx509d.c b/kdc/bx509d.c index 064c424b7..4d1b694a9 100644 --- a/kdc/bx509d.c +++ b/kdc/bx509d.c @@ -33,32 +33,19 @@ /* * This file implements a RESTful HTTPS API to an online CA, as well as an - * HTTP/Negotiate token issuer. + * HTTP/Negotiate token issuer, as well as a way to get TGTs. * - * Users are authenticated with bearer tokens. + * Users are authenticated with Negotiate and/or Bearer. * - * This is essentially a RESTful online CA sharing code with the KDC's kx509 - * online CA, and also a proxy for PKINIT and GSS-API (Negotiate). + * This is essentially a RESTful online CA sharing some code with the KDC's + * kx509 online CA, and also a proxy for PKINIT and GSS-API (Negotiate). * - * To get a key certified: - * - * GET /bx509?csr= - * - * To get an HTTP/Negotiate token: - * - * GET /bnegotiate?target= - * - * which, if authorized, produces a Negotiate token (base64-encoded, as - * expected, with the "Negotiate " prefix, ready to be put in an Authorization: - * header). + * See the manual page for HTTP API details. * * TBD: * - rewrite to not use libmicrohttpd but an alternative more appropriate to * Heimdal's license (though libmicrohttpd will do) - * - /bx509 should include the certificate chain - * - /bx509 should support HTTP/Negotiate * - there should be an end-point for fetching an issuer's chain - * - maybe add /bkrb5 which returns a KRB-CRED with the user's TGT * * NOTES: * - We use krb5_error_code values as much as possible. Where we need to use @@ -69,6 +56,49 @@ * (MHD_NO is an ENOMEM-cannot-even-make-a-static-503-response level event.) */ +/* + * Theory of operation: + * + * - We use libmicrohttpd (MHD) for the HTTP(S) implementation. + * + * - MHD has an online request processing model: + * + * - all requests are handled via the `dh' and `dh_cls' closure arguments + * of `MHD_start_daemon()'; ours is called `route()' + * + * - `dh' is called N+1 times: + * - once to allocate a request context + * - once for every N chunks of request body + * - once to process the request and produce a response + * + * - the response cannot begin to be produced before consuming the whole + * request body (for requests that have a body) + * (this seems like a bug in MHD) + * + * - the response body can be produced over multiple calls (i.e., in an + * online manner) + * + * - Our `route()' processes any POST request body form data / multipart by + * treating all the key/value pairs as if they had been additional URI query + * parameters. + * + * - Then `route()' calls a handler appropriate to the URI local-part with the + * request context, and the handler produces a response in one call. + * + * I.e., we turn the online MHD request processing into not-online. Our + * handlers are presented with complete requests and must produce complete + * responses in one call. + * + * - `route()' also does any authentication and CSRF protection so that the + * request handlers don't have to. + * + * This non-online request handling approach works for most everything we want + * to do. However, for /get-tgts with very large numbers of principals, we + * might have to revisit this, using MHD_create_response_from_callback() or + * MHD_create_response_from_pipe() (and a thread to do the actual work of + * producing the body) instead of MHD_create_response_from_buffer(). + */ + #define _XOPEN_SOURCE_EXTENDED 1 #define _DEFAULT_SOURCE 1 #define _BSD_SOURCE 1 @@ -128,20 +158,40 @@ typedef enum MHD_Result heim_mhd_result; enum k5_creds_kind { K5_CREDS_EPHEMERAL, K5_CREDS_CACHED }; +/* + * This is to keep track of memory we need to free, mainly because we had to + * duplicate data from the MHD POST form data processor. + */ +struct free_tend_list { + void *freeme1; + void *freeme2; + struct free_tend_list *next; +}; + +/* Per-request context data structure */ typedef struct bx509_request_desc { + /* Common elements for Heimdal request/response services */ HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; struct MHD_Connection *connection; + struct MHD_PostProcessor *pp; + struct MHD_Response *response; krb5_times token_times; time_t req_life; hx509_request req; + struct free_tend_list *free_list; const char *for_cname; const char *target; const char *redir; + const char *method; + size_t post_data_size; enum k5_creds_kind cckind; char *pkix_store; + char *tgts_filename; + FILE *tgts; char *ccname; char *freeme1; + char *csrf_token; krb5_addresses tgt_addresses; /* For /get-tgt */ char frombuf[128]; } *bx509_request_desc; @@ -214,7 +264,17 @@ get_krb5_context(krb5_context *contextp) return *contextp ? 0 : ENOMEM; } +typedef enum { + CSRF_PROT_UNSPEC = 0, + CSRF_PROT_GET_WITH_HEADER = 1, + CSRF_PROT_GET_WITH_TOKEN = 2, + CSRF_PROT_POST_WITH_HEADER = 8, + CSRF_PROT_POST_WITH_TOKEN = 16, +} csrf_protection_type; + +static csrf_protection_type csrf_prot_type = CSRF_PROT_UNSPEC; static int port = -1; +static int allow_GET_flag = -1; static int help_flag; static int daemonize; static int daemon_child_fd = -1; @@ -223,11 +283,16 @@ static int version_flag; static int reverse_proxied_flag; static int thread_per_client_flag; struct getarg_strings audiences; +static getarg_strings csrf_prot_type_strs; +static const char *csrf_header = "X-CSRF"; static const char *cert_file; static const char *priv_key_file; static const char *cache_dir; +static const char *csrf_key_file; static char *impersonation_key_fn; +static char csrf_key[16]; + static krb5_error_code resp(struct bx509_request_desc *, int, enum MHD_ResponseMemoryMode, const char *, const void *, size_t, const char *); @@ -243,6 +308,7 @@ static krb5_error_code bad_404(struct bx509_request_desc *, const char *); static krb5_error_code bad_405(struct bx509_request_desc *, const char *); static krb5_error_code bad_500(struct bx509_request_desc *, krb5_error_code, const char *); static krb5_error_code bad_503(struct bx509_request_desc *, krb5_error_code, const char *); +static heim_mhd_result validate_csrf_token(struct bx509_request_desc *r); static int validate_token(struct bx509_request_desc *r) @@ -409,16 +475,20 @@ mk_pkix_store(char **pkix_store) int ret = ENOMEM; int fd; + if (*pkix_store) { + const char *fn = strchr(*pkix_store, ':'); + + fn = fn ? fn + 1 : *pkix_store; + (void) unlink(fn); + } + + free(*pkix_store); *pkix_store = NULL; if (asprintf(&s, "PEM-FILE:%s/pkix-XXXXXX", cache_dir) == -1 || s == NULL) { free(s); return ret; } - /* - * This way of using mkstemp() isn't safer than mktemp(), but we want to - * quiet the warning that we'd get if we used mktemp(). - */ if ((fd = mkstemp(s + sizeof("PEM-FILE:") - 1)) == -1) { free(s); return errno; @@ -428,11 +498,6 @@ mk_pkix_store(char **pkix_store) return 0; } -/* - * XXX Shouldn't be a body, but a status message. The body should be - * configurable to be from a file. MHD doesn't give us a way to set the - * response status message though, just the body. - */ static krb5_error_code resp(struct bx509_request_desc *r, int http_status_code, @@ -442,26 +507,31 @@ resp(struct bx509_request_desc *r, size_t bodylen, const char *token) { - struct MHD_Response *response; int mret = MHD_YES; + if (r->response) + return MHD_YES; + (void) gettimeofday(&r->tv_end, NULL); if (http_status_code == MHD_HTTP_OK || http_status_code == MHD_HTTP_TEMPORARY_REDIRECT) audit_trail(r, 0); - response = MHD_create_response_from_buffer(bodylen, rk_UNCONST(body), - rmmode); - if (response == NULL) + r->response = MHD_create_response_from_buffer(bodylen, rk_UNCONST(body), + rmmode); + if (r->response == NULL) return -1; - mret = MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, - "no-store, max-age=0"); + if (r->csrf_token) + mret = MHD_add_response_header(r->response, "X-CSRF-Token", r->csrf_token); + if (mret == MHD_YES) + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_CACHE_CONTROL, + "no-store, max-age=0"); if (mret == MHD_YES && http_status_code == MHD_HTTP_UNAUTHORIZED) { - mret = MHD_add_response_header(response, + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer"); if (mret == MHD_YES) - mret = MHD_add_response_header(response, + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Negotiate"); } else if (mret == MHD_YES && http_status_code == MHD_HTTP_TEMPORARY_REDIRECT) { @@ -470,21 +540,21 @@ resp(struct bx509_request_desc *r, /* XXX Move this */ redir = MHD_lookup_connection_value(r->connection, MHD_GET_ARGUMENT_KIND, "redirect"); - mret = MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_LOCATION, redir); if (mret != MHD_NO && token) - mret = MHD_add_response_header(response, + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_AUTHORIZATION, token); } if (mret == MHD_YES && content_type) { - mret = MHD_add_response_header(response, + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_CONTENT_TYPE, content_type); } if (mret == MHD_YES) - mret = MHD_queue_response(r->connection, http_status_code, response); - MHD_destroy_response(response); + mret = MHD_queue_response(r->connection, http_status_code, r->response); + MHD_destroy_response(r->response); return mret == MHD_NO ? -1 : 0; } @@ -520,7 +590,7 @@ bad_reqv(struct bx509_request_desc *r, emsg = strerror(code); } - ret = vasprintf(&formatted, fmt, ap) == -1; + ret = vasprintf(&formatted, fmt, ap); if (code) { if (ret > -1 && formatted) ret = asprintf(&msg, "%s: %s (%d)", formatted, emsg, (int)code); @@ -601,6 +671,13 @@ bad_405(struct bx509_request_desc *r, const char *method) "Method not supported: %s", method); } +static krb5_error_code +bad_413(struct bx509_request_desc *r) +{ + return bad_req(r, E2BIG, MHD_HTTP_METHOD_NOT_ALLOWED, + "POST request body too large"); +} + static krb5_error_code bad_500(struct bx509_request_desc *r, krb5_error_code ret, @@ -871,20 +948,28 @@ addr_to_string(krb5_context context, snprintf(str, len, "", addr->sa_family); } +static void clean_req_desc(struct bx509_request_desc *); + static krb5_error_code set_req_desc(struct MHD_Connection *connection, + const char *method, const char *url, - struct bx509_request_desc *r) + struct bx509_request_desc **rp) { + struct bx509_request_desc *r; const union MHD_ConnectionInfo *ci; const char *token; krb5_error_code ret; - memset(r, 0, sizeof(*r)); + *rp = NULL; + if ((r = calloc(1, sizeof(*r))) == NULL) + return ENOMEM; (void) gettimeofday(&r->tv_start, NULL); ret = get_krb5_context(&r->context); r->connection = connection; + r->response = NULL; + r->pp = NULL; r->request.data = ""; r->request.length = sizeof(""); r->from = r->frombuf; @@ -893,12 +978,17 @@ set_req_desc(struct MHD_Connection *connection, r->hcontext = r->context ? r->context->hcontext : NULL; r->config = NULL; r->logf = logfac; + r->csrf_token = NULL; + r->free_list = NULL; + r->method = method; r->reqtype = url; r->target = r->redir = NULL; r->pkix_store = NULL; r->for_cname = NULL; r->freeme1 = NULL; r->reason = NULL; + r->tgts_filename = NULL; + r->tgts = NULL; r->ccname = NULL; r->reply = NULL; r->sname = NULL; @@ -934,6 +1024,10 @@ set_req_desc(struct MHD_Connection *connection, } + if (ret == 0) + *rp = r; + else + clean_req_desc(r); return ret; } @@ -942,6 +1036,13 @@ clean_req_desc(struct bx509_request_desc *r) { if (!r) return; + while (r->free_list) { + struct free_tend_list *ftl = r->free_list; + r->free_list = r->free_list->next; + free(ftl->freeme1); + free(ftl->freeme2); + free(ftl); + } if (r->pkix_store) { const char *fn = strchr(r->pkix_store, ':'); @@ -955,6 +1056,7 @@ clean_req_desc(struct bx509_request_desc *r) } krb5_free_addresses(r->context, &r->tgt_addresses); hx509_request_free(&r->req); + heim_release(r->attributes); heim_release(r->reason); heim_release(r->kv); if (r->ccname && r->cckind == K5_CREDS_EPHEMERAL) { @@ -964,11 +1066,22 @@ clean_req_desc(struct bx509_request_desc *r) fn += sizeof("FILE:") - 1; (void) unlink(fn); } + if (r->tgts) + (void) fclose(r->tgts); + if (r->tgts_filename) { + (void) unlink(r->tgts_filename); + free(r->tgts_filename); + } + /* No need to destroy r->response */ + if (r->pp) + MHD_destroy_post_processor(r->pp); + free(r->csrf_token); free(r->pkix_store); free(r->freeme1); free(r->ccname); free(r->cname); free(r->sname); + free(r); } /* Implements GETs of /bx509 */ @@ -984,9 +1097,6 @@ bx509(struct bx509_request_desc *r) if (csr == NULL) return bad_400(r, EINVAL, "CSR is missing"); - if ((ret = validate_token(r))) - return ret; /* validate_token() calls bad_req() */ - if (r->cname == NULL) return bad_403(r, EINVAL, "Could not extract principal name from token"); @@ -1424,9 +1534,8 @@ k5_get_creds(struct bx509_request_desc *r, enum k5_creds_kind kind) if ((ret = k5_do_CA(r))) return ret; /* k5_do_CA() calls bad_req() */ - if (ret == 0 && (ret = do_pkinit(r, kind))) - ret = bad_403(r, ret, - "Could not acquire Kerberos credentials using PKINIT"); + if (ret == 0) + ret = do_pkinit(r, kind); return ret; } @@ -1682,15 +1791,11 @@ bnegotiate(struct bx509_request_desc *r) char *nego_tok = NULL; ret = bnegotiate_get_target(r); - if (ret == 0) { - heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "target", "%s", - r->target ? r->target : ""); - heim_audit_setkv_bool((heim_svc_req_desc)r, "redir", !!r->redir); - ret = validate_token(r); - } - /* bnegotiate_get_target() and validate_token() call bad_req() */ if (ret) - return ret; + return ret; /* bnegotiate_get_target() calls bad_req() */ + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "target", "%s", + r->target ? r->target : ""); + heim_audit_setkv_bool((heim_svc_req_desc)r, "redir", !!r->redir); /* * Make sure we have Kerberos credentials for cprinc. If we have them @@ -1702,7 +1807,8 @@ bnegotiate(struct bx509_request_desc *r) */ ret = k5_get_creds(r, K5_CREDS_CACHED); if (ret) - return ret; + return bad_403(r, ret, + "Could not acquire Kerberos credentials using PKINIT"); /* Acquire the Negotiate token and output it */ if (ret == 0 && r->ccname != NULL) @@ -1795,10 +1901,17 @@ get_tgt_param_cb(void *d, /* * Implements /get-tgt end-point. * - * Query parameters (mutually exclusive): + * Query parameters: * * - cname= (client principal name, if not the same as the authenticated - * name, then this will be impersonated if allowed) + * name, then this will be impersonated if allowed; may be + * given only once) + * + * - address= (IP address to add as a ticket address; may be given + * multiple times) + * + * - lifetime=