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;
136 count = write (inSocket, ptr, inBufferLength - bytesWritten);
139 /* Try again on EINTR */
140 if (errno != EINTR) { err = errno; }
143 bytesWritten += count;
145 } while (!err && (bytesWritten < inBufferLength));
148 if (err) { gsscon_print_error (err, "WriteBuffer failed"); }
153 /* --------------------------------------------------------------------------- */
154 /* Read a GSS token (length + data) off the network */
156 int gsscon_read_token (int inSocket,
157 char **outTokenValue,
158 size_t *outTokenLength)
162 u_int32_t tokenLength = 0;
164 if (!outTokenValue ) { err = EINVAL; }
165 if (!outTokenLength) { err = EINVAL; }
168 err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
172 tokenLength = ntohl (tokenLength);
173 token = malloc (tokenLength);
177 memset (token, 0, tokenLength);
179 err = ReadBuffer (inSocket, tokenLength, token);
184 *outTokenLength = tokenLength;
185 *outTokenValue = token;
186 token = NULL; /* only free on error */
188 gsscon_print_error (err, "ReadToken failed");
191 if (token) { free (token); }
196 /* --------------------------------------------------------------------------- */
197 /* Write a GSS token (length + data) onto the network */
199 int gsscon_write_token (int inSocket,
200 const char *inTokenValue,
201 size_t inTokenLength)
204 u_int32_t tokenLength = htonl (inTokenLength);
206 if (!inTokenValue) { err = EINVAL; }
209 err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
213 err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
217 // printf ("Wrote token:\n");
218 // PrintBuffer (inTokenValue, inTokenLength);
221 gsscon_print_error (err, "gsscon_write_token() failed");
227 /* --------------------------------------------------------------------------- */
228 /* Read an encrypted GSS token (length + encrypted data) off the network */
231 int gsscon_read_encrypted_token (int inSocket,
232 const gss_ctx_id_t inContext,
233 char **outTokenValue,
234 size_t *outTokenLength)
238 size_t tokenLength = 0;
239 OM_uint32 majorStatus;
240 OM_uint32 minorStatus = 0;
241 gss_buffer_desc outputBuffer = { 0 , NULL};
242 char *unencryptedToken = NULL;
244 if (!inContext ) { err = EINVAL; }
245 if (!outTokenValue ) { err = EINVAL; }
246 if (!outTokenLength) { err = EINVAL; }
249 err = gsscon_read_token (inSocket, &token, &tokenLength);
253 gss_buffer_desc inputBuffer = { tokenLength, token};
254 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
256 majorStatus = gss_unwrap (&minorStatus,
261 NULL /* qop_state */);
262 if (majorStatus != GSS_S_COMPLETE) {
263 gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
264 err = minorStatus ? minorStatus : majorStatus;
265 } else if (!encrypted) {
266 fprintf (stderr, "WARNING! Mechanism not using encryption!");
267 err = EINVAL; /* You may not want to fail here. */
272 unencryptedToken = malloc (outputBuffer.length);
273 if (unencryptedToken == NULL) { err = ENOMEM; }
277 memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
279 // printf ("Unencrypted token:\n");
280 // PrintBuffer (unencryptedToken, outputBuffer.length);
282 *outTokenLength = outputBuffer.length;
283 *outTokenValue = unencryptedToken;
284 unencryptedToken = NULL; /* only free on error */
287 gsscon_print_error (err, "ReadToken failed");
290 if (token ) { free (token); }
291 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
292 if (unencryptedToken ) { free (unencryptedToken); }
297 /* --------------------------------------------------------------------------- */
298 /* Write an encrypted GSS token (length + encrypted data) onto the network */
300 int gsscon_write_encrypted_token (int inSocket,
301 const gss_ctx_id_t inContext,
303 size_t inTokenLength)
306 OM_uint32 majorStatus;
307 OM_uint32 minorStatus = 0;
308 gss_buffer_desc outputBuffer = { 0, NULL };
310 if (!inContext) { err = EINVAL; }
311 if (!inToken ) { err = EINVAL; }
314 gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
315 int encrypt = 1; /* do encryption and integrity protection */
316 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
318 majorStatus = gss_wrap (&minorStatus,
325 if (majorStatus != GSS_S_COMPLETE) {
326 gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
327 err = minorStatus ? minorStatus : majorStatus;
328 } else if (!encrypted) {
329 fprintf (stderr, "WARNING! Mechanism does not support encryption!");
330 err = EINVAL; /* You may not want to fail here. */
335 // printf ("Unencrypted token:\n");
336 // PrintBuffer (inToken, inTokenLength);
337 err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
342 gsscon_print_error (err, "gsscon_write_token failed");
345 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
350 /* --------------------------------------------------------------------------- */
351 /* Print BSD error */
353 void gsscon_print_error (int inError,
354 const char *inString)
356 fprintf (stderr, "%s: %s (err = %d)\n",
357 inString, error_message (inError), inError);
360 /* --------------------------------------------------------------------------- */
361 /* PrintGSSAPI errors */
363 void gsscon_print_gss_errors (const char *inRoutineName,
364 OM_uint32 inMajorStatus,
365 OM_uint32 inMinorStatus)
367 OM_uint32 minorStatus;
368 OM_uint32 majorStatus;
369 gss_buffer_desc errorBuffer;
371 OM_uint32 messageContext = 0; /* first message */
374 fprintf (stderr, "Error returned by %s:\n", inRoutineName);
377 majorStatus = gss_display_status (&minorStatus,
383 if (majorStatus == GSS_S_COMPLETE) {
384 fprintf (stderr," major error <%d> %s\n",
385 count, (char *) errorBuffer.value);
386 gss_release_buffer (&minorStatus, &errorBuffer);
389 } while (messageContext != 0);
394 majorStatus = gss_display_status (&minorStatus,
400 fprintf (stderr," minor error <%d> %s\n",
401 count, (char *) errorBuffer.value);
403 } while (messageContext != 0);