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.
59 /* --------------------------------------------------------------------------- */
60 /* Display the contents of the buffer in hex and ascii */
62 static void PrintBuffer (const char *inBuffer,
67 for (i = 0; i < inLength; i += 16) {
69 for (l = i; l < (i + 16); l++) {
73 u_int8_t *byte = (u_int8_t *) inBuffer + l;
74 printf ("%2.2x", *byte);
76 if ((l % 4) == 3) { printf (" "); }
79 for (l = i; l < (i + 16) && l < inLength; l++) {
80 printf ("%c", ((inBuffer[l] > 0x1f) &&
81 (inBuffer[l] < 0x7f)) ? inBuffer[l] : '.');
88 /* --------------------------------------------------------------------------- */
89 /* Standard network read loop, accounting for EINTR, EOF and incomplete reads */
91 static int ReadBuffer (int inSocket,
92 size_t inBufferLength,
96 ssize_t bytesRead = 0;
98 if (!ioBuffer) { err = EINVAL; }
101 char *ptr = ioBuffer;
103 ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
105 /* Try again on EINTR */
106 if (errno != EINTR) { err = errno; }
107 } else if (count == 0) {
108 err = ECONNRESET; /* EOF and we expected data */
113 } while (!err && (bytesRead < inBufferLength));
116 if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
121 /* --------------------------------------------------------------------------- */
122 /* Standard network write loop, accounting for EINTR and incomplete writes */
124 static int WriteBuffer (int inSocket,
125 const char *inBuffer,
126 size_t inBufferLength)
129 ssize_t bytesWritten = 0;
131 if (!inBuffer) { err = EINVAL; }
134 const char *ptr = inBuffer;
138 /* disable the SIGPIPE signal while we write so that we can handle a
139 * broken pipe error gracefully */
140 signal(SIGPIPE, SIG_IGN); /* temporarily disable */
141 count = write (inSocket, ptr, inBufferLength - bytesWritten);
142 signal(SIGPIPE, SIG_DFL); /* reenable */
145 /* Try again on EINTR */
146 if (errno != EINTR) { err = errno; }
149 bytesWritten += count;
151 } while (!err && (bytesWritten < inBufferLength));
154 if (err) { gsscon_print_error (err, "WriteBuffer failed"); }
159 /* --------------------------------------------------------------------------- */
160 /* Read a GSS token (length + data) off the network */
162 int gsscon_read_token (int inSocket,
163 char **outTokenValue,
164 size_t *outTokenLength)
168 u_int32_t tokenLength = 0;
170 if (!outTokenValue ) { err = EINVAL; }
171 if (!outTokenLength) { err = EINVAL; }
174 err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
178 tokenLength = ntohl (tokenLength);
179 token = malloc (tokenLength);
180 memset (token, 0, tokenLength);
182 err = ReadBuffer (inSocket, tokenLength, token);
186 // printf ("Read token:\n");
187 // PrintBuffer (token, tokenLength);
189 *outTokenLength = tokenLength;
190 *outTokenValue = token;
191 token = NULL; /* only free on error */
193 gsscon_print_error (err, "ReadToken failed");
196 if (token) { free (token); }
201 /* --------------------------------------------------------------------------- */
202 /* Write a GSS token (length + data) onto the network */
204 int gsscon_write_token (int inSocket,
205 const char *inTokenValue,
206 size_t inTokenLength)
209 u_int32_t tokenLength = htonl (inTokenLength);
211 if (!inTokenValue) { err = EINVAL; }
214 err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
218 err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
222 // printf ("Wrote token:\n");
223 // PrintBuffer (inTokenValue, inTokenLength);
226 gsscon_print_error (err, "gsscon_write_token() failed");
232 /* --------------------------------------------------------------------------- */
233 /* Read an encrypted GSS token (length + encrypted data) off the network */
236 int gsscon_read_encrypted_token (int inSocket,
237 const gss_ctx_id_t inContext,
238 char **outTokenValue,
239 size_t *outTokenLength)
243 size_t tokenLength = 0;
244 OM_uint32 majorStatus;
245 OM_uint32 minorStatus = 0;
246 gss_buffer_desc outputBuffer = { 0 , NULL};
247 char *unencryptedToken = NULL;
249 if (!inContext ) { err = EINVAL; }
250 if (!outTokenValue ) { err = EINVAL; }
251 if (!outTokenLength) { err = EINVAL; }
254 err = gsscon_read_token (inSocket, &token, &tokenLength);
258 gss_buffer_desc inputBuffer = { tokenLength, token};
259 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
261 majorStatus = gss_unwrap (&minorStatus,
266 NULL /* qop_state */);
267 if (majorStatus != GSS_S_COMPLETE) {
268 gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
269 err = minorStatus ? minorStatus : majorStatus;
270 } else if (!encrypted) {
271 fprintf (stderr, "WARNING! Mechanism not using encryption!");
272 err = EINVAL; /* You may not want to fail here. */
277 unencryptedToken = malloc (outputBuffer.length);
278 if (unencryptedToken == NULL) { err = ENOMEM; }
282 memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
284 // printf ("Unencrypted token:\n");
285 // PrintBuffer (unencryptedToken, outputBuffer.length);
287 *outTokenLength = outputBuffer.length;
288 *outTokenValue = unencryptedToken;
289 unencryptedToken = NULL; /* only free on error */
292 gsscon_print_error (err, "ReadToken failed");
295 if (token ) { free (token); }
296 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
297 if (unencryptedToken ) { free (unencryptedToken); }
302 /* --------------------------------------------------------------------------- */
303 /* Write an encrypted GSS token (length + encrypted data) onto the network */
305 int gsscon_write_encrypted_token (int inSocket,
306 const gss_ctx_id_t inContext,
308 size_t inTokenLength)
311 OM_uint32 majorStatus;
312 OM_uint32 minorStatus = 0;
313 gss_buffer_desc outputBuffer = { 0, NULL };
315 if (!inContext) { err = EINVAL; }
316 if (!inToken ) { err = EINVAL; }
319 gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
320 int encrypt = 1; /* do encryption and integrity protection */
321 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
323 majorStatus = gss_wrap (&minorStatus,
330 if (majorStatus != GSS_S_COMPLETE) {
331 gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
332 err = minorStatus ? minorStatus : majorStatus;
333 } else if (!encrypted) {
334 fprintf (stderr, "WARNING! Mechanism does not support encryption!");
335 err = EINVAL; /* You may not want to fail here. */
340 // printf ("Unencrypted token:\n");
341 // PrintBuffer (inToken, inTokenLength);
342 err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
347 gsscon_print_error (err, "gsscon_write_token failed");
350 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
355 /* --------------------------------------------------------------------------- */
356 /* Print BSD error */
358 void gsscon_print_error (int inError,
359 const char *inString)
361 fprintf (stderr, "%s: %s (err = %d)\n",
362 inString, error_message (inError), inError);
365 /* --------------------------------------------------------------------------- */
366 /* PrintGSSAPI errors */
368 void gsscon_print_gss_errors (const char *inRoutineName,
369 OM_uint32 inMajorStatus,
370 OM_uint32 inMinorStatus)
372 OM_uint32 minorStatus;
373 OM_uint32 majorStatus;
374 gss_buffer_desc errorBuffer;
376 OM_uint32 messageContext = 0; /* first message */
379 fprintf (stderr, "Error returned by %s:\n", inRoutineName);
382 majorStatus = gss_display_status (&minorStatus,
388 if (majorStatus == GSS_S_COMPLETE) {
389 fprintf (stderr," major error <%d> %s\n",
390 count, (char *) errorBuffer.value);
391 gss_release_buffer (&minorStatus, &errorBuffer);
394 } while (messageContext != 0);
399 majorStatus = gss_display_status (&minorStatus,
405 fprintf (stderr," minor error <%d> %s\n",
406 count, (char *) errorBuffer.value);
408 } while (messageContext != 0);