diff options
author | Simo Sorce <simo@redhat.com> | 2012-02-23 17:57:58 -0500 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2012-04-05 11:20:33 -0400 |
commit | 34d8ca04e148263ffd4860718652eb474087f848 (patch) | |
tree | 10af3408150ec6dc1515d88f94c63afccec3245d /proxy/src | |
parent | 99d24402236ab621f8c03fdba49e7a75e38263a5 (diff) | |
download | gss-proxy-34d8ca04e148263ffd4860718652eb474087f848.tar.gz gss-proxy-34d8ca04e148263ffd4860718652eb474087f848.tar.xz gss-proxy-34d8ca04e148263ffd4860718652eb474087f848.zip |
creds: add code to import krb5 credentials based on configuration.
Diffstat (limited to 'proxy/src')
-rw-r--r-- | proxy/src/gp_conv.c | 2 | ||||
-rw-r--r-- | proxy/src/gp_creds.c | 304 | ||||
-rw-r--r-- | proxy/src/gp_creds.h | 44 | ||||
-rw-r--r-- | proxy/src/gp_proxy.h | 6 | ||||
-rw-r--r-- | proxy/src/gp_rpc_accept_sec_context.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_acquire_cred.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_creds.h | 50 | ||||
-rw-r--r-- | proxy/src/gp_rpc_import_and_canon_name.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_indicate_mechs.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_init_sec_context.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_rpc_process.c | 8 | ||||
-rw-r--r-- | proxy/src/gp_rpc_process.h | 3 | ||||
-rw-r--r-- | proxy/src/gp_rpc_release_handle.c | 1 | ||||
-rw-r--r-- | proxy/src/gp_socket.c | 15 | ||||
-rw-r--r-- | proxy/src/gp_workers.c | 10 |
15 files changed, 433 insertions, 15 deletions
diff --git a/proxy/src/gp_conv.c b/proxy/src/gp_conv.c index e568f5e..d87a45b 100644 --- a/proxy/src/gp_conv.c +++ b/proxy/src/gp_conv.c @@ -801,5 +801,3 @@ int gp_copy_gssx_name_alloc(gssx_name *in, gssx_name **out) *out = o; return 0; } - - diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c new file mode 100644 index 0000000..f205a68 --- /dev/null +++ b/proxy/src/gp_creds.c @@ -0,0 +1,304 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "config.h" +#include <stdio.h> +#include <sys/socket.h> +#include <errno.h> +#include <pwd.h> +#include <krb5/krb5.h> +#include <gssapi/gssapi_krb5.h> +#include "gp_proxy.h" +#include "gp_rpc_creds.h" +#include "gp_creds.h" + +#define GSS_MECH_KRB5_OID_LENGTH 9 +#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002" + +gss_OID_desc gp_mech_krb5 = { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID }; + +struct supported_mechs_map { + int internal_id; + const gss_OID mech; +} supported_mechs_map[] = { + { GP_CRED_KRB5, &gp_mech_krb5 }, + { 0, NULL } +}; + +bool gp_creds_allowed_mech(struct gp_service *svc, gss_OID desired_mech) +{ + int i; + + for (i = 0; supported_mechs_map[i].internal_id != 0; i++) { + if (svc->mechs & supported_mechs_map[i].internal_id) { + if (gss_oid_equal(desired_mech, supported_mechs_map[i].mech)) { + return true; + } + } + } + + return false; +} + +uint32_t gp_get_supported_mechs(uint32_t *min, + struct gp_service *svc, gss_OID_set *set) +{ + uint32_t ret_maj; + uint32_t ret_min; + int i; + + ret_maj = gss_create_empty_oid_set(&ret_min, set); + if (ret_maj) { + *min = ret_min; + return ret_maj; + } + + for (i = 0; supported_mechs_map[i].internal_id != 0; i++) { + ret_maj = gss_add_oid_set_member(&ret_min, + supported_mechs_map[i].mech, set); + if (ret_maj) { + *min = ret_min; + gss_release_oid_set(&ret_min, set); + return ret_maj; + } + } + + *min = 0; + return GSS_S_COMPLETE; +} + +struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx, + struct gp_conn *conn) +{ + struct gp_creds *gcs; + int i; + + gcs = gp_conn_get_creds(conn); + + for (i = 0; i < gpctx->config->num_svcs; i++) { + if (gpctx->config->svcs[i]->euid == gcs->ucred.uid) { + return gpctx->config->svcs[i]; + } + } + + return NULL; +} + +static char *gp_get_ccache_name(struct gp_service *svc, + gss_name_t desired_name) +{ + char buffer[2048]; + struct passwd pwd, *res = NULL; + char *ccache; + char *tmp; + char *p; + int ret; + + if (svc->krb5.ccache == NULL) { + ret = getpwuid_r(svc->euid, &pwd, buffer, 2048, &res); + if (ret || !res) { + return NULL; + } + + ret = asprintf(&ccache, "%s/krb5cc_%s", CCACHE_PATH, pwd.pw_name); + if (ret == -1) { + return NULL; + } + + return ccache; + } + + ccache = strdup(svc->krb5.ccache); + if (!ccache) { + return NULL; + } + + p = ccache; + while ((p = strchr(p, '%')) != NULL) { + p++; + switch (*p) { + case '%': + p++; + continue; + case 'u': + if (!res) { + ret = getpwuid_r(svc->euid, &pwd, buffer, 2048, &res); + if (ret || !res) { + free(ccache); + return NULL; + } + } + ret = asprintf(&tmp, "%.*s%s%s", + (int)(p - ccache - 1), ccache, pwd.pw_name, p + 1); + if (ret == -1) { + free(ccache); + return NULL; + } + p = p - ccache + tmp; + free(ccache); + ccache = tmp; + break; + default: + p++; + continue; + } + } + + return ccache; +} + +uint32_t gp_add_krb5_creds(uint32_t *min, + struct gp_service *svc, + gss_cred_id_t in_cred, + gss_name_t desired_name, + gss_cred_usage_t cred_usage, + uint32_t initiator_time_req, + uint32_t acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + uint32_t *initiator_time_rec, + uint32_t *acceptor_time_rec) +{ + char *ccache_name; + krb5_context kctx; + krb5_principal principal = NULL; + krb5_keytab keytab = NULL; + krb5_ccache ccache = NULL; + krb5_error_code kerr; + uint32_t ret_maj = 0; + uint32_t ret_min = 0; + uint32_t discard; + + if (!min || !output_cred_handle) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + *min = 0; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs) { + *actual_mechs = GSS_C_NO_OID_SET; + } + + if (in_cred != GSS_C_NO_CREDENTIAL) { + /* we can't yet handle adding to an existing credential due to + * the way gss_krb5_import_cred works. This limitation should + * be removed by adding a gssapi extension that superceedes this + * function completely */ + return GSS_S_CRED_UNAVAIL; + } + + kerr = krb5_init_context(&kctx); + if (kerr != 0) { + *min = kerr; + return GSS_S_FAILURE; + } + + if (cred_usage == GSS_C_ACCEPT && svc->krb5.keytab == NULL) { + ret_maj = GSS_S_CRED_UNAVAIL; + goto done; + } + + if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) { + ccache_name = gp_get_ccache_name(svc, desired_name); + if (!ccache_name) { + ret_maj = GSS_S_CRED_UNAVAIL; + goto done; + } + + kerr = krb5_cc_resolve(kctx, ccache_name, &ccache); + if (kerr) { + ret_maj = GSS_S_FAILURE; + ret_min = kerr; + goto done; + } + + /* FIXME: initiate ? */ + } + + if (desired_name) { + /* FIXME: resolve principal name */ + } + + if (svc->krb5.keytab) { + kerr = krb5_kt_resolve(kctx, svc->krb5.keytab, &keytab); + if (kerr != 0) { + ret_maj = GSS_S_FAILURE; + ret_min = kerr; + goto done; + } + } + + ret_maj = gss_krb5_import_cred(&ret_min, + ccache, principal, keytab, + output_cred_handle); + if (ret_maj) { + goto done; + } + + if (actual_mechs) { + ret_maj = gss_create_empty_oid_set(&ret_min, actual_mechs); + if (ret_maj) { + goto done; + } + ret_maj = gss_add_oid_set_member(&ret_min, + &gp_mech_krb5, actual_mechs); + if (ret_maj) { + goto done; + } + } + + if (initiator_time_rec || acceptor_time_rec) { + ret_maj = gss_inquire_cred_by_mech(&ret_min, + *output_cred_handle, + &gp_mech_krb5, + NULL, + initiator_time_rec, + acceptor_time_rec, + NULL); + if (ret_maj) { + goto done; + } + } + +done: + if (ret_maj) { + if (*output_cred_handle) { + gss_release_cred(&discard, output_cred_handle); + } + if (actual_mechs && *actual_mechs) { + gss_release_oid_set(&discard, actual_mechs); + } + } + *min = ret_min; + if (ccache) { + krb5_cc_close(kctx, ccache); + } + if (keytab) { + krb5_kt_close(kctx, keytab); + } + + krb5_free_context(kctx); + return ret_maj; +} diff --git a/proxy/src/gp_creds.h b/proxy/src/gp_creds.h new file mode 100644 index 0000000..8858a8c --- /dev/null +++ b/proxy/src/gp_creds.h @@ -0,0 +1,44 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _GP_CREDS_H_ +#define _GP_CREDS_H_ + +#include "config.h" +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> +#include <gssapi/gssapi.h> + +#define CRED_TYPE_NONE 0x00 +#define CRED_TYPE_UNIX 0x01 +#define CRED_TYPE_SELINUX 0x02 + +struct gp_creds { + int type; + struct ucred ucred; +}; + +#endif /* _GP_CREDS_H_ */ diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h index cebde03..bffcac1 100644 --- a/proxy/src/gp_proxy.h +++ b/proxy/src/gp_proxy.h @@ -85,6 +85,7 @@ void accept_sock_conn(verto_ctx *vctx, verto_ev *ev); void gp_conn_free(struct gp_conn *conn); void gp_socket_send_data(verto_ctx *vctx, struct gp_conn *conn, uint8_t *buffer, size_t buflen); +struct gp_creds *gp_conn_get_creds(struct gp_conn *conn); /* from gp_workers.c */ int gp_workers_init(struct gssproxy_ctx *gpctx); @@ -94,7 +95,12 @@ int gp_query_new(struct gp_workers *w, struct gp_conn *conn, /* from gp_rpc.c */ int gp_rpc_process_call(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, uint8_t *inbuf, size_t inlen, uint8_t **outbuf, size_t *outlen); +/* from gp_creds.c */ +struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx, + struct gp_conn *conn); + #endif /* _GP_PROXY_H_ */ diff --git a/proxy/src/gp_rpc_accept_sec_context.c b/proxy/src/gp_rpc_accept_sec_context.c index 96c781b..ec5835a 100644 --- a/proxy/src/gp_rpc_accept_sec_context.c +++ b/proxy/src/gp_rpc_accept_sec_context.c @@ -26,6 +26,7 @@ #include "gp_rpc_process.h" int gp_accept_sec_context(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_rpc_acquire_cred.c b/proxy/src/gp_rpc_acquire_cred.c index 4649e0e..611bfe6 100644 --- a/proxy/src/gp_rpc_acquire_cred.c +++ b/proxy/src/gp_rpc_acquire_cred.c @@ -26,6 +26,7 @@ #include "gp_rpc_process.h" int gp_acquire_cred(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_rpc_creds.h b/proxy/src/gp_rpc_creds.h new file mode 100644 index 0000000..2c0aea5 --- /dev/null +++ b/proxy/src/gp_rpc_creds.h @@ -0,0 +1,50 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _GP_RPC_CREDS_H_ +#define _GP_RPC_CREDS_H_ + +#include "config.h" +#include <stdint.h> +#include <gssapi/gssapi.h> + +struct gp_service; + +bool gp_creds_allowed_mech(struct gp_service *svc, gss_OID desired_mech); +uint32_t gp_get_supported_mechs(uint32_t *min, + struct gp_service *svc, gss_OID_set *set); + +uint32_t gp_add_krb5_creds(uint32_t *min, + struct gp_service *svc, + gss_cred_id_t in_cred, + gss_name_t desired_name, + gss_cred_usage_t cred_usage, + uint32_t initiator_time_req, + uint32_t acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + uint32_t *initiator_time_rec, + uint32_t *acceptor_time_rec); +#endif /* _GP_RPC_CREDS_H_ */ diff --git a/proxy/src/gp_rpc_import_and_canon_name.c b/proxy/src/gp_rpc_import_and_canon_name.c index 559373c..ba2bc06 100644 --- a/proxy/src/gp_rpc_import_and_canon_name.c +++ b/proxy/src/gp_rpc_import_and_canon_name.c @@ -32,6 +32,7 @@ * touch this function */ int gp_import_and_canon_name(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_rpc_indicate_mechs.c b/proxy/src/gp_rpc_indicate_mechs.c index b0fb2c5..c85243b 100644 --- a/proxy/src/gp_rpc_indicate_mechs.c +++ b/proxy/src/gp_rpc_indicate_mechs.c @@ -27,6 +27,7 @@ #include "gp_debug.h" int gp_indicate_mechs(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_rpc_init_sec_context.c b/proxy/src/gp_rpc_init_sec_context.c index c8f7f82..d1afe39 100644 --- a/proxy/src/gp_rpc_init_sec_context.c +++ b/proxy/src/gp_rpc_init_sec_context.c @@ -26,6 +26,7 @@ #include "gp_rpc_process.h" int gp_init_sec_context(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_rpc_process.c b/proxy/src/gp_rpc_process.c index da4ea57..1742320 100644 --- a/proxy/src/gp_rpc_process.c +++ b/proxy/src/gp_rpc_process.c @@ -289,10 +289,11 @@ static int gp_rpc_encode_reply(XDR *xdr_reply_ctx, return 0; } -static int gp_rpc_execute(struct gssproxy_ctx *gpctx, uint32_t proc, +static int gp_rpc_execute(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, uint32_t proc, union gp_rpc_arg *arg, union gp_rpc_res *res) { - return gp_xdr_set[proc].exec_fn(gpctx, arg, res); + return gp_xdr_set[proc].exec_fn(gpctx, gpsvc, arg, res); } static int gp_rpc_return_buffer(XDR *xdr_reply_ctx, char *reply_buffer, @@ -324,6 +325,7 @@ static void gp_rpc_free_xdrs(int proc, } int gp_rpc_process_call(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, uint8_t *inbuf, size_t inlen, uint8_t **outbuf, size_t *outlen) { @@ -349,7 +351,7 @@ int gp_rpc_process_call(struct gssproxy_ctx *gpctx, ret = gp_rpc_decode_call(&xdr_call_ctx, &xid, &proc, &arg, &acc, &rej); if (!ret) { /* execute request */ - ret = gp_rpc_execute(gpctx, proc, &arg, &res); + ret = gp_rpc_execute(gpctx, gpsvc, proc, &arg, &res); if (ret) { acc = GP_RPC_SYSTEM_ERR; ret = EINVAL; diff --git a/proxy/src/gp_rpc_process.h b/proxy/src/gp_rpc_process.h index a81b066..e85cff6 100644 --- a/proxy/src/gp_rpc_process.h +++ b/proxy/src/gp_rpc_process.h @@ -36,10 +36,13 @@ #include "gp_export.h" #include "rpcgen/gss_proxy.h" #include "rpcgen/gp_rpc.h" +#include "gp_rpc_creds.h" struct gssproxy_ctx; +struct gp_service; #define gp_exec_std_args struct gssproxy_ctx *gpctx, \ + struct gp_service *gpsvc, \ union gp_rpc_arg *arg, \ union gp_rpc_res *res diff --git a/proxy/src/gp_rpc_release_handle.c b/proxy/src/gp_rpc_release_handle.c index 5264cf2..a25458c 100644 --- a/proxy/src/gp_rpc_release_handle.c +++ b/proxy/src/gp_rpc_release_handle.c @@ -26,6 +26,7 @@ #include "gp_rpc_process.h" int gp_release_handle(struct gssproxy_ctx *gpctx, + struct gp_service *gpsvc, union gp_rpc_arg *arg, union gp_rpc_res *res) { diff --git a/proxy/src/gp_socket.c b/proxy/src/gp_socket.c index 01c89fe..e42125c 100644 --- a/proxy/src/gp_socket.c +++ b/proxy/src/gp_socket.c @@ -35,15 +35,7 @@ #include <errno.h> #include <netinet/in.h> #include "gp_proxy.h" - -#define CRED_TYPE_NONE 0x00 -#define CRED_TYPE_UNIX 0x01 -#define CRED_TYPE_SELINUX 0x02 - -struct gp_creds { - int type; - struct ucred ucred; -}; +#include "gp_creds.h" #define FRAGMENT_BIT (1 << 31) @@ -69,6 +61,11 @@ struct gp_buffer { size_t pos; }; +struct gp_creds *gp_conn_get_creds(struct gp_conn *conn) +{ + return &conn->creds; +} + void gp_conn_free(struct gp_conn *conn) { if (conn->us.sd != -1) { diff --git a/proxy/src/gp_workers.c b/proxy/src/gp_workers.c index 1a58136..0e388d6 100644 --- a/proxy/src/gp_workers.c +++ b/proxy/src/gp_workers.c @@ -428,11 +428,19 @@ static void *gp_worker_main(void *pvt) static void gp_handle_query(struct gp_workers *w, struct gp_query *q) { + struct gp_service *gpsvc; uint8_t *buffer; size_t buflen; int ret; - ret = gp_rpc_process_call(w->gpctx, + /* find service */ + gpsvc = gp_creds_match_conn(w->gpctx, q->conn); + if (!gpsvc) { + q->status = GP_QUERY_ERR; + return; + } + + ret = gp_rpc_process_call(w->gpctx, gpsvc, q->buffer, q->buflen, &buffer, &buflen); if (ret) { |