1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/*
* Copyright (C) 1996-2019 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
* Please see the COPYING and CONTRIBUTORS files for details.
*/
#include "squid.h"
#if HAVE_GSSAPI
#include "base64.h"
#include "tools/squidclient/gssapi_support.h"
#include <iostream>
#if !defined(gss_mech_spnego)
static gss_OID_desc _gss_mech_spnego = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
gss_OID gss_mech_spnego = &_gss_mech_spnego;
#endif
#define BUFFER_SIZE 8192
/**
* Check return valuse major_status, minor_status for error and print error description
* in case of an error.
*
* \retval true in case of gssapi error
* \retval false in case of no gssapi error
*/
bool
check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function)
{
if (GSS_ERROR(major_status)) {
OM_uint32 maj_stat, min_stat;
OM_uint32 msg_ctx = 0;
gss_buffer_desc status_string;
char buf[BUFFER_SIZE];
size_t len;
len = 0;
msg_ctx = 0;
while (!msg_ctx) {
/* convert major status code (GSS-API error) to text */
maj_stat = gss_display_status(&min_stat, major_status,
GSS_C_GSS_CODE,
GSS_C_NULL_OID,
&msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
snprintf(buf + len, BUFFER_SIZE-len, "%s", (char *) status_string.value);
len += status_string.length;
gss_release_buffer(&min_stat, &status_string);
break;
}
gss_release_buffer(&min_stat, &status_string);
}
snprintf(buf + len, BUFFER_SIZE-len, "%s", ". ");
len += 2;
msg_ctx = 0;
while (!msg_ctx) {
/* convert minor status code (underlying routine error) to text */
maj_stat = gss_display_status(&min_stat, minor_status,
GSS_C_MECH_CODE,
GSS_C_NULL_OID,
&msg_ctx, &status_string);
if (maj_stat == GSS_S_COMPLETE) {
snprintf(buf + len, BUFFER_SIZE-len,"%s", (char *) status_string.value);
len += status_string.length;
gss_release_buffer(&min_stat, &status_string);
break;
}
gss_release_buffer(&min_stat, &status_string);
}
std::cerr << "ERROR: " << function << " failed: " << buf << std::endl;
return true;
}
return false;
}
/**
* Get gssapi token for service HTTP/<server>
* User has to initiate a kinit user@DOMAIN on commandline first for the
* function to be successful
*
* \return base64 encoded token if successful,
* string "ERROR" if unsuccessful
*/
char *
GSSAPI_token(const char *server)
{
OM_uint32 major_status, minor_status;
gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
gss_name_t server_name = GSS_C_NO_NAME;
gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
char *token = NULL;
setbuf(stdout, NULL);
setbuf(stdin, NULL);
if (!server) {
std::cerr << "ERROR: GSSAPI: No server name" << std::endl;
token = new char[6];
memcpy(token, "ERROR", 5);
token[5] = '\0';
return token;
}
service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
service.length = strlen((char *) service.value);
major_status = gss_import_name(&minor_status, &service,
gss_nt_service_name, &server_name);
if (!check_gss_err(major_status, minor_status, "gss_import_name()")) {
major_status = gss_init_sec_context(&minor_status,
GSS_C_NO_CREDENTIAL,
&gss_context,
server_name,
gss_mech_spnego,
0,
0,
GSS_C_NO_CHANNEL_BINDINGS,
&input_token,
NULL,
&output_token,
NULL,
NULL);
if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()") && output_token.length) {
token = new char[base64_encode_len(output_token.length)];
struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
size_t blen = base64_encode_update(&ctx, token, output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
blen += base64_encode_final(&ctx, token+blen);
token[blen] = '\0';
}
}
if (!output_token.length) {
token = new char[6];
memcpy(token, "ERROR", 5);
token[5] = '\0';
}
gss_delete_sec_context(&minor_status, &gss_context, NULL);
gss_release_buffer(&minor_status, &service);
gss_release_buffer(&minor_status, &input_token);
gss_release_buffer(&minor_status, &output_token);
gss_release_name(&minor_status, &server_name);
return token;
}
#endif /* HAVE_GSSAPI */
|