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