Home | History | Annotate | Download | only in ftp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * Shared routines for client and server for
     31  * secure read(), write(), getc(), and putc().
     32  * Only one security context, thus only work on one fd at a time!
     33  */
     34 
     35 #include "ftp_var.h"
     36 #include <gssapi/gssapi.h>
     37 #include <arpa/ftp.h>
     38 #include <stdio.h>
     39 #include <string.h>
     40 #include <stdlib.h>
     41 #include <sys/types.h>
     42 #include <netinet/in.h>
     43 #include <errno.h>
     44 
     45 extern struct	sockaddr_in hisaddr;
     46 extern struct	sockaddr_in myaddr;
     47 extern int	dlevel;
     48 extern int	auth_type;
     49 extern uint_t	maxbuf; 	/* maximum output buffer size */
     50 extern uchar_t	*ucbuf;		/* cleartext buffer */
     51 static uint_t	nout;		/* number of chars in ucbuf */
     52 static uint_t	smaxbuf;	/* Internal saved value of maxbuf */
     53 static uint_t	smaxqueue;	/* Maximum allowed to queue before flush */
     54 
     55 extern gss_ctx_id_t gcontext;
     56 static int secure_putbuf(int, uchar_t *, uint_t);
     57 
     58 static int
     59 looping_write(int fd, const char *buf, int len)
     60 {
     61 	int cc, len2 = 0;
     62 
     63 	if (len == 0)
     64 		return (0);
     65 
     66 	do {
     67 		cc = write(fd, buf, len);
     68 		if (cc < 0) {
     69 			if (errno == EINTR)
     70 				continue;
     71 			return (cc);
     72 		} else if (cc == 0) {
     73 			return (len2);
     74 		} else {
     75 			buf += cc;
     76 			len2 += cc;
     77 			len -= cc;
     78 		}
     79 	} while (len > 0);
     80 	return (len2);
     81 }
     82 
     83 static int
     84 looping_read(int fd, char *buf, int len)
     85 {
     86 	int cc, len2 = 0;
     87 
     88 	do {
     89 		cc = read(fd, buf, len);
     90 		if (cc < 0) {
     91 			if (errno == EINTR)
     92 				continue;
     93 			return (cc);	/* errno is already set */
     94 		} else if (cc == 0) {
     95 			return (len2);
     96 		} else {
     97 			buf += cc;
     98 			len2 += cc;
     99 			len -= cc;
    100 		}
    101 	} while (len > 0);
    102 	return (len2);
    103 }
    104 
    105 #define	ERR	-2
    106 
    107 static void
    108 secure_error(char *fmt, ...)
    109 {
    110 	va_list ap;
    111 
    112 	va_start(ap, fmt);
    113 	vfprintf(stderr, fmt, ap);
    114 	va_end(ap);
    115 	putc('\n', stderr);
    116 }
    117 
    118 /*
    119  * Given maxbuf as a buffer size, determine how much can we
    120  * really transfer given the overhead of different algorithms
    121  *
    122  * Sets smaxbuf and smaxqueue
    123  */
    124 
    125 static int
    126 secure_determine_constants(void)
    127 {
    128 	smaxbuf = maxbuf;
    129 	smaxqueue = maxbuf;
    130 
    131 	if (auth_type == AUTHTYPE_GSSAPI) {
    132 		OM_uint32 maj_stat, min_stat, mlen;
    133 		OM_uint32 msize = maxbuf;
    134 
    135 		maj_stat = gss_wrap_size_limit(&min_stat, gcontext,
    136 			(dlevel == PROT_P),
    137 			GSS_C_QOP_DEFAULT,
    138 			msize, &mlen);
    139 		if (maj_stat != GSS_S_COMPLETE) {
    140 			user_gss_error(maj_stat, min_stat,
    141 				"GSSAPI fudge determination");
    142 			/* Return error how? */
    143 			return (ERR);
    144 		}
    145 		smaxqueue = mlen;
    146 	}
    147 
    148 	return (0);
    149 }
    150 
    151 static uchar_t
    152 secure_putbyte(int fd, uchar_t c)
    153 {
    154 	int ret;
    155 
    156 	if ((smaxbuf == 0) || (smaxqueue == 0) || (smaxbuf != maxbuf)) {
    157 	    ret = secure_determine_constants();
    158 	    if (ret)
    159 		return (ret);
    160 	}
    161 	ucbuf[nout++] = c;
    162 	if (nout == smaxqueue) {
    163 		nout = 0;
    164 		ret = secure_putbuf(fd, ucbuf, smaxqueue);
    165 		return (ret ? ret :c);
    166 	}
    167 	return (c);
    168 }
    169 
    170 /*
    171  * returns:
    172  *	 0  on success
    173  *	-1  on error (errno set)
    174  *	-2  on security error
    175  */
    176 int
    177 secure_flush(int fd)
    178 {
    179 	int ret;
    180 
    181 	if (dlevel == PROT_C)
    182 		return (0);
    183 	if (nout)
    184 		if (ret = secure_putbuf(fd, ucbuf, nout))
    185 			return (ret);
    186 	return (secure_putbuf(fd, (uchar_t *)"", nout = 0));
    187 }
    188 
    189 /*
    190  * returns:
    191  *	>= 0	on success
    192  *	-1	on error
    193  *	-2	on security error
    194  */
    195 int
    196 secure_putc(int c, FILE *stream)
    197 {
    198 	if (dlevel == PROT_C)
    199 		return (putc(c, stream));
    200 	return (secure_putbyte(fileno(stream), (uchar_t)c));
    201 }
    202 
    203 /*
    204  * returns:
    205  *	nbyte on success
    206  *	-1  on error (errno set)
    207  *	-2  on security error
    208  */
    209 ssize_t
    210 secure_write(int fd, const void *inbuf, size_t nbyte)
    211 {
    212 	uint_t i;
    213 	int c;
    214 	uchar_t *buf = (uchar_t *)inbuf;
    215 
    216 	if (dlevel == PROT_C)
    217 		return (write(fd, buf, nbyte));
    218 	for (i = 0; nbyte > 0; nbyte--)
    219 		if ((c = secure_putbyte(fd, buf[i++])) < 0)
    220 			return (c);
    221 	return (i);
    222 }
    223 
    224 /*
    225  * returns:
    226  *	 0  on success
    227  *	-1  on error, errno set
    228  *	-2  on security error
    229  */
    230 static int secure_putbuf(int fd, uchar_t *buf, uint_t nbyte)
    231 {
    232 	static char *outbuf;		/* output ciphertext */
    233 	static uint_t bufsize;	/* size of outbuf */
    234 	int length;
    235 	uint_t net_len;
    236 
    237 	/* Other auth types go here ... */
    238 
    239 	if (auth_type == AUTHTYPE_GSSAPI) {
    240 		gss_buffer_desc in_buf, out_buf;
    241 		OM_uint32 maj_stat, min_stat;
    242 		int conf_state;
    243 
    244 		in_buf.value = buf;
    245 		in_buf.length = nbyte;
    246 		maj_stat = gss_seal(&min_stat, gcontext,
    247 				(dlevel == PROT_P), /* confidential */
    248 				GSS_C_QOP_DEFAULT,
    249 				&in_buf, &conf_state,
    250 				&out_buf);
    251 		if (maj_stat != GSS_S_COMPLETE) {
    252 			/*
    253 			 * generally need to deal
    254 			 * ie. should loop, but for now just fail
    255 			 */
    256 			user_gss_error(maj_stat, min_stat, dlevel == PROT_P?
    257 				"GSSAPI seal failed" : "GSSAPI sign failed");
    258 			return (ERR);
    259 		}
    260 
    261 		if (bufsize < out_buf.length) {
    262 			outbuf = outbuf ?
    263 				realloc(outbuf, (size_t)out_buf.length) :
    264 				malloc((size_t)out_buf.length);
    265 			if (outbuf)
    266 				bufsize = out_buf.length;
    267 			else {
    268 				bufsize = 0;
    269 				secure_error("%s (in malloc of PROT buffer)",
    270 					strerror(errno));
    271 				return (ERR);
    272 			}
    273 		}
    274 
    275 		memcpy(outbuf, out_buf.value, length = out_buf.length);
    276 		gss_release_buffer(&min_stat, &out_buf);
    277 	}
    278 	net_len = htonl((uint32_t)length);
    279 	if (looping_write(fd, (char *)&net_len, 4) == -1)
    280 		return (-1);
    281 	if (looping_write(fd, outbuf, length) != length)
    282 		return (-1);
    283 	return (0);
    284 }
    285 
    286 static int
    287 secure_getbyte(int fd)
    288 {
    289 	/* number of chars in ucbuf, pointer into ucbuf */
    290 	static uint_t nin, bufp;
    291 	int kerror;
    292 	uint_t length;
    293 
    294 	if (nin == 0) {
    295 		if ((kerror =
    296 			looping_read(fd, (char *)&length, sizeof (length)))
    297 			!= sizeof (length)) {
    298 			secure_error("Couldn't read PROT buffer length: %d/%s",
    299 				kerror, (kerror == -1) ? strerror(errno) :
    300 				"premature EOF");
    301 			return (ERR);
    302 		}
    303 		if ((length = ntohl((uint32_t)length)) > maxbuf) {
    304 			secure_error("Length (%d) of PROT buffer > PBSZ=%u",
    305 				length, maxbuf);
    306 			return (ERR);
    307 		}
    308 		if ((kerror = looping_read(fd, (char *)ucbuf, length))
    309 			!= length) {
    310 			secure_error("Couldn't read %u byte PROT buffer: %s",
    311 					length, kerror == -1 ?
    312 					strerror(errno) : "premature EOF");
    313 			return (ERR);
    314 		}
    315 		/* Other auth types go here ... */
    316 
    317 		if (auth_type == AUTHTYPE_GSSAPI) {
    318 			gss_buffer_desc xmit_buf, msg_buf;
    319 			OM_uint32 maj_stat, min_stat;
    320 			int conf_state;
    321 
    322 			xmit_buf.value = ucbuf;
    323 			xmit_buf.length = length;
    324 			conf_state = (dlevel == PROT_P);
    325 			/* decrypt/verify the message */
    326 			maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
    327 				&msg_buf, &conf_state, NULL);
    328 			if (maj_stat != GSS_S_COMPLETE) {
    329 				user_gss_error(maj_stat, min_stat,
    330 				    (dlevel == PROT_P)?
    331 				    "failed unsealing ENC message":
    332 				    "failed unsealing MIC message");
    333 				return (ERR);
    334 			}
    335 
    336 			memcpy(ucbuf, msg_buf.value,
    337 				nin = bufp = msg_buf.length);
    338 			gss_release_buffer(&min_stat, &msg_buf);
    339 		}
    340 		/* Other auth types go here ... */
    341 	}
    342 	return ((nin == 0) ? EOF : ucbuf[bufp - nin--]);
    343 }
    344 
    345 /*
    346  * returns:
    347  *	 0	on success
    348  *	-1	on EOF
    349  *	-2	on security error
    350  */
    351 int
    352 secure_getc(FILE *stream)
    353 {
    354 	if (dlevel == PROT_C)
    355 		return (getc(stream));
    356 	return (secure_getbyte(fileno(stream)));
    357 }
    358 
    359 /*
    360  * returns:
    361  *	> 0	on success (n == # of bytes read)
    362  *	 0	on EOF
    363  *	-1	on error, errno set, only for PROT_C
    364  *	-2	on security error (ERR = -2)
    365  */
    366 ssize_t
    367 secure_read(int fd, void *inbuf, size_t nbyte)
    368 {
    369 	int c, i;
    370 	char *buf = (char *)inbuf;
    371 
    372 	if (dlevel == PROT_C)
    373 		return (read(fd, buf, nbyte));
    374 	if (goteof)
    375 		return (goteof = 0);
    376 
    377 	for (i = 0; nbyte > 0; nbyte--)
    378 		switch (c = secure_getbyte(fd)) {
    379 			case ERR:
    380 				return (c);
    381 			case EOF:
    382 				goteof = i ? 1 : 0;
    383 				return (i);
    384 			default:
    385 				buf[i++] = c;
    386 		}
    387 	return (i);
    388 }
    389