Update copyright date to 2012
[trust_router.git] / gsscon / gsscon_common.c
1 /*
2  * Copyright (c) 2012, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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.
32  *
33  * This code was adapted from the MIT Kerberos Consortium's
34  * GSS example code, which was distributed under the following
35  * license:
36  *
37  * Copyright 2004-2006 Massachusetts Institute of Technology.
38  * All Rights Reserved.
39  *
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.
53  */
54
55 #include <gsscon.h>
56
57 /* --------------------------------------------------------------------------- */
58 /* Display the contents of the buffer in hex and ascii                         */
59
60 static void PrintBuffer (const char *inBuffer, 
61                          size_t      inLength)
62 {
63     int i;  
64     
65     for (i = 0; i < inLength; i += 16) {
66         int l;
67         for (l = i; l < (i + 16); l++) {
68             if (l >= inLength) {
69                 printf ("  ");
70             } else {
71                 u_int8_t *byte = (u_int8_t *) inBuffer + l;
72                 printf ("%2.2x", *byte);
73             }
74             if ((l % 4) == 3) { printf (" "); }
75         }
76         printf ("   ");
77         for (l = i; l < (i + 16) && l < inLength; l++) {
78             printf ("%c", ((inBuffer[l] > 0x1f) && 
79                            (inBuffer[l] < 0x7f)) ? inBuffer[l] : '.');            
80         }
81         printf ("\n");
82     }
83     printf ("\n");
84 }
85
86 /* --------------------------------------------------------------------------- */
87 /* Standard network read loop, accounting for EINTR, EOF and incomplete reads  */
88
89 static int ReadBuffer (int     inSocket, 
90                        size_t  inBufferLength, 
91                        char   *ioBuffer)
92 {
93     int err = 0;
94     ssize_t bytesRead = 0;
95     
96     if (!ioBuffer) { err = EINVAL; }
97     
98     if (!err) {
99         char *ptr = ioBuffer;
100         do {
101             ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
102             if (count < 0) {
103                 /* Try again on EINTR */
104                 if (errno != EINTR) { err = errno; }
105             } else if (count == 0) {
106                 err = ECONNRESET; /* EOF and we expected data */
107             } else {
108                 ptr += count;
109                 bytesRead += count;
110             }
111         } while (!err && (bytesRead < inBufferLength));
112     } 
113     
114     if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
115
116     return err;
117 }
118
119 /* --------------------------------------------------------------------------- */
120 /* Standard network write loop, accounting for EINTR and incomplete writes     */
121
122 static int WriteBuffer (int         inSocket, 
123                         const char *inBuffer, 
124                         size_t      inBufferLength)
125 {
126     int err = 0;
127     ssize_t bytesWritten = 0;
128     
129     if (!inBuffer) { err = EINVAL; }
130     
131     if (!err) {
132         const char *ptr = inBuffer;
133         do {
134             ssize_t count = write (inSocket, ptr, inBufferLength - bytesWritten);
135             if (count < 0) {
136                 /* Try again on EINTR */
137                 if (errno != EINTR) { err = errno; }
138             } else {
139                 ptr += count;
140                 bytesWritten += count;
141             }
142         } while (!err && (bytesWritten < inBufferLength));
143     } 
144     
145     if (err) { gsscon_print_error (err, "WritBuffer failed"); }
146
147     return err;
148 }
149
150 /* --------------------------------------------------------------------------- */
151 /* Read a GSS token (length + data) off the network                            */
152
153 int gsscon_read_token (int      inSocket, 
154                char   **outTokenValue, 
155                size_t  *outTokenLength)
156 {
157     int err = 0;
158     char *token = NULL;
159     u_int32_t tokenLength = 0;
160     
161     if (!outTokenValue ) { err = EINVAL; }
162     if (!outTokenLength) { err = EINVAL; }
163     
164     if (!err) {
165         err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
166     }
167     
168     if (!err) {
169         tokenLength = ntohl (tokenLength);
170         token = malloc (tokenLength);
171         memset (token, 0, tokenLength); 
172         
173         err = ReadBuffer (inSocket, tokenLength, token);
174     }
175     
176     if (!err) {
177         printf ("Read token:\n");
178         PrintBuffer (token, tokenLength);
179         
180         *outTokenLength = tokenLength;
181         *outTokenValue = token;        
182         token = NULL; /* only free on error */
183     } else { 
184         gsscon_print_error (err, "ReadToken failed"); 
185     }
186
187     if (token) { free (token); }
188     
189     return err;
190 }
191
192 /* --------------------------------------------------------------------------- */
193 /* Write a GSS token (length + data) onto the network                          */
194
195 int gsscon_write_token (int         inSocket, 
196                 const char *inTokenValue, 
197                 size_t      inTokenLength)
198 {
199     int err = 0;
200     u_int32_t tokenLength = htonl (inTokenLength);
201
202     if (!inTokenValue) { err = EINVAL; }
203     
204     if (!err) {
205         err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
206     }
207         
208     if (!err) { 
209         err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
210     }
211     
212     if (!err) {
213         printf ("Wrote token:\n");
214         PrintBuffer (inTokenValue, inTokenLength);
215     } else { 
216         gsscon_print_error (err, "gsscon_write_token() failed");
217     }
218    
219     return err;
220 }
221
222 /* --------------------------------------------------------------------------- */
223 /* Read an encrypted GSS token (length + encrypted data) off the network       */
224
225
226 int gsscon_read_encrypted_token (int                  inSocket, 
227                         const gss_ctx_id_t   inContext, 
228                         char               **outTokenValue, 
229                         size_t              *outTokenLength)
230 {
231     int err = 0;
232     char *token = NULL;
233     size_t tokenLength = 0;
234     OM_uint32 majorStatus;
235     OM_uint32 minorStatus = 0;
236     gss_buffer_desc outputBuffer = { 0 , NULL};
237     char *unencryptedToken = NULL;
238     
239     if (!inContext     ) { err = EINVAL; }
240     if (!outTokenValue ) { err = EINVAL; }
241     if (!outTokenLength) { err = EINVAL; }
242     
243     if (!err) {
244         err = gsscon_read_token (inSocket, &token, &tokenLength);
245     }
246     
247     if (!err) {
248         gss_buffer_desc inputBuffer = { tokenLength, token};
249         int encrypted = 0; /* did mechanism encrypt/integrity protect? */
250
251         majorStatus = gss_unwrap (&minorStatus, 
252                                   inContext, 
253                                   &inputBuffer, 
254                                   &outputBuffer, 
255                                   &encrypted, 
256                                   NULL /* qop_state */);
257         if (majorStatus != GSS_S_COMPLETE) { 
258             gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
259             err = minorStatus ? minorStatus : majorStatus; 
260         } else if (!encrypted) {
261             fprintf (stderr, "WARNING!  Mechanism not using encryption!");
262             err = EINVAL; /* You may not want to fail here. */
263         }
264     }
265     
266     if (!err) {
267         unencryptedToken = malloc (outputBuffer.length);
268         if (unencryptedToken == NULL) { err = ENOMEM; }
269     }
270     
271     if (!err) {
272         memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
273         
274         printf ("Unencrypted token:\n");
275         PrintBuffer (unencryptedToken, outputBuffer.length);
276         
277         *outTokenLength = outputBuffer.length;
278         *outTokenValue = unencryptedToken;
279         unencryptedToken = NULL; /* only free on error */
280         
281     } else { 
282         gsscon_print_error (err, "ReadToken failed"); 
283     }
284     
285     if (token             ) { free (token); }
286     if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
287     if (unencryptedToken  ) { free (unencryptedToken); }
288     
289     return err;
290 }
291
292 /* --------------------------------------------------------------------------- */
293 /* Write an encrypted GSS token (length + encrypted data) onto the network     */
294
295 int gsscon_write_encrypted_token (int                 inSocket, 
296                          const gss_ctx_id_t  inContext, 
297                          const char         *inToken, 
298                          size_t              inTokenLength)
299 {
300     int err = 0;
301     OM_uint32 majorStatus;
302     OM_uint32 minorStatus = 0;
303     gss_buffer_desc outputBuffer = { 0, NULL };
304     
305     if (!inContext) { err = EINVAL; }
306     if (!inToken  ) { err = EINVAL; }
307     
308     if (!err) {
309         gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
310         int encrypt = 1;   /* do encryption and integrity protection */
311         int encrypted = 0; /* did mechanism encrypt/integrity protect? */
312         
313         majorStatus = gss_wrap (&minorStatus, 
314                                 inContext, 
315                                 encrypt, 
316                                 GSS_C_QOP_DEFAULT,
317                                 &inputBuffer, 
318                                 &encrypted, 
319                                 &outputBuffer);
320         if (majorStatus != GSS_S_COMPLETE) { 
321             gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
322             err = minorStatus ? minorStatus : majorStatus; 
323         } else if (!encrypted) {
324             fprintf (stderr, "WARNING!  Mechanism does not support encryption!");
325             err = EINVAL; /* You may not want to fail here. */
326         }
327     }
328     
329     if (!err) {
330         printf ("Unencrypted token:\n");
331         PrintBuffer (inToken, inTokenLength);
332         err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
333     }
334     
335     if (!err) {
336     } else { 
337         gsscon_print_error (err, "gsscon_write_token failed");
338     }
339     
340     if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
341     
342     return err;
343 }
344
345 /* --------------------------------------------------------------------------- */
346 /* Print BSD error                                                             */
347
348 void gsscon_print_error (int         inError, 
349                  const char *inString)
350 {
351     fprintf (stderr, "%s: %s (err = %d)\n", 
352              inString, error_message (inError), inError);
353 }
354
355 /* --------------------------------------------------------------------------- */
356 /* PrintGSSAPI errors                                                         */
357
358 void gsscon_print_gss_errors (const char *inRoutineName, 
359                      OM_uint32   inMajorStatus, 
360                      OM_uint32   inMinorStatus)
361 {
362     OM_uint32 minorStatus;
363     OM_uint32 majorStatus;      
364     gss_buffer_desc errorBuffer;
365
366     OM_uint32 messageContext = 0; /* first message */
367     int count = 1;
368     
369     fprintf (stderr, "Error returned by %s:\n", inRoutineName);
370     
371     do {
372         majorStatus = gss_display_status (&minorStatus, 
373                                           inMajorStatus, 
374                                           GSS_C_GSS_CODE, 
375                                           GSS_C_NULL_OID, 
376                                           &messageContext, 
377                                           &errorBuffer);
378         if (majorStatus == GSS_S_COMPLETE) {
379             fprintf (stderr,"      major error <%d> %s\n", 
380                      count, (char *) errorBuffer.value);
381             gss_release_buffer (&minorStatus, &errorBuffer);
382         }
383         ++count;
384     } while (messageContext != 0);
385     
386     count = 1;
387     messageContext = 0;
388     do {
389         majorStatus = gss_display_status (&minorStatus, 
390                                           inMinorStatus, 
391                                           GSS_C_MECH_CODE, 
392                                           GSS_C_NULL_OID, 
393                                           &messageContext, 
394                                           &errorBuffer);
395         fprintf (stderr,"      minor error <%d> %s\n", 
396                  count, (char *) errorBuffer.value);
397         ++count;
398     } while (messageContext != 0);
399 }
400