From d6d1af8251432c3528c769b02107c8ee9833fe7e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 1 Sep 2020 18:13:54 +0100 Subject: [PATCH] Add "kafs gssapi aklog" command to do gssapi negotiation for rxgk testing --- kafs/.gitignore | 1 + kafs/Makefile | 19 +- kafs/gssapi_aklog.C | 499 +++++++++++++++++++++++++++++++++++++++++++ kafs/gssapi_help.C | 48 +++++ kafs/kafs.C | 2 + rpc-api/add_key.xg | 56 +++++ rpc-api/rxgk.et | 26 +++ rpc-api/rxgk.xg | 96 +++++++++ rpc-api/yfs.xg | 2 - rpc-api/yfs_common.h | 3 + rpc-api/yfs_rxgk.xg | 201 +++++++++++++++++ 11 files changed, 947 insertions(+), 6 deletions(-) create mode 100644 kafs/gssapi_aklog.C create mode 100644 kafs/gssapi_help.C create mode 100644 rpc-api/add_key.xg create mode 100644 rpc-api/rxgk.et create mode 100644 rpc-api/rxgk.xg create mode 100644 rpc-api/yfs_rxgk.xg diff --git a/kafs/.gitignore b/kafs/.gitignore index 94f131d..8df2ca6 100644 --- a/kafs/.gitignore +++ b/kafs/.gitignore @@ -1,5 +1,6 @@ bos.[CH] fs.[CH] +gssapi.[CH] pts.[CH] vos.[CH] kafs diff --git a/kafs/Makefile b/kafs/Makefile index 2c52d0f..13fa607 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -26,6 +26,11 @@ FS_SRCS := \ fs.C \ fs_help.C +GSSAPI_SRCS := \ + gssapi.C \ + gssapi_aklog.C \ + gssapi_help.C + PTS_SRCS := \ pts.C \ pts_help.C @@ -44,9 +49,10 @@ VOS_SRCS := \ CORE_OBJS := $(patsubst %.C,%.o,$(CORE_SRCS)) BOS_OBJS := $(patsubst %.C,%.o,$(BOS_SRCS)) FS_OBJS := $(patsubst %.C,%.o,$(FS_SRCS)) +GSSAPI_OBJS := $(patsubst %.C,%.o,$(GSSAPI_SRCS)) PTS_OBJS := $(patsubst %.C,%.o,$(PTS_SRCS)) VOS_OBJS := $(patsubst %.C,%.o,$(VOS_SRCS)) -KAFS_OBJS := $(CORE_OBJS) $(BOS_OBJS) $(FS_OBJS) $(PTS_OBJS) $(VOS_OBJS) +KAFS_OBJS := $(CORE_OBJS) $(BOS_OBJS) $(FS_OBJS) $(GSSAPI_OBJS) $(PTS_OBJS) $(VOS_OBJS) all: kafs @@ -56,6 +62,9 @@ bos.C bos.H: gen_command.py $(filter-out bos.C, $(BOS_SRCS)) fs.C fs.H: gen_command.py $(filter-out fs.C, $(FS_SRCS)) ./gen_command.py fs $(filter-out fs.C, $(FS_SRCS)) +gssapi.C gssapi.H: gen_command.py $(filter-out gssapi.C, $(GSSAPI_SRCS)) + ./gen_command.py gssapi $(filter-out gssapi.C, $(GSSAPI_SRCS)) + pts.C pts.H: gen_command.py $(filter-out pts.C, $(PTS_SRCS)) ./gen_command.py pts $(filter-out pts.C, $(PTS_SRCS)) @@ -65,6 +74,7 @@ vos.C vos.H: gen_command.py $(filter-out vos.C, $(VOS_SRCS)) GENFILES := \ bos.C bos.H \ fs.C fs.H \ + gssapi.C gssapi.H \ pts.C pts.H \ vos.C vos.H @@ -74,7 +84,7 @@ DEPS := $(wildcard .*.o.d) ifneq ($(DEPS),) include $(DEPS) else -$(KAFS_OBJS): bos.H fs.H pts.H vos.H +$(KAFS_OBJS): bos.H fs.H gssapi.H pts.H vos.H endif %.o: %.C @@ -83,9 +93,10 @@ endif LIBDIR := ../lib kafs: $(KAFS_OBJS) $(LIBDIR)/libkafs_utils.a - $(CXX) -o $@ $(KAFS_OBJS) -L$(LIBDIR) -lkafs_utils -lkafs_client -luuid -lfmt + $(CXX) -o $@ $(KAFS_OBJS) -L$(LIBDIR) -lkafs_utils -lkafs_client -luuid -lfmt \ + -lgssapi_krb5 -lkeyutils clean: $(RM) *~ *.o $(DEPS) - $(RM) bos.[CH] fs.[CH] pts.[CH] vos.[CH] + $(RM) bos.[CH] fs.[CH] pts.[CH] vos.[CH] gssapi.[CH] $(RM) kafs diff --git a/kafs/gssapi_aklog.C b/kafs/gssapi_aklog.C new file mode 100644 index 0000000..5a43cdf --- /dev/null +++ b/kafs/gssapi_aklog.C @@ -0,0 +1,499 @@ +/* GSSAPI-based aklog + * + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +extern "C" { +#define private foo +#include +#undef private +} +#include "kafs.H" +#include "afs_xg.H" +#include "vlservice.H" + +using rxrpc::ref; +using kafs::afs::RXGK_StartParams; +using kafs::afs::RXGK_ClientInfo; + +static bool debug_gss = true; + +#define verbose_gss(FMT, ...) \ + do { if (a_verbose) fmt::print("GSSAPI: " FMT, ## __VA_ARGS__); } while (0) +#define debug_gss(FMT, ...) \ + do { if (debug_gss) fmt::print("GSSAPI: " FMT, ## __VA_ARGS__); } while (0) + +struct rxgk_nonce { + unsigned int nonce[kafs::afs::RXGK_NONCE_SIZE / sizeof(unsigned int)]; + + void set() { + for (size_t i = 0; + i < sizeof(nonce) / sizeof(unsigned int); + i += sizeof(unsigned int)) + nonce[i] = random(); + } + + size_t size() const { return sizeof(nonce); } +}; + +static size_t rxgk_get_enc_len(RXGK_ClientInfo &client_info) +{ + switch (client_info.enctype) { + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: return 128 / 8; + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: return 256 / 8; + case ENCTYPE_AES128_CTS_HMAC_SHA256_128: return 128 / 8; + case ENCTYPE_AES256_CTS_HMAC_SHA384_192: return 256 / 8; + case ENCTYPE_CAMELLIA128_CTS_CMAC: return 128 / 8; + case ENCTYPE_CAMELLIA256_CTS_CMAC: return 128 / 8; + default: + throw std::runtime_error( + fmt::format("GSSAPI Unknown enctype {}", client_info.enctype)); + } +} + +static void throw_error(const std::string &what, OM_uint32 major, OM_uint32 minor) +{ + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + OM_uint32 ret_minor, mc; + + debug_gss("{} -> maj={:x} min={:x})\n", what, major, minor); + + if (GSS_ERROR(major)) { + gss_display_status(&ret_minor, minor, GSS_C_MECH_CODE, GSS_C_NO_OID, + &mc, &buf); + std::string msg((const char *)buf.value, buf.length); + + throw std::runtime_error( + fmt::format("GSSAPI {}: {} [{:d},{:d}]", + what, msg, major, minor)); + } +} + +/* + * Invoke RxGK negotiation on the RxGK server. + */ +static void rxgk_negotiate(rxrpc::Call_params &gss_params, + RXGK_StartParams &client_start, + gss_buffer_desc &input_token, + gss_buffer_desc &output_token, + rxrpc::Opaque &opaque_cache, + rxrpc::Opaque &_rxgk_info, + bool a_verbose) +{ + rxrpc::Opaque input_token_buffer; + rxrpc::Opaque output_token_buffer; + rxrpc::Opaque opaque_out; + + uint32_t gss_major_status; + uint32_t gss_minor_status; + rxrpc::Opaque rxgk_info; + + debug_gss("-> GSSNegotiate()\n"); + + input_token_buffer.buffer_size = input_token.length; + input_token_buffer.buffer = input_token.value; + + debug_gss("input token {}\n", input_token_buffer.size()); + debug_gss("input opaque {}\n", opaque_cache.size()); + + verbose_gss("Invoke RXGK::GSSNegotiate()\n"); + + kafs::afs::YFSRXGK::GSSNegotiate(&gss_params, + client_start, input_token_buffer, opaque_cache, + output_token_buffer, opaque_out, + gss_major_status, gss_minor_status, rxgk_info); + + debug_gss("GSSNegotiate() -> maj={:x} min={:x}\n", gss_major_status, gss_minor_status); + debug_gss("output token {}\n", output_token_buffer.size()); + debug_gss("output opaque {}\n", opaque_out.size()); + debug_gss("output info {}\n", rxgk_info.size()); + + output_token.value = output_token_buffer.buffer; + output_token.length = output_token_buffer.size(); + output_token_buffer.del_buffer = false; + + if (opaque_cache.del_buffer) + free(opaque_cache.buffer); + opaque_cache = opaque_cache; + opaque_out.del_buffer = false; + + if (_rxgk_info.del_buffer) + free(_rxgk_info.buffer); + _rxgk_info = rxgk_info; + rxgk_info.del_buffer = false; +} + +/* + * Unwrap the RxGK client information. + */ +static void rxgk_unwrap(gss_ctx_id_t &gssctx, rxrpc::Opaque &rxgk_info, + RXGK_ClientInfo &client_info) +{ + gss_buffer_desc wrapping = GSS_C_EMPTY_BUFFER; + gss_buffer_desc info = GSS_C_EMPTY_BUFFER; + gss_qop_t qop_state; + OM_uint32 major, minor; + int conf_state; + + wrapping.length = rxgk_info.size(); + wrapping.value = rxgk_info.buffer; + + debug_gss("rxgk_info: {}\n", rxgk_info.size()); + major = gss_unwrap(&minor, gssctx, &wrapping, &info, &conf_state, &qop_state); + if (GSS_ERROR(major)) + throw_error("gss_unwrap()", major, minor); + + debug_gss("unwrapped: {}\n", info.length); + + rxrpc::Rx_queue rxq("RXGK::GSSNegotiate"); + rxq.client_side = true; + rxq.dec_amount = info.length; + + rxrpc::Rx_buffer buf; + buf.buf = (unsigned char *)info.value; + buf.len = info.length; + buf.no_delete = true; + rxq.dec_buffers.push_back(buf); + + kafs::afs::xdr::decode_RXGK_ClientInfo(rxq, client_info); + + debug_gss("error : {}\n", client_info.errorcode); + debug_gss("enctype : {}\n", client_info.enctype); + debug_gss("level : {}\n", client_info.level); + debug_gss("lifetime: {}\n", client_info.lifetime); + debug_gss("bytelife: {}\n", client_info.bytelife); + debug_gss("expire : {}\n", client_info.expiration); + debug_gss("mic : size={}\n", client_info.mic.size()); + debug_gss("token : size={}\n", client_info.token.size()); + debug_gss("s-nonce : size={}\n", client_info.server_nonce.size()); +} + +/* + * Check the MIC on the last GSSNegotiate call. + */ +static void rxgk_check_mic(gss_ctx_id_t &gssctx, + RXGK_StartParams &rxgk_params, + RXGK_ClientInfo &client_info, + bool a_verbose) +{ + gss_qop_t qop_state; + OM_uint32 major, minor; + + rxrpc::Resv resv = { .max_ioc = 1, .flat = true }; + kafs::afs::xdr::reserve_RXGK_StartParams(resv, rxgk_params); + + ref buf = alloc_enc_buffer(resv); + kafs::afs::xdr::encode_RXGK_StartParams(buf, rxgk_params); + rxrpc::seal_buffer(buf); + + gss_buffer_desc msg = { + .length = buf->size, + .value = buf->enc_buf, + }; + gss_buffer_desc mic = { + .length = client_info.mic.size(), + .value = client_info.mic.buffer, + }; + + verbose_gss("Verify MIC\n"); + major = gss_verify_mic(&minor, gssctx, &msg, &mic, &qop_state); + if (GSS_ERROR(major)) + throw_error("gss_verify_mic()", major, minor); +} + +/* + * Derive the transport key, K0. + */ +static void rxgk_derive_K0(gss_ctx_id_t &gssctx, + RXGK_StartParams &rxgk_params, + RXGK_ClientInfo &client_info, + rxrpc::Opaque &K0_buffer, + bool a_verbose) +{ + gss_buffer_desc K0 = GSS_C_EMPTY_BUFFER; + gss_buffer_desc prf_in; + OM_uint32 major, minor; + size_t enclen = rxgk_get_enc_len(client_info); + size_t csize = rxgk_params.client_nonce.size(); + size_t ssize = client_info.server_nonce.size(); + + prf_in.length = csize + ssize; + prf_in.value = alloca(prf_in.length); + memcpy(prf_in.value, rxgk_params.client_nonce.buffer, csize); + memcpy((char *)prf_in.value + csize, client_info.server_nonce.buffer, ssize); + + major = gss_pseudo_random(&minor, gssctx, GSS_C_PRF_KEY_FULL, &prf_in, + enclen, &K0); + if (GSS_ERROR(major)) + throw_error("gss_pseudo_random()", major, minor); + + debug_gss("K0 size {}\n", K0.length); + + K0_buffer.buffer_size = K0.length; + K0_buffer.buffer = K0.value; + K0_buffer.del_buffer = true; +} + +static void clear_gss_buffer(gss_buffer_t buf) +{ + free(buf->value); + buf->value = NULL; + buf->length = 0; +} + +static void rxgk_add_key(kafs::Context *ctx, + RXGK_ClientInfo &client_info, + rxrpc::Opaque &K0, + bool a_verbose, + unsigned sec_type) +{ + kafs::afs::ktc_tokenUnion token; + + token.type = sec_type; + switch (sec_type) { + case kafs::afs::AFSTOKEN_UNION_YFSGK: + token.ygk.begintime = 0; + token.ygk.endtime = client_info.expiration; + token.ygk.level = client_info.level; + token.ygk.lifetime = client_info.lifetime; + token.ygk.bytelife = client_info.bytelife; + token.ygk.enctype = client_info.enctype; + token.ygk.key = K0; + token.ygk.key.del_buffer = false; + token.ygk.ticket = client_info.token; + token.ygk.ticket.del_buffer = false; + break; + default: + throw std::runtime_error("Unknown security type"); + } + + rxrpc::Resv resv = { .max_ioc = 1, .flat = true }; + kafs::afs::xdr::reserve_ktc_tokenUnion(resv, token); + ref buf = alloc_enc_buffer(resv); + kafs::afs::xdr::encode_ktc_tokenUnion(buf, token); + rxrpc::seal_buffer(buf); + + verbose_gss("XDR encoded token {}\n", buf->size); + + kafs::afs::ktc_setTokenData payload; + payload.flags = 0; + payload.cell = ctx->cell_name; + payload.tokens.resize(1); + + rxrpc::Opaque &tok = payload.tokens[0]; + tok.buffer = buf->enc_buf; + tok.buffer_size = buf->size; + tok.del_buffer = false; + + rxrpc::Resv resv2 = { .max_ioc = 1, .flat = true }; + kafs::afs::xdr::reserve_ktc_setTokenData(resv2, payload); + ref buf2 = alloc_enc_buffer(resv2); + kafs::afs::xdr::encode_ktc_setTokenData(buf2, payload); + rxrpc::seal_buffer(buf2); + + std::string desc = fmt::format("afs@{}", ctx->cell_name); + + verbose_gss("XDR encoded payload {}\n", buf2->size); + verbose_gss("Key name {}\n", desc); + + key_serial_t key = add_key("rxrpc", desc.c_str(), buf2->enc_buf, buf2->size, + KEY_SPEC_SESSION_KEYRING); + if (key == -1) + throw std::system_error( + std::error_code(errno, std::generic_category()), + fmt::format("GSSAPI: Failed to add key '{}'", desc)); +} + +/*** + * COMMAND: gssapi aklog - Authenticate via GSSAPI for RxGK + * ARG: "[-cell ]" + * ARG: "[-principal ]" + * ARG: "[-enctypes +]" + * ARG: "[-levels +]" + * ARG: "[-noauth]" - Auth + * ARG: "[-localauth]" - Auth + * ARG: "[-verbose]" + * ARG: "[-encrypt]" - Auth + * + * Authenticate via GSSAPI to get tokens for the RxGK security class. + */ +void COMMAND_gssapi_aklog( + kafs::Context *ctx, + std::string &a_principal, + std::vector &a_enctypes, + std::vector &a_levels, + bool a_verbose) +{ + gss_buffer_desc token_for_gssapi = GSS_C_EMPTY_BUFFER; + gss_buffer_desc token_for_rxgk = GSS_C_EMPTY_BUFFER; + gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER; + gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT; + gss_name_t target_name = GSS_C_NO_NAME; + gss_OID actual_mech = GSS_C_NO_OID; + OM_uint32 major, minor, req_flags, ret_flags; + bool anon = false; + + ref vlservice = new kafs::VL_service(ctx); + rxrpc::Opaque opaque_cache, rxgk_info, K0; + RXGK_ClientInfo client_info; + + rxrpc::Call_params gss_params = vlservice->vl_params; + gss_params.peer.srx_service = kafs::afs::YFSRXGK_SERVICE_ID; + gss_params.security = NULL; + + rxgk_nonce nonce; + nonce.set(); + + RXGK_StartParams rxgk_params; + if (a_enctypes.size() == 0) { + rxgk_params.enctypes.push_back(ENCTYPE_AES128_CTS_HMAC_SHA1_96); + rxgk_params.enctypes.push_back(ENCTYPE_AES256_CTS_HMAC_SHA1_96); + rxgk_params.enctypes.push_back(ENCTYPE_AES128_CTS_HMAC_SHA256_128); + rxgk_params.enctypes.push_back(ENCTYPE_AES256_CTS_HMAC_SHA384_192); + rxgk_params.enctypes.push_back(ENCTYPE_CAMELLIA128_CTS_CMAC); + rxgk_params.enctypes.push_back(ENCTYPE_CAMELLIA256_CTS_CMAC); + } else { + for (size_t i = 0; i < a_enctypes.size(); i++) { + std::string &enc = a_enctypes[i]; + rxgk_params.enctypes.push_back(stoi(enc)); + } + } + + if (a_levels.size() == 0) { + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_CLEAR); + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_AUTH); + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_CRYPT); + } else { + for (size_t i = 0; i < a_levels.size(); i++) { + std::string &level = a_levels[i]; + if (level == "a") + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_CLEAR); + else if (level == "i") + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_AUTH); + else if (level == "c") + rxgk_params.levels.push_back(kafs::afs::RXGK_LEVEL_CRYPT); + else + throw std::invalid_argument("Unknown level"); + } + } + + rxgk_params.lifetime = 0; + rxgk_params.bytelife = 0; + rxgk_params.client_nonce.buffer_size = nonce.size(); + rxgk_params.client_nonce.buffer = nonce.nonce; + + try { + std::string name = fmt::format("yfs-rxgk@_afs.{}", ctx->cell_name); + + verbose_gss("Name: {}\n", name); + + name_buf.value = (void *)name.c_str(); + name_buf.length = name.size(); + major = gss_import_name(&minor, &name_buf, + GSS_C_NT_HOSTBASED_SERVICE, &target_name); + if (GSS_ERROR(major)) + throw std::runtime_error("GSSAPI: Could not import name"); + + /* Mutual authentication will require a token from acceptor to + * initiator and thus a second call to gss_init_sec_context(). + */ + req_flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; // | GSS_C_CONF_FLAG + if (anon) + req_flags |= GSS_C_ANON_FLAG; + + for (;;) { + verbose_gss("Invoke gss_init_sec_context()\n"); + + /* The initiator_cred_handle, mech_type, time_req, + * input_chan_bindings, actual_mech_type, and time_rec + * parameters are not needed in many cases. We pass + * GSS_C_NO_CREDENTIAL, GSS_C_NO_OID, 0, NULL, NULL, + * and NULL for them, respectively. + */ + major = gss_init_sec_context( + &minor, + GSS_C_NO_CREDENTIAL, /* Claimant cred */ + &gssctx, + target_name, /* Target name */ + GSS_C_NO_OID, /* Mech type */ + req_flags, /* Request flags */ + GSS_C_INDEFINITE, /* Lifetime req */ + GSS_C_NO_CHANNEL_BINDINGS, /* Input chan bindings */ + &token_for_gssapi, /* Input token */ + &actual_mech, /* Actual mech type */ + &token_for_rxgk, /* Output token */ + &ret_flags, /* Return flags */ + NULL); /* Lifetime_rec */ + + if (GSS_ERROR(major)) { + /* Should really call rxgk_negotiate() again + * here to transfer the error to the server. + */ + throw_error("gss_init_sec_context()", major, minor); + } + + clear_gss_buffer(&token_for_gssapi); + + /* Check that an anonymous initiator retained their + * anonymity. + */ + if (anon && !(ret_flags & GSS_C_ANON_FLAG)) + throw std::runtime_error( + "GSSAPI: Anonymous requested but not available"); + + /* Always send a token if we are expecting another input token + * (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. + */ + if ((major & GSS_S_CONTINUE_NEEDED) || + token_for_rxgk.length > 0) + rxgk_negotiate(gss_params, rxgk_params, + token_for_rxgk, token_for_gssapi, + opaque_cache, rxgk_info, a_verbose); + + gss_release_buffer(&minor, &token_for_rxgk); + + if (major & GSS_S_CONTINUE_NEEDED) + continue; + + if (major == GSS_S_COMPLETE) + break; + + /* This situation is forbidden by RFC 2743. Bail out. */ + throw std::runtime_error( + "GSSAPI: major not complete or continue but not error"); + } + + if ((ret_flags & req_flags) != req_flags) + throw std::runtime_error( + "GSSAPI: Negotiated context does not support requested flags"); + + rxgk_unwrap(gssctx, rxgk_info, client_info); + rxgk_check_mic(gssctx, rxgk_params, client_info, a_verbose); + rxgk_derive_K0(gssctx, rxgk_params, client_info, K0, a_verbose); + + rxgk_add_key(ctx, client_info, K0, a_verbose, + kafs::afs::AFSTOKEN_UNION_YFSGK); + + verbose_gss("Negotiation successful\n"); + } catch (...) { + gss_release_buffer(&minor, &token_for_rxgk); + gss_delete_sec_context(&minor, &gssctx, NULL); + gss_release_name(&minor, &target_name); + throw; + } + + gss_release_buffer(&minor, &token_for_rxgk); + gss_delete_sec_context(&minor, &gssctx, NULL); + gss_release_name(&minor, &target_name); +} diff --git a/kafs/gssapi_help.C b/kafs/gssapi_help.C new file mode 100644 index 0000000..dfdad8d --- /dev/null +++ b/kafs/gssapi_help.C @@ -0,0 +1,48 @@ +/* The gssapi help command + * + * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include "gssapi.H" + +/*** + * COMMAND: gssapi help - Get help on commands + * ARG: "[-topic +]" + * ARG: "[-admin]" + */ +void COMMAND_gssapi_help( + kafs::Context *ctx, + std::vector &a_topic, + bool a_admin) +{ + if (a_topic.empty()) + return kafs::help(&gen_gssapi_suite); + for (std::vector::iterator i = a_topic.begin(); i != a_topic.end(); i++) + kafs::help(&gen_gssapi_suite, *i); +} + +/*** + * COMMAND: gssapi apropos - Search for a command by its help text + * ARG: "-topic " + */ +void COMMAND_gssapi_apropos( + kafs::Context *ctx, + std::string &a_topic) +{ + const kafs::Command *cmd; + int i; + + for (i = 0; gen_gssapi_suite.commands[i]; i++) { + cmd = gen_gssapi_suite.commands[i]; + + if (strstr(cmd->name, a_topic.c_str()) || + strstr(cmd->help, a_topic.c_str())) + printf("%s: %s\n", cmd->name, cmd->help); + } +} diff --git a/kafs/kafs.C b/kafs/kafs.C index c028b55..f3a5396 100644 --- a/kafs/kafs.C +++ b/kafs/kafs.C @@ -24,6 +24,7 @@ extern "C" { #include "arg_parse.H" #include "bos.H" #include "fs.H" +#include "gssapi.H" #include "pts.H" #include "vos.H" #include "display.H" @@ -43,6 +44,7 @@ static ref context; const kafs::Suite *kafs::command_suites[] = { &gen_bos_suite, &gen_fs_suite, + &gen_gssapi_suite, &gen_pts_suite, &gen_vos_suite, NULL diff --git a/rpc-api/add_key.xg b/rpc-api/add_key.xg new file mode 100644 index 0000000..5290839 --- /dev/null +++ b/rpc-api/add_key.xg @@ -0,0 +1,56 @@ +/* afstoken - pioctl interface for new common token data structures. -*- c -*- + * + * revised following suggestions from lha@kth.se 20070511, 20070513 + */ + +/* this file is in the public domain. Do what thou wilt. */ + +typedef int64_t opr_time; + +const AFSTOKEN_RK_TIX_MAX = 12000; /* Matches entry in rxkad.h */ + +struct token_rxkad { + afs_int32 viceid; + afs_int32 kvno; + afs_int64 key; + afs_int32 begintime; + afs_int32 endtime; + afs_int32 primary_flag; + opaque ticket; +}; + +struct token_yfs_rxgk { + opr_time begintime; + opr_time endtime; + afs_int64 level; + afs_int64 lifetime; + afs_int64 bytelife; + afs_int64 enctype; + opaque key<>; + opaque ticket<>; +}; + +const AFSTOKEN_UNION_NOAUTH = 0; +const AFSTOKEN_UNION_KAD = 2; +const AFSTOKEN_UNION_YFSGK = 6; + +union ktc_tokenUnion switch (afs_int32 type) { + case AFSTOKEN_UNION_KAD: + token_rxkad kad; + case AFSTOKEN_UNION_YFSGK: + token_yfs_rxgk ygk; +}; + +const AFSTOKEN_LENGTH_MAX = 16384; +typedef opaque token_opaque; + +const AFSTOKEN_EX_SETPAG = 0x00000001; /* set tokens in new pag */ +const AFSTOKEN_EX_SYSTEM = 0x00000002; /* system default token */ +const AFSTOKEN_MAX = 8; +const AFSTOKEN_CELL_MAX = 64; + +struct ktc_setTokenData { + afs_int32 flags; + string cell; + token_opaque tokens; +}; diff --git a/rpc-api/rxgk.et b/rpc-api/rxgk.et new file mode 100644 index 0000000..d4a47db --- /dev/null +++ b/rpc-api/rxgk.et @@ -0,0 +1,26 @@ +/* + * Auristor/YFS fileserver and cache manager opcodes. Please do not add or + * modify opcodes here without consulting Auristor, Inc.. + * + * Copyright (c) 2015-2020 AuriStor, Inc. + * 255 W 94th St, New York NY 10025-6985 United States, Earth, Sol, Milky Way + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +error_table RXGK + ec RXGKINCONSISTENCY, "Security module structure inconsistent" + ec RXGKPACKETSHORT, "Packet too short for security challenge" + ec RXGKBADCHALLENGE, "Security challenge/response failed" + ec RXGKSEALEDINCON, "Sealed data is inconsistent" + ec RXGKNOTAUTH, "Caller not authorised" + ec RXGKEXPIRED, "Authentication expired" + ec RXGKBADLEVEL, "Unsupported or not permitted security level" + ec RXGKBADKEYNO, "Bad transport key number" + ec RXGKNOTRXGK, "Security layer is not rxgk" + ec RXGKUNSUPPORTED, "Endpoint does not support rxgk" + ec RXGKGSSERROR, "GSSAPI mechanism error" +end diff --git a/rpc-api/rxgk.xg b/rpc-api/rxgk.xg new file mode 100644 index 0000000..a1dab01 --- /dev/null +++ b/rpc-api/rxgk.xg @@ -0,0 +1,96 @@ +/* -*- c -*- + * RxGK support pieces. + * + * From: https://tools.ietf.org/html/draft-wilkinson-afs3-rxgk-11 + */ + +package RXGK_ + +const RXGK_SERVICE = 34567; + +const RXGK_CLIENT_ENC_PACKET = 1026; +const RXGK_CLIENT_MIC_PACKET = 1027; +const RXGK_SERVER_ENC_PACKET = 1028; +const RXGK_SERVER_MIC_PACKET = 1029; +const RXGK_CLIENT_ENC_RESPONSE = 1030; +const RXGK_SERVER_ENC_TOKEN = 1036; + +enum RXGK_Level { + RXGK_LEVEL_CLEAR = 0, + RXGK_LEVEL_AUTH = 1, + RXGK_LEVEL_CRYPT = 2 +}; + +/* Error codes */ +const RXGK_INCONSISTENCY = 1233242880; /* Security module structure inconsistent */ +const RXGK_PACKETSHORT = 1233242881; /* Packet too short for security challenge */ +const RXGK_BADCHALLENGE = 1233242882; /* Invalid security challenge */ +const RXGK_BADETYPE = 1233242883; /* Invalid or impermissible encryption type */ +const RXGK_BADLEVEL = 1233242884; /* Invalid or impermissible security level */ +const RXGK_BADKEYNO = 1233242885; /* Key version number not found */ +const RXGK_EXPIRED = 1233242886; /* Token has expired */ +const RXGK_NOTAUTH = 1233242887; /* Caller not authorized */ +const RXGK_BAD_TOKEN = 1233242888; /* Security object was passed a bad token */ +const RXGK_SEALED_INCON = 1233242889; /* Sealed data inconsistent */ +const RXGK_DATA_LEN = 1233242890; /* User data too long */ +const RXGK_BAD_QOP = 1233242891; /* Inadequate quality of protection available */ + +/* limits for variable-length arrays */ +const RXGK_MAXENCTYPES = 255; +const RXGK_MAXLEVELS = 255; +const RXGK_MAXMIC = 1024; +const RXGK_MAXNONCE = 1024; +const RXGK_MAXDATA = 1048576; + +typedef int32_t RXGK_Enctypes; +typedef opaque RXGK_Data; +typedef int64_t rxgkTime; + +struct RXGK_StartParams { + RXGK_Enctypes enctypes; + RXGK_Level levels; + uint32_t lifetime; + uint32_t bytelife; + opaque client_nonce; +}; + +struct RXGK_ClientInfo { + int32_t errorcode; + int32_t enctype; + RXGK_Level level; + uint32_t lifetime; + uint32_t bytelife; + rxgkTime expiration; + opaque mic; + opaque token; + opaque server_nonce; +}; + +GSSNegotiate(IN RXGK_StartParams *client_start, + IN RXGK_Data *input_token_buffer, + IN RXGK_Data *opaque_in, + OUT RXGK_Data *output_token_buffer, + OUT RXGK_Data *opaque_out, + OUT uint32_t *gss_major_status, + OUT uint32_t *gss_minor_status, + OUT RXGK_Data *rxgk_info + ) = 1; + +struct RXGK_CombineOptions { + RXGK_Enctypes enctypes; + RXGK_Level levels; +}; + +struct RXGK_TokenInfo { + int32_t enctype; + RXGK_Level level; + uint32_t lifetime; + uint32_t bytelife; + rxgkTime expiration; +}; + +CombineTokens(IN RXGK_Data *token0, + IN RXGK_Data *token1, + IN RXGK_CombineOptions *options, + OUT RXGK_Data *new_token, + OUT RXGK_TokenInfo *info) = 2; diff --git a/rpc-api/yfs.xg b/rpc-api/yfs.xg index 468808f..87f16eb 100644 --- a/rpc-api/yfs.xg +++ b/rpc-api/yfs.xg @@ -122,8 +122,6 @@ typedef YFSFetchStatus YFSBulkStats; typedef int64_t YFSViceIds; -const AUTHDATAMAX = 1024; -const AUTHPRINTABLEMAX = 1024; struct FS_AuthName { int32_t kind; opaque data; diff --git a/rpc-api/yfs_common.h b/rpc-api/yfs_common.h index 6ae4eeb..4a26a5c 100644 --- a/rpc-api/yfs_common.h +++ b/rpc-api/yfs_common.h @@ -24,3 +24,6 @@ struct endpoint { uint32_t Type; opaque Data; /* Address and port */ }; + +const AUTHDATAMAX = 1024; +const AUTHPRINTABLEMAX = 1024; diff --git a/rpc-api/yfs_rxgk.xg b/rpc-api/yfs_rxgk.xg new file mode 100644 index 0000000..604f416 --- /dev/null +++ b/rpc-api/yfs_rxgk.xg @@ -0,0 +1,201 @@ +/* -*- c -*- + * + * Auristor/YFS fileserver and cache manager opcodes. Please do not add or + * modify opcodes here without consulting Auristor, Inc.. + * + * Copyright (c) 2015-2020 AuriStor, Inc. + * 255 W 94th St, New York NY 10025-6985 United States, Earth, Sol, Milky Way + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +package YFSRXGK_ +//prefix S +//statindex 14 + +//%#include +//%#include +//%#include "rxgk.h" +//%#include "util.h" + +//%#ifndef DEFINED_OPR_UUID_VECTOR +//%#define DEFINED_OPR_UUID_VECTOR 1 +//%typedef struct opr_uuid opr_uuid_vector; +//%#endif + +/* The spec requires us to use PrAuthName, as defined by the Extended + * Authentication Names specifcation. However, in our implementation this + * code is in the ptserver, not in the RX layer. Directly using those + * symbols here would be a layering violation, so just use an idential + * structure with a different name - they'll be identical on the wire. + */ + +const PRAUTHTYPE_GSS = 2; + +struct RXGK_AuthName { + afs_int32 kind; + opaque data; + opaque display; +}; + +/* Key derivation values */ + +const YFSRXGK_SERVICE_ID = 2508; +const RXGK_SERVICE_ID = 34567; + +const RXGK_NONCE_SIZE = 20; + +/* Limits */ +//const RXGK_MAXENCTYPES = 255; +//const RXGK_MAXLEVELS = 255; +//const RXGK_MAXMIC = 1024; +//const RXGK_MAXNONCE = 1024; +//const RXGK_MAXDATA = 1048576; +const RXGK_MAXAUTHENTICATOR = 1416; + +//typedef afs_int32 RXGK_Enctypes; +typedef RXGK_Level RXGK_Levels; + +//typedef opaque RXGK_Data; + +#if 0 +struct RXGK_StartParams { + RXGK_Enctypes enctypes; + RXGK_Levels levels; + afs_int32 lifetime; + afs_int32 bytelife; + opaque client_nonce; +}; + +struct RXGK_ClientInfo { + afs_int32 errorcode; + afs_int32 enctype; + RXGK_Level level; + afs_int32 lifetime; + afs_int32 bytelife; + rxgkTime expiration; + opaque mic; + opaque token; + opaque server_nonce; +}; + +struct RXGK_CombineOptions { + RXGK_Enctypes enctypes; + RXGK_Levels levels; +}; + +struct RXGK_TokenInfo { + afs_int32 enctype; + RXGK_Level level; + afs_int32 lifetime; + afs_int32 bytelife; + rxgkTime expirationtime; +}; +#endif + +GSSNegotiate(IN RXGK_StartParams *client_start, + IN RXGK_Data *input_token_buffer, + IN RXGK_Data *opaque_in, + OUT RXGK_Data *output_token_buffer, + OUT RXGK_Data *opaque_out, + OUT afs_uint32 *gss_major, + OUT afs_uint32 *gss_minor, + OUT RXGK_Data *rxgk_info) = 1; + +CombineTokens(IN RXGK_Data *token0, + IN RXGK_Data *token1, + IN RXGK_CombineOptions *options, + OUT RXGK_Data *new_token, + OUT RXGK_TokenInfo *info) = 2; + +const RXGKCAPABILITIESMAX = 196; +typedef afs_uint32 RXGKCapabilities; + +GetCapabilities( + OUT RXGKCapabilities *caps +) multi = 5; + +/********************************************************************** + * RX challenge and response + **********************************************************************/ + +struct RXGK_Challenge { + opaque nonce; +}; + +struct RXGK_Response { + rxgkTime start_time; + opaque token; + opaque authenticator; +}; + +struct RXGK_Authenticator { + opaque nonce; + opaque appdata<>; + RXGK_Level level; + afs_uint32 epoch; + afs_uint32 cid; + afs_int32 call_numbers<>; +}; + +/********************************************************************** + * AFS specifics + **********************************************************************/ + +#if 0 +AFSCombineTokensOld(IN RXGK_Data *token0, + IN RXGK_Data *token1, + IN RXGK_CombineOptions *options, + IN opr_uuid *destination, + OUT RXGK_Data *new_token, + OUT RXGK_TokenInfo *token_info) = 3; +#endif + +AFSCombineTokens(IN RXGK_Data *token0, + IN RXGK_Data *token1, + IN RXGK_CombineOptions *options, + IN opr_uuid *destination, + OUT RXGK_Data *new_token, + OUT RXGK_TokenInfo *token_info) = 4; + +/* Token format */ + +struct rxgk_key { + afs_uint32 enctype; + opaque key<>; +}; + +struct RXGK_Token { + rxgk_key K0; + RXGK_Level level; + rxgkTime starttime; + afs_int32 lifetime; + afs_int32 bytelife; + rxgkTime expirationtime; + struct RXGK_AuthName identities<>; +}; + +struct RXGK_TokenContainer { + afs_int32 kvno; + afs_int32 enctype; + opaque encrypted_token<>; +}; + +#if 0 +/* Server registration (actual RPC is a generic VL one, these are + * just marshalling types + */ + +struct RXGK_ServerKeyDataRequest { + afs_int32 enctypes<>; + opaque nonce1<>; +}; + +struct RXGK_ServerKeyDataResponse { + afs_int32 enctype; + opaque nonce2<>; +}; +#endif -- 2.49.0