/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 1994 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appears in all copies and * that both that copyright notice and this permission notice appear in * supporting documentation, and that the name of OpenVision not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. OpenVision makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology. * All rights reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #include "autoconf.h" #include #ifdef _WIN32 #include #include #else #include #include #include #endif #include #ifdef HAVE_UNISTD_H #include #endif #include /* need struct timeval */ #include #if HAVE_SYS_TIME_H #include #endif #include #include "gss-misc.h" /* for store_32_be */ #include "k5-platform.h" #ifdef HAVE_STDLIB_H #include #else extern char *malloc(); #endif FILE *display_file; gss_buffer_desc empty_token_buf = { 0, (void *)"" }; gss_buffer_t empty_token = &empty_token_buf; static void display_status_1(char *m, OM_uint32 code, int type); static int write_all(int fildes, char *buf, unsigned int nbyte) { int ret; char *ptr; for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { ret = send(fildes, ptr, nbyte, 0); if (ret < 0) { if (errno == EINTR) continue; return ret; } else if (ret == 0) { return ptr - buf; } } return ptr - buf; } static int read_all(int fildes, char *buf, unsigned int nbyte) { int ret; char *ptr; fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(fildes, &rfds); tv.tv_sec = 10; tv.tv_usec = 0; for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0 || !FD_ISSET(fildes, &rfds)) return ptr - buf; ret = recv(fildes, ptr, nbyte, 0); if (ret < 0) { if (errno == EINTR) continue; return ret; } else if (ret == 0) { return ptr - buf; } } return ptr - buf; } /* * Function: send_token * * Purpose: Writes a token to a file descriptor. * * Arguments: * * s (r) an open file descriptor * flags (r) the flags to write * tok (r) the token to write * * Returns: 0 on success, -1 on failure * * Effects: * * If the flags are non-null, send_token writes the token flags (a * single byte, even though they're passed in in an integer). Next, * the token length (as a network long) and then the token data are * written to the file descriptor s. It returns 0 on success, and -1 * if an error occurs or if it could not write all the data. */ int send_token(int s, int flags, gss_buffer_t tok) { int ret; unsigned char char_flags = (unsigned char)flags; unsigned char lenbuf[4]; if (char_flags) { ret = write_all(s, (char *)&char_flags, 1); if (ret != 1) { perror("sending token flags"); return -1; } } if (tok->length > 0xffffffffUL) abort(); store_32_be(tok->length, lenbuf); ret = write_all(s, (char *)lenbuf, 4); if (ret < 0) { perror("sending token length"); return -1; } else if (ret != 4) { if (display_file) { fprintf(display_file, "sending token length: %d of %d bytes written\n", ret, 4); } return -1; } ret = write_all(s, tok->value, tok->length); if (ret < 0) { perror("sending token data"); return -1; } else if ((size_t)ret != tok->length) { if (display_file) { fprintf(display_file, "sending token data: %d of %d bytes written\n", ret, (int)tok->length); } return -1; } return 0; } /* * Function: recv_token * * Purpose: Reads a token from a file descriptor. * * Arguments: * * s (r) an open file descriptor * flags (w) the read flags * tok (w) the read token * * Returns: 0 on success, -1 on failure * * Effects: * * recv_token reads the token flags (a single byte, even though * they're stored into an integer, then reads the token length (as a * network long), allocates memory to hold the data, and then reads * the token data from the file descriptor s. It blocks to read the * length and data, if necessary. On a successful return, the token * should be freed with gss_release_buffer. It returns 0 on success, * and -1 if an error occurs or if it could not read all the data. */ int recv_token(int s, int *flags, gss_buffer_t tok) { int ret; unsigned char char_flags; unsigned char lenbuf[4]; ret = read_all(s, (char *)&char_flags, 1); if (ret < 0) { perror("reading token flags"); return -1; } else if (!ret) { if (display_file) fputs("reading token flags: 0 bytes read\n", display_file); return -1; } else { *flags = char_flags; } if (char_flags == 0) { lenbuf[0] = 0; ret = read_all(s, (char *)&lenbuf[1], 3); if (ret < 0) { perror("reading token length"); return -1; } else if (ret != 3) { if (display_file) { fprintf(display_file, "reading token length: %d of %d bytes read\n", ret, 3); } return -1; } } else { ret = read_all(s, (char *)lenbuf, 4); if (ret < 0) { perror("reading token length"); return -1; } else if (ret != 4) { if (display_file) { fprintf(display_file, "reading token length: %d of %d bytes read\n", ret, 4); } return -1; } } tok->length = load_32_be(lenbuf); tok->value = malloc(tok->length ? tok->length : 1); if (tok->length && tok->value == NULL) { if (display_file) fprintf(display_file, "Out of memory allocating token data\n"); return -1; } ret = read_all(s, (char *)tok->value, tok->length); if (ret < 0) { perror("reading token data"); free(tok->value); return -1; } else if ((size_t)ret != tok->length) { fprintf(stderr, "sending token data: %d of %d bytes written\n", ret, (int)tok->length); free(tok->value); return -1; } return 0; } static void display_status_1(char *m, OM_uint32 code, int type) { OM_uint32 min_stat; gss_buffer_desc msg; OM_uint32 msg_ctx; msg_ctx = 0; while (1) { (void)gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg); if (display_file) { fprintf(display_file, "GSS-API error %s: %s\n", m, (char *)msg.value); } (void)gss_release_buffer(&min_stat, &msg); if (!msg_ctx) break; } } /* * Function: display_status * * Purpose: displays GSS-API messages * * Arguments: * * msg a string to be displayed with the message * maj_stat the GSS-API major status code * min_stat the GSS-API minor status code * * Effects: * * The GSS-API messages associated with maj_stat and min_stat are * displayed on stderr, each preceded by "GSS-API error : " and * followed by a newline. */ void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) { display_status_1(msg, maj_stat, GSS_C_GSS_CODE); display_status_1(msg, min_stat, GSS_C_MECH_CODE); } /* * Function: display_ctx_flags * * Purpose: displays the flags returned by context initiation in * a human-readable form * * Arguments: * * int ret_flags * * Effects: * * Strings corresponding to the context flags are printed on * stdout, preceded by "context flag: " and followed by a newline */ void display_ctx_flags(OM_uint32 flags) { if (flags & GSS_C_DELEG_FLAG) fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n"); if (flags & GSS_C_MUTUAL_FLAG) fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n"); if (flags & GSS_C_REPLAY_FLAG) fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n"); if (flags & GSS_C_SEQUENCE_FLAG) fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n"); if (flags & GSS_C_CONF_FLAG) fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n"); if (flags & GSS_C_INTEG_FLAG) fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n"); } void print_token(gss_buffer_t tok) { size_t i; unsigned char *p = tok->value; if (!display_file) return; for (i = 0; i < tok->length; i++, p++) { fprintf(display_file, "%02x ", *p); if (i % 16 == 15) { fprintf(display_file, "\n"); } } fprintf(display_file, "\n"); fflush(display_file); } #ifdef _WIN32 #include #include int gettimeofday(struct timeval *tv, void *ignore_tz) { struct _timeb tb; _tzset(); _ftime(&tb); if (tv) { tv->tv_sec = tb.time; tv->tv_usec = tb.millitm * 1000; } return 0; } #endif /* _WIN32 */