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