Bump versions to 1.5.2 in a couple places.
[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 <signal.h>
56
57 #include <gsscon.h>
58
59 /* --------------------------------------------------------------------------- */
60 /* Display the contents of the buffer in hex and ascii                         */
61
62 static void PrintBuffer (const char *inBuffer, 
63                          size_t      inLength)
64 {
65     int i;  
66     
67     for (i = 0; i < inLength; i += 16) {
68         int l;
69         for (l = i; l < (i + 16); l++) {
70             if (l >= inLength) {
71                 printf ("  ");
72             } else {
73                 u_int8_t *byte = (u_int8_t *) inBuffer + l;
74                 printf ("%2.2x", *byte);
75             }
76             if ((l % 4) == 3) { printf (" "); }
77         }
78         printf ("   ");
79         for (l = i; l < (i + 16) && l < inLength; l++) {
80             printf ("%c", ((inBuffer[l] > 0x1f) && 
81                            (inBuffer[l] < 0x7f)) ? inBuffer[l] : '.');            
82         }
83         printf ("\n");
84     }
85     printf ("\n");
86 }
87
88 /* --------------------------------------------------------------------------- */
89 /* Standard network read loop, accounting for EINTR, EOF and incomplete reads  */
90
91 static int ReadBuffer (int     inSocket, 
92                        size_t  inBufferLength, 
93                        char   *ioBuffer)
94 {
95     int err = 0;
96     ssize_t bytesRead = 0;
97     
98     if (!ioBuffer) { err = EINVAL; }
99     
100     if (!err) {
101         char *ptr = ioBuffer;
102         do {
103             ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
104             if (count < 0) {
105                 /* Try again on EINTR */
106                 if (errno != EINTR) { err = errno; }
107             } else if (count == 0) {
108                 err = ECONNRESET; /* EOF and we expected data */
109             } else {
110                 ptr += count;
111                 bytesRead += count;
112             }
113         } while (!err && (bytesRead < inBufferLength));
114     } 
115     
116     if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
117
118     return err;
119 }
120
121 /* --------------------------------------------------------------------------- */
122 /* Standard network write loop, accounting for EINTR and incomplete writes     */
123
124 static int WriteBuffer (int         inSocket, 
125                         const char *inBuffer, 
126                         size_t      inBufferLength)
127 {
128     int err = 0;
129     ssize_t bytesWritten = 0;
130     
131     if (!inBuffer) { err = EINVAL; }
132     
133     if (!err) {
134         const char *ptr = inBuffer;
135         do {
136             ssize_t count;
137
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 */
143
144             if (count < 0) {
145                 /* Try again on EINTR */
146                 if (errno != EINTR) { err = errno; }
147             } else {
148                 ptr += count;
149                 bytesWritten += count;
150             }
151         } while (!err && (bytesWritten < inBufferLength));
152     } 
153     
154     if (err) { gsscon_print_error (err, "WriteBuffer failed"); }
155
156     return err;
157 }
158
159 /* --------------------------------------------------------------------------- */
160 /* Read a GSS token (length + data) off the network                            */
161
162 int gsscon_read_token (int      inSocket, 
163                char   **outTokenValue, 
164                size_t  *outTokenLength)
165 {
166     int err = 0;
167     char *token = NULL;
168     u_int32_t tokenLength = 0;
169     
170     if (!outTokenValue ) { err = EINVAL; }
171     if (!outTokenLength) { err = EINVAL; }
172     
173     if (!err) {
174         err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
175     }
176     
177     if (!err) {
178         tokenLength = ntohl (tokenLength);
179         token = malloc (tokenLength);
180         memset (token, 0, tokenLength); 
181         
182         err = ReadBuffer (inSocket, tokenLength, token);
183     }
184     
185     if (!err) {
186     //    printf ("Read token:\n");
187     //    PrintBuffer (token, tokenLength);
188         
189         *outTokenLength = tokenLength;
190         *outTokenValue = token;        
191         token = NULL; /* only free on error */
192     } else { 
193         gsscon_print_error (err, "ReadToken failed"); 
194     }
195
196     if (token) { free (token); }
197     
198     return err;
199 }
200
201 /* --------------------------------------------------------------------------- */
202 /* Write a GSS token (length + data) onto the network                          */
203
204 int gsscon_write_token (int         inSocket, 
205                 const char *inTokenValue, 
206                 size_t      inTokenLength)
207 {
208     int err = 0;
209     u_int32_t tokenLength = htonl (inTokenLength);
210
211     if (!inTokenValue) { err = EINVAL; }
212     
213     if (!err) {
214         err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
215     }
216         
217     if (!err) { 
218         err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
219     }
220     
221     if (!err) {
222     //    printf ("Wrote token:\n");
223     //    PrintBuffer (inTokenValue, inTokenLength);
224
225     } else { 
226         gsscon_print_error (err, "gsscon_write_token() failed");
227     }
228    
229     return err;
230 }
231
232 /* --------------------------------------------------------------------------- */
233 /* Read an encrypted GSS token (length + encrypted data) off the network       */
234
235
236 int gsscon_read_encrypted_token (int                  inSocket, 
237                         const gss_ctx_id_t   inContext, 
238                         char               **outTokenValue, 
239                         size_t              *outTokenLength)
240 {
241     int err = 0;
242     char *token = NULL;
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;
248     
249     if (!inContext     ) { err = EINVAL; }
250     if (!outTokenValue ) { err = EINVAL; }
251     if (!outTokenLength) { err = EINVAL; }
252     
253     if (!err) {
254         err = gsscon_read_token (inSocket, &token, &tokenLength);
255     }
256     
257     if (!err) {
258         gss_buffer_desc inputBuffer = { tokenLength, token};
259         int encrypted = 0; /* did mechanism encrypt/integrity protect? */
260
261         majorStatus = gss_unwrap (&minorStatus, 
262                                   inContext, 
263                                   &inputBuffer, 
264                                   &outputBuffer, 
265                                   &encrypted, 
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. */
273         }
274     }
275     
276     if (!err) {
277         unencryptedToken = malloc (outputBuffer.length);
278         if (unencryptedToken == NULL) { err = ENOMEM; }
279     }
280     
281     if (!err) {
282         memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
283         
284         // printf ("Unencrypted token:\n");
285         // PrintBuffer (unencryptedToken, outputBuffer.length);
286         
287         *outTokenLength = outputBuffer.length;
288         *outTokenValue = unencryptedToken;
289         unencryptedToken = NULL; /* only free on error */
290         
291     } else { 
292         gsscon_print_error (err, "ReadToken failed"); 
293     }
294     
295     if (token             ) { free (token); }
296     if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
297     if (unencryptedToken  ) { free (unencryptedToken); }
298     
299     return err;
300 }
301
302 /* --------------------------------------------------------------------------- */
303 /* Write an encrypted GSS token (length + encrypted data) onto the network     */
304
305 int gsscon_write_encrypted_token (int                 inSocket, 
306                          const gss_ctx_id_t  inContext, 
307                          const char         *inToken, 
308                          size_t              inTokenLength)
309 {
310     int err = 0;
311     OM_uint32 majorStatus;
312     OM_uint32 minorStatus = 0;
313     gss_buffer_desc outputBuffer = { 0, NULL };
314     
315     if (!inContext) { err = EINVAL; }
316     if (!inToken  ) { err = EINVAL; }
317     
318     if (!err) {
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? */
322         
323         majorStatus = gss_wrap (&minorStatus, 
324                                 inContext, 
325                                 encrypt, 
326                                 GSS_C_QOP_DEFAULT,
327                                 &inputBuffer, 
328                                 &encrypted, 
329                                 &outputBuffer);
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. */
336         }
337     }
338     
339     if (!err) {
340       //  printf ("Unencrypted token:\n");
341       //  PrintBuffer (inToken, inTokenLength);
342         err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
343     }
344     
345     if (!err) {
346     } else { 
347         gsscon_print_error (err, "gsscon_write_token failed");
348     }
349     
350     if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
351     
352     return err;
353 }
354
355 /* --------------------------------------------------------------------------- */
356 /* Print BSD error                                                             */
357
358 void gsscon_print_error (int         inError, 
359                  const char *inString)
360 {
361     fprintf (stderr, "%s: %s (err = %d)\n", 
362              inString, error_message (inError), inError);
363 }
364
365 /* --------------------------------------------------------------------------- */
366 /* PrintGSSAPI errors                                                         */
367
368 void gsscon_print_gss_errors (const char *inRoutineName, 
369                      OM_uint32   inMajorStatus, 
370                      OM_uint32   inMinorStatus)
371 {
372     OM_uint32 minorStatus;
373     OM_uint32 majorStatus;      
374     gss_buffer_desc errorBuffer;
375
376     OM_uint32 messageContext = 0; /* first message */
377     int count = 1;
378     
379     fprintf (stderr, "Error returned by %s:\n", inRoutineName);
380     
381     do {
382         majorStatus = gss_display_status (&minorStatus, 
383                                           inMajorStatus, 
384                                           GSS_C_GSS_CODE, 
385                                           GSS_C_NULL_OID, 
386                                           &messageContext, 
387                                           &errorBuffer);
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);
392         }
393         ++count;
394     } while (messageContext != 0);
395     
396     count = 1;
397     messageContext = 0;
398     do {
399         majorStatus = gss_display_status (&minorStatus, 
400                                           inMinorStatus, 
401                                           GSS_C_MECH_CODE, 
402                                           GSS_C_NULL_OID, 
403                                           &messageContext, 
404                                           &errorBuffer);
405         fprintf (stderr,"      minor error <%d> %s\n", 
406                  count, (char *) errorBuffer.value);
407         ++count;
408     } while (messageContext != 0);
409 }
410