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 #define READBUFFER_TIMEOUT_SECONDS (60 * 1000)
92 static int ReadBuffer (int inSocket,
93 size_t inBufferLength,
97 ssize_t bytesRead = 0;
99 if (!ioBuffer) { err = EINVAL; }
101 /* Read in non-blocking mode */
103 err = fcntl(inSocket, F_SETFL, O_NONBLOCK);
107 char *ptr = ioBuffer;
110 struct pollfd fds = {inSocket, POLLIN, 0}; /* poll for data ready on the socket */
113 poll_rc = poll(&fds, 1, READBUFFER_TIMEOUT_SECONDS);
118 } else if (poll_rc < 0) {
119 /* try again if we were interrupted, otherwise exit */
120 if (errno != EINTR) {
126 /* Data should be ready to read */
127 count = read (inSocket, ptr, inBufferLength - bytesRead);
129 /* Try again on EINTR (if we get EAGAIN or EWOULDBLOCK, something is wrong because
130 * we just polled the fd) */
131 if (errno != EINTR) { err = errno; }
132 } else if (count == 0) {
133 err = ECONNRESET; /* EOF and we expected data */
138 } while (!err && (bytesRead < inBufferLength));
141 if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
146 /* --------------------------------------------------------------------------- */
147 /* Standard network write loop, accounting for EINTR and incomplete writes */
149 static int WriteBuffer (int inSocket,
150 const char *inBuffer,
151 size_t inBufferLength)
154 ssize_t bytesWritten = 0;
156 if (!inBuffer) { err = EINVAL; }
159 const char *ptr = inBuffer;
163 count = write (inSocket, ptr, inBufferLength - bytesWritten);
166 /* Try again on EINTR */
167 if (errno != EINTR) { err = errno; }
170 bytesWritten += count;
172 } while (!err && (bytesWritten < inBufferLength));
175 if (err) { gsscon_print_error (err, "WriteBuffer failed"); }
180 /* --------------------------------------------------------------------------- */
181 /* Read a GSS token (length + data) off the network */
183 int gsscon_read_token (int inSocket,
184 char **outTokenValue,
185 size_t *outTokenLength)
189 u_int32_t tokenLength = 0;
191 if (!outTokenValue ) { err = EINVAL; }
192 if (!outTokenLength) { err = EINVAL; }
195 err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
199 tokenLength = ntohl (tokenLength);
200 token = malloc (tokenLength);
204 memset (token, 0, tokenLength);
206 err = ReadBuffer (inSocket, tokenLength, token);
211 *outTokenLength = tokenLength;
212 *outTokenValue = token;
213 token = NULL; /* only free on error */
215 gsscon_print_error (err, "ReadToken failed");
218 if (token) { free (token); }
223 /* --------------------------------------------------------------------------- */
224 /* Write a GSS token (length + data) onto the network */
226 int gsscon_write_token (int inSocket,
227 const char *inTokenValue,
228 size_t inTokenLength)
231 u_int32_t tokenLength = htonl (inTokenLength);
233 if (!inTokenValue) { err = EINVAL; }
236 err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
240 err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
244 // printf ("Wrote token:\n");
245 // PrintBuffer (inTokenValue, inTokenLength);
248 gsscon_print_error (err, "gsscon_write_token() failed");
254 /* --------------------------------------------------------------------------- */
255 /* Read an encrypted GSS token (length + encrypted data) off the network */
258 int gsscon_read_encrypted_token (int inSocket,
259 const gss_ctx_id_t inContext,
260 char **outTokenValue,
261 size_t *outTokenLength)
265 size_t tokenLength = 0;
266 OM_uint32 majorStatus;
267 OM_uint32 minorStatus = 0;
268 gss_buffer_desc outputBuffer = { 0 , NULL};
269 char *unencryptedToken = NULL;
271 if (!inContext ) { err = EINVAL; }
272 if (!outTokenValue ) { err = EINVAL; }
273 if (!outTokenLength) { err = EINVAL; }
276 err = gsscon_read_token (inSocket, &token, &tokenLength);
280 gss_buffer_desc inputBuffer = { tokenLength, token};
281 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
283 majorStatus = gss_unwrap (&minorStatus,
288 NULL /* qop_state */);
289 if (majorStatus != GSS_S_COMPLETE) {
290 gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
291 err = minorStatus ? minorStatus : majorStatus;
292 } else if (!encrypted) {
293 fprintf (stderr, "WARNING! Mechanism not using encryption!");
294 err = EINVAL; /* You may not want to fail here. */
299 unencryptedToken = malloc (outputBuffer.length);
300 if (unencryptedToken == NULL) { err = ENOMEM; }
304 memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
306 // printf ("Unencrypted token:\n");
307 // PrintBuffer (unencryptedToken, outputBuffer.length);
309 *outTokenLength = outputBuffer.length;
310 *outTokenValue = unencryptedToken;
311 unencryptedToken = NULL; /* only free on error */
314 gsscon_print_error (err, "ReadToken failed");
317 if (token ) { free (token); }
318 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
319 if (unencryptedToken ) { free (unencryptedToken); }
324 /* --------------------------------------------------------------------------- */
325 /* Write an encrypted GSS token (length + encrypted data) onto the network */
327 int gsscon_write_encrypted_token (int inSocket,
328 const gss_ctx_id_t inContext,
330 size_t inTokenLength)
333 OM_uint32 majorStatus;
334 OM_uint32 minorStatus = 0;
335 gss_buffer_desc outputBuffer = { 0, NULL };
337 if (!inContext) { err = EINVAL; }
338 if (!inToken ) { err = EINVAL; }
341 gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
342 int encrypt = 1; /* do encryption and integrity protection */
343 int encrypted = 0; /* did mechanism encrypt/integrity protect? */
345 majorStatus = gss_wrap (&minorStatus,
352 if (majorStatus != GSS_S_COMPLETE) {
353 gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
354 err = minorStatus ? minorStatus : majorStatus;
355 } else if (!encrypted) {
356 fprintf (stderr, "WARNING! Mechanism does not support encryption!");
357 err = EINVAL; /* You may not want to fail here. */
362 // printf ("Unencrypted token:\n");
363 // PrintBuffer (inToken, inTokenLength);
364 err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
369 gsscon_print_error (err, "gsscon_write_token failed");
372 if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
377 /* --------------------------------------------------------------------------- */
378 /* Print BSD error */
380 void gsscon_print_error (int inError,
381 const char *inString)
383 fprintf (stderr, "%s: %s (err = %d)\n",
384 inString, error_message (inError), inError);
387 /* --------------------------------------------------------------------------- */
388 /* PrintGSSAPI errors */
390 void gsscon_print_gss_errors (const char *inRoutineName,
391 OM_uint32 inMajorStatus,
392 OM_uint32 inMinorStatus)
394 OM_uint32 minorStatus;
395 OM_uint32 majorStatus;
396 gss_buffer_desc errorBuffer;
398 OM_uint32 messageContext = 0; /* first message */
401 fprintf (stderr, "Error returned by %s:\n", inRoutineName);
404 majorStatus = gss_display_status (&minorStatus,
410 if (majorStatus == GSS_S_COMPLETE) {
411 fprintf (stderr," major error <%d> %s\n",
412 count, (char *) errorBuffer.value);
413 gss_release_buffer (&minorStatus, &errorBuffer);
416 } while (messageContext != 0);
421 majorStatus = gss_display_status (&minorStatus,
427 fprintf (stderr," minor error <%d> %s\n",
428 count, (char *) errorBuffer.value);
430 } while (messageContext != 0);