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 49 #include <stdio.h> 50 #ifdef _WIN32 51 #include <windows.h> 52 #include <winsock.h> 53 #else 54 #include <sys/types.h> 55 #include <netinet/in.h> 56 #include <sys/socket.h> 57 #endif 58 #include <errno.h> 59 60 #ifdef HAVE_UNISTD_H 61 #include <unistd.h> 62 #endif 63 #include <string.h> 64 65 /* need struct timeval */ 66 #ifdef HAVE_SYS_TIME_H 67 #include <sys/time.h> 68 #else 69 #include <time.h> 70 #endif 71 72 #include <gssapi/gssapi_generic.h> 73 #include "gss-misc.h" 74 75 #ifdef HAVE_STDLIB_H 76 #include <stdlib.h> 77 #else 78 extern char *malloc(); 79 #endif 80 81 FILE *display_file; 82 83 gss_buffer_desc empty_token_buf = { 0, (void *) "" }; 84 gss_buffer_t empty_token = &empty_token_buf; 85 86 static void display_status_1(char *m, OM_uint32 code, int type); 87 88 static int 89 write_all(int fildes, const void *data, unsigned int nbyte) 90 { 91 int ret; 92 const char *ptr, *buf = data; 93 94 for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { 95 ret = send(fildes, ptr, nbyte, 0); 96 if (ret < 0) { 97 if (errno == EINTR) 98 continue; 99 return (ret); 100 } else if (ret == 0) { 101 return (ptr - buf); 102 } 103 } 104 105 return (ptr - buf); 106 } 107 108 static int 109 read_all(int fildes, void *data, unsigned int nbyte) 110 { 111 int ret; 112 char *ptr, *buf = data; 113 fd_set rfds; 114 struct timeval tv; 115 116 FD_ZERO(&rfds); 117 FD_SET(fildes, &rfds); 118 tv.tv_sec = 300; 119 tv.tv_usec = 0; 120 121 for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { 122 if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0 123 || !FD_ISSET(fildes, &rfds)) 124 return (ptr - buf); 125 ret = recv(fildes, ptr, nbyte, 0); 126 if (ret < 0) { 127 if (errno == EINTR) 128 continue; 129 return (ret); 130 } else if (ret == 0) { 131 return (ptr - buf); 132 } 133 } 134 135 return (ptr - buf); 136 } 137 138 /* 139 * Function: send_token 140 * 141 * Purpose: Writes a token to a file descriptor. 142 * 143 * Arguments: 144 * 145 * s (r) an open file descriptor 146 * flags (r) the flags to write 147 * tok (r) the token to write 148 * 149 * Returns: 0 on success, -1 on failure 150 * 151 * Effects: 152 * 153 * If the flags are non-null, send_token writes the token flags (a 154 * single byte, even though they're passed in in an integer). Next, 155 * the token length (as a network long) and then the token data are 156 * written to the file descriptor s. It returns 0 on success, and -1 157 * if an error occurs or if it could not write all the data. 158 */ 159 int 160 send_token(int s, int flags, gss_buffer_t tok) 161 { 162 int ret; 163 unsigned char char_flags = (unsigned char) flags; 164 unsigned char lenbuf[4]; 165 166 if (char_flags) { 167 ret = write_all(s, (char *) &char_flags, 1); 168 if (ret != 1) { 169 perror("sending token flags"); 170 return -1; 171 } 172 } 173 if (tok->length > 0xffffffffUL) 174 abort(); 175 lenbuf[0] = (tok->length >> 24) & 0xff; 176 lenbuf[1] = (tok->length >> 16) & 0xff; 177 lenbuf[2] = (tok->length >> 8) & 0xff; 178 lenbuf[3] = tok->length & 0xff; 179 180 ret = write_all(s, lenbuf, 4); 181 if (ret < 0) { 182 perror("sending token length"); 183 return -1; 184 } else if (ret != 4) { 185 if (display_file) 186 fprintf(display_file, 187 "sending token length: %d of %d bytes written\n", ret, 4); 188 return -1; 189 } 190 191 ret = write_all(s, tok->value, tok->length); 192 if (ret < 0) { 193 perror("sending token data"); 194 return -1; 195 } else if ((size_t)ret != tok->length) { 196 if (display_file) 197 fprintf(display_file, 198 "sending token data: %d of %d bytes written\n", 199 ret, (int) tok->length); 200 return -1; 201 } 202 203 return 0; 204 } 205 206 /* 207 * Function: recv_token 208 * 209 * Purpose: Reads a token from a file descriptor. 210 * 211 * Arguments: 212 * 213 * s (r) an open file descriptor 214 * flags (w) the read flags 215 * tok (w) the read token 216 * 217 * Returns: 0 on success, -1 on failure 218 * 219 * Effects: 220 * 221 * recv_token reads the token flags (a single byte, even though 222 * they're stored into an integer, then reads the token length (as a 223 * network long), allocates memory to hold the data, and then reads 224 * the token data from the file descriptor s. It blocks to read the 225 * length and data, if necessary. On a successful return, the token 226 * should be freed with gss_release_buffer. It returns 0 on success, 227 * and -1 if an error occurs or if it could not read all the data. 228 */ 229 int 230 recv_token(int s, int *flags, gss_buffer_t tok) 231 { 232 int ret; 233 unsigned char char_flags; 234 unsigned char lenbuf[4]; 235 236 ret = read_all(s, (char *) &char_flags, 1); 237 if (ret < 0) { 238 perror("reading token flags"); 239 return -1; 240 } else if (!ret) { 241 if (display_file) 242 fputs("reading token flags: 0 bytes read\n", display_file); 243 return -1; 244 } else { 245 *flags = (int) char_flags; 246 } 247 248 if (char_flags == 0) { 249 lenbuf[0] = 0; 250 ret = read_all(s, &lenbuf[1], 3); 251 if (ret < 0) { 252 perror("reading token length"); 253 return -1; 254 } else if (ret != 3) { 255 if (display_file) 256 fprintf(display_file, 257 "reading token length: %d of %d bytes read\n", ret, 3); 258 return -1; 259 } 260 } else { 261 ret = read_all(s, lenbuf, 4); 262 if (ret < 0) { 263 perror("reading token length"); 264 return -1; 265 } else if (ret != 4) { 266 if (display_file) 267 fprintf(display_file, 268 "reading token length: %d of %d bytes read\n", ret, 4); 269 return -1; 270 } 271 } 272 273 tok->length = ((lenbuf[0] << 24) 274 | (lenbuf[1] << 16) 275 | (lenbuf[2] << 8) 276 | lenbuf[3]); 277 tok->value = (char *) malloc(tok->length ? tok->length : 1); 278 if (tok->length && tok->value == NULL) { 279 if (display_file) 280 fprintf(display_file, "Out of memory allocating token data\n"); 281 return -1; 282 } 283 284 ret = read_all(s, (char *) tok->value, tok->length); 285 if (ret < 0) { 286 perror("reading token data"); 287 free(tok->value); 288 return -1; 289 } else if ((size_t)ret != tok->length) { 290 fprintf(stderr, "sending token data: %d of %d bytes written\n", 291 ret, (int) tok->length); 292 free(tok->value); 293 return -1; 294 } 295 296 return 0; 297 } 298 299 static void 300 display_status_1(char *m, OM_uint32 code, int type) 301 { 302 OM_uint32 min_stat; 303 gss_buffer_desc msg; 304 OM_uint32 msg_ctx; 305 306 msg_ctx = 0; 307 while (1) { 308 (void) gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, 309 &msg_ctx, &msg); 310 if (display_file) 311 fprintf(display_file, "GSS-API error %s: %s\n", m, 312 (char *) msg.value); 313 (void) gss_release_buffer(&min_stat, &msg); 314 315 if (!msg_ctx) 316 break; 317 } 318 } 319 320 /* 321 * Function: display_status 322 * 323 * Purpose: displays GSS-API messages 324 * 325 * Arguments: 326 * 327 * msg a string to be displayed with the message 328 * maj_stat the GSS-API major status code 329 * min_stat the GSS-API minor status code 330 * 331 * Effects: 332 * 333 * The GSS-API messages associated with maj_stat and min_stat are 334 * displayed on stderr, each preceded by "GSS-API error <msg>: " and 335 * followed by a newline. 336 */ 337 void 338 display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) 339 { 340 display_status_1(msg, maj_stat, GSS_C_GSS_CODE); 341 display_status_1(msg, min_stat, GSS_C_MECH_CODE); 342 } 343 344 /* 345 * Function: display_ctx_flags 346 * 347 * Purpose: displays the flags returned by context initiation in 348 * a human-readable form 349 * 350 * Arguments: 351 * 352 * int ret_flags 353 * 354 * Effects: 355 * 356 * Strings corresponding to the context flags are printed on 357 * stdout, preceded by "context flag: " and followed by a newline 358 */ 359 360 void 361 display_ctx_flags(OM_uint32 flags) 362 { 363 if (flags & GSS_C_DELEG_FLAG) 364 fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n"); 365 if (flags & GSS_C_MUTUAL_FLAG) 366 fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n"); 367 if (flags & GSS_C_REPLAY_FLAG) 368 fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n"); 369 if (flags & GSS_C_SEQUENCE_FLAG) 370 fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n"); 371 if (flags & GSS_C_CONF_FLAG) 372 fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n"); 373 if (flags & GSS_C_INTEG_FLAG) 374 fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n"); 375 } 376 377 void 378 print_token(gss_buffer_t tok) 379 { 380 unsigned int i; 381 unsigned char *p = tok->value; 382 383 if (!display_file) 384 return; 385 for (i = 0; i < tok->length; i++, p++) { 386 fprintf(display_file, "%02x ", *p); 387 if ((i % 16) == 15) { 388 fprintf(display_file, "\n"); 389 } 390 } 391 fprintf(display_file, "\n"); 392 fflush(display_file); 393 } 394 395 #ifdef _WIN32 396 #include <sys\timeb.h> 397 #include <time.h> 398 399 int 400 gettimeofday(struct timeval *tv, void *ignore_tz) 401 { 402 struct _timeb tb; 403 _tzset(); 404 _ftime(&tb); 405 if (tv) { 406 tv->tv_sec = tb.time; 407 tv->tv_usec = tb.millitm * 1000; 408 } 409 return 0; 410 } 411 #endif /* _WIN32 */ 412