2 * Copyright (c) 2012, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
33 * This code was adapted from the MIT Kerberos Consortium's
34 * GSS example code, which was distributed under the following
37 * Copyright 2004-2006 Massachusetts Institute of Technology.
38 * All Rights Reserved.
40 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
41 * distribute this software and its documentation for any purpose and
42 * without fee is hereby granted, provided that the above copyright
43 * notice appear in all copies and that both that copyright notice and
44 * this permission notice appear in supporting documentation, and that
45 * the name of M.I.T. not be used in advertising or publicity pertaining
46 * to distribution of the software without specific, written prior
47 * permission. Furthermore if you modify this software you must label
48 * your software as modified software and not distribute it in such a
49 * fashion that it might be confused with the original M.I.T. software.
50 * M.I.T. makes no representations about the suitability of
51 * this software for any purpose. It is provided "as is" without express
52 * or implied warranty.
57 /* --------------------------------------------------------------------------- */
58 /* Display the contents of the buffer in hex and ascii */
60 static void PrintBuffer (const char *inBuffer,
65 for (i = 0; i < inLength; i += 16) {
67 for (l = i; l < (i + 16); l++) {
71 u_int8_t *byte = (u_int8_t *) inBuffer + l;
72 printf ("%2.2x", *byte);
74 if ((l % 4) == 3) { printf (" "); }
77 for (l = i; l < (i + 16) && l < inLength; l++) {
78 printf ("%c", ((inBuffer[l] > 0x1f) &&
79 (inBuffer[l] < 0x7f)) ? inBuffer[l] : '.');
86 /* --------------------------------------------------------------------------- */
87 /* Standard network read loop, accounting for EINTR, EOF and incomplete reads */
89 static int ReadBuffer (int inSocket,
90 size_t inBufferLength,
94 ssize_t bytesRead = 0;
96 if (!ioBuffer) { err = EINVAL; }
101 ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
103 /* Try again on EINTR */
104 if (errno != EINTR) { err = errno; }
105 } else if (count == 0) {
106 err = ECONNRESET; /* EOF and we expected data */
111 } while (!err && (bytesRead < inBufferLength));
114 if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
119 /* --------------------------------------------------------------------------- */
120 /* Standard network write loop, accounting for EINTR and incomplete writes */
122 static int WriteBuffer (int inSocket,
123 const char *inBuffer,
124 size_t inBufferLength)
127 ssize_t bytesWritten = 0;
129 if (!inBuffer) { err = EINVAL; }
132 const char *ptr = inBuffer;
134 ssize_t count = write (inSocket, ptr, inBufferLength - bytesWritten);
136 /* Try again on EINTR */
137 if (errno != EINTR) { err = errno; }
140 bytesWritten += count;
142 } while (!err && (bytesWritten < inBufferLength));
145 if (err) { gsscon_print_error (err, "WritBuffer failed"); }
150 /* --------------------------------------------------------------------------- */
151 /* Read a GSS token (length + data) off the network */
153 int gsscon_read_token (int inSocket,
154 char **outTokenValue,
155 size_t *outTokenLength)
159 u_int32_t tokenLength = 0;
161 if (!outTokenValue ) { err = EINVAL; }
162 if (!outTokenLength) { err = EINVAL; }
165 err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
169 tokenLength = ntohl (tokenLength);
170 token = malloc (tokenLength);
171 memset (token, 0, tokenLength);
173 err = ReadBuffer (inSocket, tokenLength, token);
177 // printf ("Read token:\n");
178 // PrintBuffer (token, tokenLength);
180 *outTokenLength = tokenLength;
181 *outTokenValue = token;
182 token = NULL; /* only free on error */
184 gsscon_print_error (err, "ReadToken failed");
187 if (token) { free (token); }
192 /* --------------------------------------------------------------------------- */
193 /* Write a GSS token (length + data) onto the network */
195 int gsscon_write_token (int inSocket,
196 const char *inTokenValue,
197 size_t inTokenLength)
200 u_int32_t tokenLength = htonl (inTokenLength);
202 if (!inTokenValue) { err = EINVAL; }
205 err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
209 err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
213 // printf ("Wrote token:\n");
214 // PrintBuffer (inTokenValue, inTokenLength);
217 gsscon_print_error (err, "gsscon_write_token() failed");
223 /* --------------------------------------------------------------------------- */
224 /* Read an encrypted GSS token (length + encrypted data) off the network */
227 int gsscon_read_encrypted_token (int inSocket,
228 const gss_ctx_id_t inContext,
229 char **outTokenValue,
230 size_t *outTokenLength)
234 size_t tokenLength = 0;
235 OM_uint32 majorStatus;
236 OM_uint32 minorStatus = 0;
237 gss_buffer_desc outputBuffer = { 0 , NULL};
238 char *unencryptedToken = NULL;
240 if (!inContext ) { err = EINVAL; }
241 if (!outTokenValue ) { err = EINVAL; }
242 if (!outTokenLength) { err = EINVAL; }
245 err = gsscon_read_token (inSocket, &token, &tokenLength);
249 gss_buffer_desc inputBuffer = { tokenLength, token};
250 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
252 majorStatus = gss_unwrap (&minorStatus,
257 NULL /* qop_state */);
258 if (majorStatus != GSS_S_COMPLETE) {
259 gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
260 err = minorStatus ? minorStatus : majorStatus;
261 } else if (!encrypted) {
262 fprintf (stderr, "WARNING! Mechanism not using encryption!");
263 err = EINVAL; /* You may not want to fail here. */
268 unencryptedToken = malloc (outputBuffer.length);
269 if (unencryptedToken == NULL) { err = ENOMEM; }
273 memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
275 // printf ("Unencrypted token:\n");
276 // PrintBuffer (unencryptedToken, outputBuffer.length);
278 *outTokenLength = outputBuffer.length;
279 *outTokenValue = unencryptedToken;
280 unencryptedToken = NULL; /* only free on error */
283 gsscon_print_error (err, "ReadToken failed");
286 if (token ) { free (token); }
287 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
288 if (unencryptedToken ) { free (unencryptedToken); }
293 /* --------------------------------------------------------------------------- */
294 /* Write an encrypted GSS token (length + encrypted data) onto the network */
296 int gsscon_write_encrypted_token (int inSocket,
297 const gss_ctx_id_t inContext,
299 size_t inTokenLength)
302 OM_uint32 majorStatus;
303 OM_uint32 minorStatus = 0;
304 gss_buffer_desc outputBuffer = { 0, NULL };
306 if (!inContext) { err = EINVAL; }
307 if (!inToken ) { err = EINVAL; }
310 gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
311 int encrypt = 1; /* do encryption and integrity protection */
312 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
314 majorStatus = gss_wrap (&minorStatus,
321 if (majorStatus != GSS_S_COMPLETE) {
322 gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
323 err = minorStatus ? minorStatus : majorStatus;
324 } else if (!encrypted) {
325 fprintf (stderr, "WARNING! Mechanism does not support encryption!");
326 err = EINVAL; /* You may not want to fail here. */
331 // printf ("Unencrypted token:\n");
332 // PrintBuffer (inToken, inTokenLength);
333 err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
338 gsscon_print_error (err, "gsscon_write_token failed");
341 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
346 /* --------------------------------------------------------------------------- */
347 /* Print BSD error */
349 void gsscon_print_error (int inError,
350 const char *inString)
352 fprintf (stderr, "%s: %s (err = %d)\n",
353 inString, error_message (inError), inError);
356 /* --------------------------------------------------------------------------- */
357 /* PrintGSSAPI errors */
359 void gsscon_print_gss_errors (const char *inRoutineName,
360 OM_uint32 inMajorStatus,
361 OM_uint32 inMinorStatus)
363 OM_uint32 minorStatus;
364 OM_uint32 majorStatus;
365 gss_buffer_desc errorBuffer;
367 OM_uint32 messageContext = 0; /* first message */
370 fprintf (stderr, "Error returned by %s:\n", inRoutineName);
373 majorStatus = gss_display_status (&minorStatus,
379 if (majorStatus == GSS_S_COMPLETE) {
380 fprintf (stderr," major error <%d> %s\n",
381 count, (char *) errorBuffer.value);
382 gss_release_buffer (&minorStatus, &errorBuffer);
385 } while (messageContext != 0);
390 majorStatus = gss_display_status (&minorStatus,
396 fprintf (stderr," minor error <%d> %s\n",
397 count, (char *) errorBuffer.value);
399 } while (messageContext != 0);