1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1994 by OpenVision Technologies, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name of OpenVision not be used
10 * in advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. OpenVision makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23 /*
24 * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology.
25 * All rights reserved.
26 *
27 * Export of this software from the United States of America may
28 * require a specific license from the United States Government.
29 * It is the responsibility of any person or organization contemplating
30 * export to obtain such a license before exporting.
31 *
32 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
33 * distribute this software and its documentation for any purpose and
34 * without fee is hereby granted, provided that the above copyright
35 * notice appear in all copies and that both that copyright notice and
36 * this permission notice appear in supporting documentation, and that
37 * the name of M.I.T. not be used in advertising or publicity pertaining
38 * to distribution of the software without specific, written prior
39 * permission. Furthermore if you modify this software you must label
40 * your software as modified software and not distribute it in such a
41 * fashion that it might be confused with the original M.I.T. software.
42 * M.I.T. makes no representations about the suitability of
43 * this software for any purpose. It is provided "as is" without express
44 * or implied warranty.
45 */
46
47 #include "autoconf.h"
48 #include <stdio.h>
49 #ifdef _WIN32
50 #include <windows.h>
51 #include <winsock.h>
52 #else
53 #include <sys/types.h>
54 #include <netinet/in.h>
55 #include <sys/socket.h>
56 #endif
57 #include <errno.h>
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #include <string.h>
62
63 /* need struct timeval */
64 #include <time.h>
65 #if HAVE_SYS_TIME_H
66 #include <sys/time.h>
67 #endif
68
69 #include <gssapi/gssapi_generic.h>
70 #include "gss-misc.h"
71 /* for store_32_be */
72 #include "k5-platform.h"
73
74 #ifdef HAVE_STDLIB_H
75 #include <stdlib.h>
76 #else
77 extern char *malloc();
78 #endif
79
80 FILE *display_file;
81
82 gss_buffer_desc empty_token_buf = { 0, (void *)"" };
83 gss_buffer_t empty_token = &empty_token_buf;
84
85 static void display_status_1(char *m, OM_uint32 code, int type);
86
87 static int
write_all(int fildes,char * buf,unsigned int nbyte)88 write_all(int fildes, char *buf, unsigned int nbyte)
89 {
90 int ret;
91 char *ptr;
92
93 for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
94 ret = send(fildes, ptr, nbyte, 0);
95 if (ret < 0) {
96 if (errno == EINTR)
97 continue;
98 return ret;
99 } else if (ret == 0) {
100 return ptr - buf;
101 }
102 }
103
104 return ptr - buf;
105 }
106
107 static int
read_all(int fildes,char * buf,unsigned int nbyte)108 read_all(int fildes, char *buf, unsigned int nbyte)
109 {
110 int ret;
111 char *ptr;
112 fd_set rfds;
113 struct timeval tv;
114
115 FD_ZERO(&rfds);
116 FD_SET(fildes, &rfds);
117 tv.tv_sec = 10;
118 tv.tv_usec = 0;
119
120 for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
121 if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0 ||
122 !FD_ISSET(fildes, &rfds))
123 return ptr - buf;
124 ret = recv(fildes, ptr, nbyte, 0);
125 if (ret < 0) {
126 if (errno == EINTR)
127 continue;
128 return ret;
129 } else if (ret == 0) {
130 return ptr - buf;
131 }
132 }
133
134 return ptr - buf;
135 }
136
137 /*
138 * Function: send_token
139 *
140 * Purpose: Writes a token to a file descriptor.
141 *
142 * Arguments:
143 *
144 * s (r) an open file descriptor
145 * flags (r) the flags to write
146 * tok (r) the token to write
147 *
148 * Returns: 0 on success, -1 on failure
149 *
150 * Effects:
151 *
152 * If the flags are non-null, send_token writes the token flags (a
153 * single byte, even though they're passed in in an integer). Next,
154 * the token length (as a network long) and then the token data are
155 * written to the file descriptor s. It returns 0 on success, and -1
156 * if an error occurs or if it could not write all the data.
157 */
158 int
send_token(int s,int flags,gss_buffer_t tok)159 send_token(int s, int flags, gss_buffer_t tok)
160 {
161 int ret;
162 unsigned char char_flags = (unsigned char)flags;
163 unsigned char lenbuf[4];
164
165 if (char_flags) {
166 ret = write_all(s, (char *)&char_flags, 1);
167 if (ret != 1) {
168 perror("sending token flags");
169 return -1;
170 }
171 }
172 if (tok->length > 0xffffffffUL)
173 abort();
174 store_32_be(tok->length, lenbuf);
175 ret = write_all(s, (char *)lenbuf, 4);
176 if (ret < 0) {
177 perror("sending token length");
178 return -1;
179 } else if (ret != 4) {
180 if (display_file) {
181 fprintf(display_file,
182 "sending token length: %d of %d bytes written\n", ret, 4);
183 }
184 return -1;
185 }
186
187 ret = write_all(s, tok->value, tok->length);
188 if (ret < 0) {
189 perror("sending token data");
190 return -1;
191 } else if ((size_t)ret != tok->length) {
192 if (display_file) {
193 fprintf(display_file,
194 "sending token data: %d of %d bytes written\n",
195 ret, (int)tok->length);
196 }
197 return -1;
198 }
199
200 return 0;
201 }
202
203 /*
204 * Function: recv_token
205 *
206 * Purpose: Reads a token from a file descriptor.
207 *
208 * Arguments:
209 *
210 * s (r) an open file descriptor
211 * flags (w) the read flags
212 * tok (w) the read token
213 *
214 * Returns: 0 on success, -1 on failure
215 *
216 * Effects:
217 *
218 * recv_token reads the token flags (a single byte, even though
219 * they're stored into an integer, then reads the token length (as a
220 * network long), allocates memory to hold the data, and then reads
221 * the token data from the file descriptor s. It blocks to read the
222 * length and data, if necessary. On a successful return, the token
223 * should be freed with gss_release_buffer. It returns 0 on success,
224 * and -1 if an error occurs or if it could not read all the data.
225 */
226 int
recv_token(int s,int * flags,gss_buffer_t tok)227 recv_token(int s, int *flags, gss_buffer_t tok)
228 {
229 int ret;
230 unsigned char char_flags;
231 unsigned char lenbuf[4];
232
233 ret = read_all(s, (char *)&char_flags, 1);
234 if (ret < 0) {
235 perror("reading token flags");
236 return -1;
237 } else if (!ret) {
238 if (display_file)
239 fputs("reading token flags: 0 bytes read\n", display_file);
240 return -1;
241 } else {
242 *flags = char_flags;
243 }
244
245 if (char_flags == 0) {
246 lenbuf[0] = 0;
247 ret = read_all(s, (char *)&lenbuf[1], 3);
248 if (ret < 0) {
249 perror("reading token length");
250 return -1;
251 } else if (ret != 3) {
252 if (display_file) {
253 fprintf(display_file,
254 "reading token length: %d of %d bytes read\n", ret, 3);
255 }
256 return -1;
257 }
258 } else {
259 ret = read_all(s, (char *)lenbuf, 4);
260 if (ret < 0) {
261 perror("reading token length");
262 return -1;
263 } else if (ret != 4) {
264 if (display_file) {
265 fprintf(display_file,
266 "reading token length: %d of %d bytes read\n", ret, 4);
267 }
268 return -1;
269 }
270 }
271
272 tok->length = load_32_be(lenbuf);
273 tok->value = malloc(tok->length ? tok->length : 1);
274 if (tok->length && tok->value == NULL) {
275 if (display_file)
276 fprintf(display_file, "Out of memory allocating token data\n");
277 return -1;
278 }
279
280 ret = read_all(s, (char *)tok->value, tok->length);
281 if (ret < 0) {
282 perror("reading token data");
283 free(tok->value);
284 return -1;
285 } else if ((size_t)ret != tok->length) {
286 fprintf(stderr, "sending token data: %d of %d bytes written\n",
287 ret, (int)tok->length);
288 free(tok->value);
289 return -1;
290 }
291
292 return 0;
293 }
294
295 static void
display_status_1(char * m,OM_uint32 code,int type)296 display_status_1(char *m, OM_uint32 code, int type)
297 {
298 OM_uint32 min_stat;
299 gss_buffer_desc msg;
300 OM_uint32 msg_ctx;
301
302 msg_ctx = 0;
303 while (1) {
304 (void)gss_display_status(&min_stat, code, type, GSS_C_NULL_OID,
305 &msg_ctx, &msg);
306 if (display_file) {
307 fprintf(display_file, "GSS-API error %s: %s\n", m,
308 (char *)msg.value);
309 }
310 (void)gss_release_buffer(&min_stat, &msg);
311
312 if (!msg_ctx)
313 break;
314 }
315 }
316
317 /*
318 * Function: display_status
319 *
320 * Purpose: displays GSS-API messages
321 *
322 * Arguments:
323 *
324 * msg a string to be displayed with the message
325 * maj_stat the GSS-API major status code
326 * min_stat the GSS-API minor status code
327 *
328 * Effects:
329 *
330 * The GSS-API messages associated with maj_stat and min_stat are
331 * displayed on stderr, each preceded by "GSS-API error <msg>: " and
332 * followed by a newline.
333 */
334 void
display_status(char * msg,OM_uint32 maj_stat,OM_uint32 min_stat)335 display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
336 {
337 display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
338 display_status_1(msg, min_stat, GSS_C_MECH_CODE);
339 }
340
341 /*
342 * Function: display_ctx_flags
343 *
344 * Purpose: displays the flags returned by context initiation in
345 * a human-readable form
346 *
347 * Arguments:
348 *
349 * int ret_flags
350 *
351 * Effects:
352 *
353 * Strings corresponding to the context flags are printed on
354 * stdout, preceded by "context flag: " and followed by a newline
355 */
356
357 void
display_ctx_flags(OM_uint32 flags)358 display_ctx_flags(OM_uint32 flags)
359 {
360 if (flags & GSS_C_DELEG_FLAG)
361 fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n");
362 if (flags & GSS_C_MUTUAL_FLAG)
363 fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n");
364 if (flags & GSS_C_REPLAY_FLAG)
365 fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n");
366 if (flags & GSS_C_SEQUENCE_FLAG)
367 fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n");
368 if (flags & GSS_C_CONF_FLAG)
369 fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n");
370 if (flags & GSS_C_INTEG_FLAG)
371 fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n");
372 }
373
374 void
print_token(gss_buffer_t tok)375 print_token(gss_buffer_t tok)
376 {
377 size_t i;
378 unsigned char *p = tok->value;
379
380 if (!display_file)
381 return;
382 for (i = 0; i < tok->length; i++, p++) {
383 fprintf(display_file, "%02x ", *p);
384 if (i % 16 == 15) {
385 fprintf(display_file, "\n");
386 }
387 }
388 fprintf(display_file, "\n");
389 fflush(display_file);
390 }
391
392 #ifdef _WIN32
393 #include <sys\timeb.h>
394 #include <time.h>
395
396 int
gettimeofday(struct timeval * tv,void * ignore_tz)397 gettimeofday(struct timeval *tv, void *ignore_tz)
398 {
399 struct _timeb tb;
400
401 _tzset();
402 _ftime(&tb);
403 if (tv) {
404 tv->tv_sec = tb.time;
405 tv->tv_usec = tb.millitm * 1000;
406 }
407 return 0;
408 }
409
410 #endif /* _WIN32 */
411