xref: /titanic_52/usr/src/cmd/cmd-inet/usr.bin/ftp/secure.c (revision 740638c8fa5a1c03618a9c75c3161dba57259a17)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*740638c8Sbw  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Shared routines for client and server for
317c478bd9Sstevel@tonic-gate  * secure read(), write(), getc(), and putc().
327c478bd9Sstevel@tonic-gate  * Only one security context, thus only work on one fd at a time!
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "ftp_var.h"
367c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
377c478bd9Sstevel@tonic-gate #include <arpa/ftp.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate extern struct	sockaddr_in hisaddr;
467c478bd9Sstevel@tonic-gate extern struct	sockaddr_in myaddr;
477c478bd9Sstevel@tonic-gate extern int	dlevel;
487c478bd9Sstevel@tonic-gate extern int	auth_type;
497c478bd9Sstevel@tonic-gate extern uint_t	maxbuf; 	/* maximum output buffer size */
507c478bd9Sstevel@tonic-gate extern uchar_t	*ucbuf;		/* cleartext buffer */
517c478bd9Sstevel@tonic-gate static uint_t	nout;		/* number of chars in ucbuf */
527c478bd9Sstevel@tonic-gate static uint_t	smaxbuf;	/* Internal saved value of maxbuf */
537c478bd9Sstevel@tonic-gate static uint_t	smaxqueue;	/* Maximum allowed to queue before flush */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate extern gss_ctx_id_t gcontext;
567c478bd9Sstevel@tonic-gate static int secure_putbuf(int, uchar_t *, uint_t);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static int
597c478bd9Sstevel@tonic-gate looping_write(int fd, const char *buf, int len)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	int cc, len2 = 0;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	if (len == 0)
647c478bd9Sstevel@tonic-gate 		return (0);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	do {
677c478bd9Sstevel@tonic-gate 		cc = write(fd, buf, len);
687c478bd9Sstevel@tonic-gate 		if (cc < 0) {
697c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
707c478bd9Sstevel@tonic-gate 				continue;
717c478bd9Sstevel@tonic-gate 			return (cc);
727c478bd9Sstevel@tonic-gate 		} else if (cc == 0) {
737c478bd9Sstevel@tonic-gate 			return (len2);
747c478bd9Sstevel@tonic-gate 		} else {
757c478bd9Sstevel@tonic-gate 			buf += cc;
767c478bd9Sstevel@tonic-gate 			len2 += cc;
777c478bd9Sstevel@tonic-gate 			len -= cc;
787c478bd9Sstevel@tonic-gate 		}
797c478bd9Sstevel@tonic-gate 	} while (len > 0);
807c478bd9Sstevel@tonic-gate 	return (len2);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static int
847c478bd9Sstevel@tonic-gate looping_read(int fd, char *buf, int len)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	int cc, len2 = 0;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	do {
897c478bd9Sstevel@tonic-gate 		cc = read(fd, buf, len);
907c478bd9Sstevel@tonic-gate 		if (cc < 0) {
917c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
927c478bd9Sstevel@tonic-gate 				continue;
937c478bd9Sstevel@tonic-gate 			return (cc);	/* errno is already set */
947c478bd9Sstevel@tonic-gate 		} else if (cc == 0) {
957c478bd9Sstevel@tonic-gate 			return (len2);
967c478bd9Sstevel@tonic-gate 		} else {
977c478bd9Sstevel@tonic-gate 			buf += cc;
987c478bd9Sstevel@tonic-gate 			len2 += cc;
997c478bd9Sstevel@tonic-gate 			len -= cc;
1007c478bd9Sstevel@tonic-gate 		}
1017c478bd9Sstevel@tonic-gate 	} while (len > 0);
1027c478bd9Sstevel@tonic-gate 	return (len2);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	ERR	-2
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static void
1087c478bd9Sstevel@tonic-gate secure_error(char *fmt, ...)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	va_list ap;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1137c478bd9Sstevel@tonic-gate 	vfprintf(stderr, fmt, ap);
1147c478bd9Sstevel@tonic-gate 	va_end(ap);
1157c478bd9Sstevel@tonic-gate 	putc('\n', stderr);
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * Given maxbuf as a buffer size, determine how much can we
1207c478bd9Sstevel@tonic-gate  * really transfer given the overhead of different algorithms
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  * Sets smaxbuf and smaxqueue
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static int
1267c478bd9Sstevel@tonic-gate secure_determine_constants(void)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	smaxbuf = maxbuf;
1297c478bd9Sstevel@tonic-gate 	smaxqueue = maxbuf;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if (auth_type == AUTHTYPE_GSSAPI) {
1327c478bd9Sstevel@tonic-gate 		OM_uint32 maj_stat, min_stat, mlen;
1337c478bd9Sstevel@tonic-gate 		OM_uint32 msize = maxbuf;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		maj_stat = gss_wrap_size_limit(&min_stat, gcontext,
1367c478bd9Sstevel@tonic-gate 			(dlevel == PROT_P),
1377c478bd9Sstevel@tonic-gate 			GSS_C_QOP_DEFAULT,
1387c478bd9Sstevel@tonic-gate 			msize, &mlen);
1397c478bd9Sstevel@tonic-gate 		if (maj_stat != GSS_S_COMPLETE) {
1407c478bd9Sstevel@tonic-gate 			user_gss_error(maj_stat, min_stat,
1417c478bd9Sstevel@tonic-gate 				"GSSAPI fudge determination");
1427c478bd9Sstevel@tonic-gate 			/* Return error how? */
1437c478bd9Sstevel@tonic-gate 			return (ERR);
1447c478bd9Sstevel@tonic-gate 		}
1457c478bd9Sstevel@tonic-gate 		smaxqueue = mlen;
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (0);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static uchar_t
1527c478bd9Sstevel@tonic-gate secure_putbyte(int fd, uchar_t c)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	int ret;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if ((smaxbuf == 0) || (smaxqueue == 0) || (smaxbuf != maxbuf)) {
1577c478bd9Sstevel@tonic-gate 	    ret = secure_determine_constants();
1587c478bd9Sstevel@tonic-gate 	    if (ret)
1597c478bd9Sstevel@tonic-gate 		return (ret);
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 	ucbuf[nout++] = c;
1627c478bd9Sstevel@tonic-gate 	if (nout == smaxqueue) {
1637c478bd9Sstevel@tonic-gate 		nout = 0;
1647c478bd9Sstevel@tonic-gate 		ret = secure_putbuf(fd, ucbuf, smaxqueue);
1657c478bd9Sstevel@tonic-gate 		return (ret ? ret :c);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	return (c);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * returns:
1727c478bd9Sstevel@tonic-gate  *	 0  on success
1737c478bd9Sstevel@tonic-gate  *	-1  on error (errno set)
1747c478bd9Sstevel@tonic-gate  *	-2  on security error
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate int
1777c478bd9Sstevel@tonic-gate secure_flush(int fd)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	int ret;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (dlevel == PROT_C)
1827c478bd9Sstevel@tonic-gate 		return (0);
1837c478bd9Sstevel@tonic-gate 	if (nout)
1847c478bd9Sstevel@tonic-gate 		if (ret = secure_putbuf(fd, ucbuf, nout))
1857c478bd9Sstevel@tonic-gate 			return (ret);
1867c478bd9Sstevel@tonic-gate 	return (secure_putbuf(fd, (uchar_t *)"", nout = 0));
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * returns:
1917c478bd9Sstevel@tonic-gate  *	>= 0	on success
1927c478bd9Sstevel@tonic-gate  *	-1	on error
1937c478bd9Sstevel@tonic-gate  *	-2	on security error
1947c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate int
1967c478bd9Sstevel@tonic-gate secure_putc(int c, FILE *stream)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	if (dlevel == PROT_C)
1997c478bd9Sstevel@tonic-gate 		return (putc(c, stream));
2007c478bd9Sstevel@tonic-gate 	return (secure_putbyte(fileno(stream), (uchar_t)c));
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate  * returns:
2057c478bd9Sstevel@tonic-gate  *	nbyte on success
2067c478bd9Sstevel@tonic-gate  *	-1  on error (errno set)
2077c478bd9Sstevel@tonic-gate  *	-2  on security error
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate ssize_t
2107c478bd9Sstevel@tonic-gate secure_write(int fd, const void *inbuf, size_t nbyte)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	uint_t i;
2137c478bd9Sstevel@tonic-gate 	int c;
2147c478bd9Sstevel@tonic-gate 	uchar_t *buf = (uchar_t *)inbuf;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (dlevel == PROT_C)
2177c478bd9Sstevel@tonic-gate 		return (write(fd, buf, nbyte));
2187c478bd9Sstevel@tonic-gate 	for (i = 0; nbyte > 0; nbyte--)
2197c478bd9Sstevel@tonic-gate 		if ((c = secure_putbyte(fd, buf[i++])) < 0)
2207c478bd9Sstevel@tonic-gate 			return (c);
2217c478bd9Sstevel@tonic-gate 	return (i);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * returns:
2267c478bd9Sstevel@tonic-gate  *	 0  on success
2277c478bd9Sstevel@tonic-gate  *	-1  on error, errno set
2287c478bd9Sstevel@tonic-gate  *	-2  on security error
2297c478bd9Sstevel@tonic-gate  */
2307c478bd9Sstevel@tonic-gate static int secure_putbuf(int fd, uchar_t *buf, uint_t nbyte)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	static char *outbuf;		/* output ciphertext */
2337c478bd9Sstevel@tonic-gate 	static uint_t bufsize;	/* size of outbuf */
2347c478bd9Sstevel@tonic-gate 	int length;
2357c478bd9Sstevel@tonic-gate 	uint_t net_len;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* Other auth types go here ... */
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (auth_type == AUTHTYPE_GSSAPI) {
2407c478bd9Sstevel@tonic-gate 		gss_buffer_desc in_buf, out_buf;
2417c478bd9Sstevel@tonic-gate 		OM_uint32 maj_stat, min_stat;
2427c478bd9Sstevel@tonic-gate 		int conf_state;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 		in_buf.value = buf;
2457c478bd9Sstevel@tonic-gate 		in_buf.length = nbyte;
2467c478bd9Sstevel@tonic-gate 		maj_stat = gss_seal(&min_stat, gcontext,
2477c478bd9Sstevel@tonic-gate 				(dlevel == PROT_P), /* confidential */
2487c478bd9Sstevel@tonic-gate 				GSS_C_QOP_DEFAULT,
2497c478bd9Sstevel@tonic-gate 				&in_buf, &conf_state,
2507c478bd9Sstevel@tonic-gate 				&out_buf);
2517c478bd9Sstevel@tonic-gate 		if (maj_stat != GSS_S_COMPLETE) {
2527c478bd9Sstevel@tonic-gate 			/*
2537c478bd9Sstevel@tonic-gate 			 * generally need to deal
2547c478bd9Sstevel@tonic-gate 			 * ie. should loop, but for now just fail
2557c478bd9Sstevel@tonic-gate 			 */
2567c478bd9Sstevel@tonic-gate 			user_gss_error(maj_stat, min_stat, dlevel == PROT_P?
2577c478bd9Sstevel@tonic-gate 				"GSSAPI seal failed" : "GSSAPI sign failed");
2587c478bd9Sstevel@tonic-gate 			return (ERR);
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		if (bufsize < out_buf.length) {
2627c478bd9Sstevel@tonic-gate 			outbuf = outbuf ?
2637c478bd9Sstevel@tonic-gate 				realloc(outbuf, (size_t)out_buf.length) :
2647c478bd9Sstevel@tonic-gate 				malloc((size_t)out_buf.length);
2657c478bd9Sstevel@tonic-gate 			if (outbuf)
2667c478bd9Sstevel@tonic-gate 				bufsize = out_buf.length;
2677c478bd9Sstevel@tonic-gate 			else {
2687c478bd9Sstevel@tonic-gate 				bufsize = 0;
2697c478bd9Sstevel@tonic-gate 				secure_error("%s (in malloc of PROT buffer)",
2707c478bd9Sstevel@tonic-gate 					strerror(errno));
2717c478bd9Sstevel@tonic-gate 				return (ERR);
2727c478bd9Sstevel@tonic-gate 			}
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		memcpy(outbuf, out_buf.value, length = out_buf.length);
2767c478bd9Sstevel@tonic-gate 		gss_release_buffer(&min_stat, &out_buf);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	net_len = htonl((uint32_t)length);
2797c478bd9Sstevel@tonic-gate 	if (looping_write(fd, (char *)&net_len, 4) == -1)
2807c478bd9Sstevel@tonic-gate 		return (-1);
2817c478bd9Sstevel@tonic-gate 	if (looping_write(fd, outbuf, length) != length)
2827c478bd9Sstevel@tonic-gate 		return (-1);
2837c478bd9Sstevel@tonic-gate 	return (0);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
286*740638c8Sbw static int
2877c478bd9Sstevel@tonic-gate secure_getbyte(int fd)
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate 	/* number of chars in ucbuf, pointer into ucbuf */
2907c478bd9Sstevel@tonic-gate 	static uint_t nin, bufp;
2917c478bd9Sstevel@tonic-gate 	int kerror;
2927c478bd9Sstevel@tonic-gate 	uint_t length;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (nin == 0) {
2957c478bd9Sstevel@tonic-gate 		if ((kerror =
2967c478bd9Sstevel@tonic-gate 			looping_read(fd, (char *)&length, sizeof (length)))
2977c478bd9Sstevel@tonic-gate 			!= sizeof (length)) {
2987c478bd9Sstevel@tonic-gate 			secure_error("Couldn't read PROT buffer length: %d/%s",
2997c478bd9Sstevel@tonic-gate 				kerror, (kerror == -1) ? strerror(errno) :
3007c478bd9Sstevel@tonic-gate 				"premature EOF");
3017c478bd9Sstevel@tonic-gate 			return (ERR);
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 		if ((length = ntohl((uint32_t)length)) > maxbuf) {
3047c478bd9Sstevel@tonic-gate 			secure_error("Length (%d) of PROT buffer > PBSZ=%u",
3057c478bd9Sstevel@tonic-gate 				length, maxbuf);
3067c478bd9Sstevel@tonic-gate 			return (ERR);
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 		if ((kerror = looping_read(fd, (char *)ucbuf, length))
3097c478bd9Sstevel@tonic-gate 			!= length) {
3107c478bd9Sstevel@tonic-gate 			secure_error("Couldn't read %u byte PROT buffer: %s",
3117c478bd9Sstevel@tonic-gate 					length, kerror == -1 ?
3127c478bd9Sstevel@tonic-gate 					strerror(errno) : "premature EOF");
3137c478bd9Sstevel@tonic-gate 			return (ERR);
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 		/* Other auth types go here ... */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		if (auth_type == AUTHTYPE_GSSAPI) {
3187c478bd9Sstevel@tonic-gate 			gss_buffer_desc xmit_buf, msg_buf;
3197c478bd9Sstevel@tonic-gate 			OM_uint32 maj_stat, min_stat;
3207c478bd9Sstevel@tonic-gate 			int conf_state;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 			xmit_buf.value = ucbuf;
3237c478bd9Sstevel@tonic-gate 			xmit_buf.length = length;
3247c478bd9Sstevel@tonic-gate 			conf_state = (dlevel == PROT_P);
3257c478bd9Sstevel@tonic-gate 			/* decrypt/verify the message */
3267c478bd9Sstevel@tonic-gate 			maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
3277c478bd9Sstevel@tonic-gate 				&msg_buf, &conf_state, NULL);
3287c478bd9Sstevel@tonic-gate 			if (maj_stat != GSS_S_COMPLETE) {
3297c478bd9Sstevel@tonic-gate 				user_gss_error(maj_stat, min_stat,
3307c478bd9Sstevel@tonic-gate 				    (dlevel == PROT_P)?
3317c478bd9Sstevel@tonic-gate 				    "failed unsealing ENC message":
3327c478bd9Sstevel@tonic-gate 				    "failed unsealing MIC message");
3337c478bd9Sstevel@tonic-gate 				return (ERR);
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 			memcpy(ucbuf, msg_buf.value,
3377c478bd9Sstevel@tonic-gate 				nin = bufp = msg_buf.length);
3387c478bd9Sstevel@tonic-gate 			gss_release_buffer(&min_stat, &msg_buf);
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 		/* Other auth types go here ... */
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	return ((nin == 0) ? EOF : ucbuf[bufp - nin--]);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * returns:
3477c478bd9Sstevel@tonic-gate  *	 0	on success
3487c478bd9Sstevel@tonic-gate  *	-1	on EOF
3497c478bd9Sstevel@tonic-gate  *	-2	on security error
3507c478bd9Sstevel@tonic-gate  */
3517c478bd9Sstevel@tonic-gate int
3527c478bd9Sstevel@tonic-gate secure_getc(FILE *stream)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	if (dlevel == PROT_C)
3557c478bd9Sstevel@tonic-gate 		return (getc(stream));
3567c478bd9Sstevel@tonic-gate 	return (secure_getbyte(fileno(stream)));
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate  * returns:
3617c478bd9Sstevel@tonic-gate  *	> 0	on success (n == # of bytes read)
3627c478bd9Sstevel@tonic-gate  *	 0	on EOF
3637c478bd9Sstevel@tonic-gate  *	-1	on error, errno set, only for PROT_C
3647c478bd9Sstevel@tonic-gate  *	-2	on security error (ERR = -2)
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate ssize_t
3677c478bd9Sstevel@tonic-gate secure_read(int fd, void *inbuf, size_t nbyte)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	int c, i;
3707c478bd9Sstevel@tonic-gate 	char *buf = (char *)inbuf;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (dlevel == PROT_C)
3737c478bd9Sstevel@tonic-gate 		return (read(fd, buf, nbyte));
3747c478bd9Sstevel@tonic-gate 	if (goteof)
3757c478bd9Sstevel@tonic-gate 		return (goteof = 0);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	for (i = 0; nbyte > 0; nbyte--)
3787c478bd9Sstevel@tonic-gate 		switch (c = secure_getbyte(fd)) {
3797c478bd9Sstevel@tonic-gate 			case ERR:
3807c478bd9Sstevel@tonic-gate 				return (c);
3817c478bd9Sstevel@tonic-gate 			case EOF:
3827c478bd9Sstevel@tonic-gate 				goteof = i ? 1 : 0;
3837c478bd9Sstevel@tonic-gate 				return (i);
3847c478bd9Sstevel@tonic-gate 			default:
3857c478bd9Sstevel@tonic-gate 				buf[i++] = c;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 	return (i);
3887c478bd9Sstevel@tonic-gate }
389