10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*473Sbw * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Shared routines for client and server for
310Sstevel@tonic-gate * secure read(), write(), getc(), and putc().
320Sstevel@tonic-gate * Only one security context, thus only work on one fd at a time!
330Sstevel@tonic-gate */
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include "ftp_var.h"
360Sstevel@tonic-gate #include <gssapi/gssapi.h>
370Sstevel@tonic-gate #include <arpa/ftp.h>
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <netinet/in.h>
430Sstevel@tonic-gate #include <errno.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate extern struct sockaddr_in hisaddr;
460Sstevel@tonic-gate extern struct sockaddr_in myaddr;
470Sstevel@tonic-gate extern int dlevel;
480Sstevel@tonic-gate extern int auth_type;
490Sstevel@tonic-gate extern uint_t maxbuf; /* maximum output buffer size */
500Sstevel@tonic-gate extern uchar_t *ucbuf; /* cleartext buffer */
510Sstevel@tonic-gate static uint_t nout; /* number of chars in ucbuf */
520Sstevel@tonic-gate static uint_t smaxbuf; /* Internal saved value of maxbuf */
530Sstevel@tonic-gate static uint_t smaxqueue; /* Maximum allowed to queue before flush */
540Sstevel@tonic-gate
550Sstevel@tonic-gate extern gss_ctx_id_t gcontext;
560Sstevel@tonic-gate static int secure_putbuf(int, uchar_t *, uint_t);
570Sstevel@tonic-gate
580Sstevel@tonic-gate static int
looping_write(int fd,const char * buf,int len)590Sstevel@tonic-gate looping_write(int fd, const char *buf, int len)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate int cc, len2 = 0;
620Sstevel@tonic-gate
630Sstevel@tonic-gate if (len == 0)
640Sstevel@tonic-gate return (0);
650Sstevel@tonic-gate
660Sstevel@tonic-gate do {
670Sstevel@tonic-gate cc = write(fd, buf, len);
680Sstevel@tonic-gate if (cc < 0) {
690Sstevel@tonic-gate if (errno == EINTR)
700Sstevel@tonic-gate continue;
710Sstevel@tonic-gate return (cc);
720Sstevel@tonic-gate } else if (cc == 0) {
730Sstevel@tonic-gate return (len2);
740Sstevel@tonic-gate } else {
750Sstevel@tonic-gate buf += cc;
760Sstevel@tonic-gate len2 += cc;
770Sstevel@tonic-gate len -= cc;
780Sstevel@tonic-gate }
790Sstevel@tonic-gate } while (len > 0);
800Sstevel@tonic-gate return (len2);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate
830Sstevel@tonic-gate static int
looping_read(int fd,char * buf,int len)840Sstevel@tonic-gate looping_read(int fd, char *buf, int len)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate int cc, len2 = 0;
870Sstevel@tonic-gate
880Sstevel@tonic-gate do {
890Sstevel@tonic-gate cc = read(fd, buf, len);
900Sstevel@tonic-gate if (cc < 0) {
910Sstevel@tonic-gate if (errno == EINTR)
920Sstevel@tonic-gate continue;
930Sstevel@tonic-gate return (cc); /* errno is already set */
940Sstevel@tonic-gate } else if (cc == 0) {
950Sstevel@tonic-gate return (len2);
960Sstevel@tonic-gate } else {
970Sstevel@tonic-gate buf += cc;
980Sstevel@tonic-gate len2 += cc;
990Sstevel@tonic-gate len -= cc;
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate } while (len > 0);
1020Sstevel@tonic-gate return (len2);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate #define ERR -2
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate static void
secure_error(char * fmt,...)1080Sstevel@tonic-gate secure_error(char *fmt, ...)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate va_list ap;
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate va_start(ap, fmt);
1130Sstevel@tonic-gate vfprintf(stderr, fmt, ap);
1140Sstevel@tonic-gate va_end(ap);
1150Sstevel@tonic-gate putc('\n', stderr);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate * Given maxbuf as a buffer size, determine how much can we
1200Sstevel@tonic-gate * really transfer given the overhead of different algorithms
1210Sstevel@tonic-gate *
1220Sstevel@tonic-gate * Sets smaxbuf and smaxqueue
1230Sstevel@tonic-gate */
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate static int
secure_determine_constants(void)1260Sstevel@tonic-gate secure_determine_constants(void)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate smaxbuf = maxbuf;
1290Sstevel@tonic-gate smaxqueue = maxbuf;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate if (auth_type == AUTHTYPE_GSSAPI) {
1320Sstevel@tonic-gate OM_uint32 maj_stat, min_stat, mlen;
1330Sstevel@tonic-gate OM_uint32 msize = maxbuf;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate maj_stat = gss_wrap_size_limit(&min_stat, gcontext,
1360Sstevel@tonic-gate (dlevel == PROT_P),
1370Sstevel@tonic-gate GSS_C_QOP_DEFAULT,
1380Sstevel@tonic-gate msize, &mlen);
1390Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
1400Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
1410Sstevel@tonic-gate "GSSAPI fudge determination");
1420Sstevel@tonic-gate /* Return error how? */
1430Sstevel@tonic-gate return (ERR);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate smaxqueue = mlen;
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate return (0);
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate static uchar_t
secure_putbyte(int fd,uchar_t c)1520Sstevel@tonic-gate secure_putbyte(int fd, uchar_t c)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate int ret;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if ((smaxbuf == 0) || (smaxqueue == 0) || (smaxbuf != maxbuf)) {
1570Sstevel@tonic-gate ret = secure_determine_constants();
1580Sstevel@tonic-gate if (ret)
1590Sstevel@tonic-gate return (ret);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate ucbuf[nout++] = c;
1620Sstevel@tonic-gate if (nout == smaxqueue) {
1630Sstevel@tonic-gate nout = 0;
1640Sstevel@tonic-gate ret = secure_putbuf(fd, ucbuf, smaxqueue);
1650Sstevel@tonic-gate return (ret ? ret :c);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate return (c);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * returns:
1720Sstevel@tonic-gate * 0 on success
1730Sstevel@tonic-gate * -1 on error (errno set)
1740Sstevel@tonic-gate * -2 on security error
1750Sstevel@tonic-gate */
1760Sstevel@tonic-gate int
secure_flush(int fd)1770Sstevel@tonic-gate secure_flush(int fd)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate int ret;
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate if (dlevel == PROT_C)
1820Sstevel@tonic-gate return (0);
1830Sstevel@tonic-gate if (nout)
1840Sstevel@tonic-gate if (ret = secure_putbuf(fd, ucbuf, nout))
1850Sstevel@tonic-gate return (ret);
1860Sstevel@tonic-gate return (secure_putbuf(fd, (uchar_t *)"", nout = 0));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate * returns:
1910Sstevel@tonic-gate * >= 0 on success
1920Sstevel@tonic-gate * -1 on error
1930Sstevel@tonic-gate * -2 on security error
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate int
secure_putc(int c,FILE * stream)1960Sstevel@tonic-gate secure_putc(int c, FILE *stream)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate if (dlevel == PROT_C)
1990Sstevel@tonic-gate return (putc(c, stream));
2000Sstevel@tonic-gate return (secure_putbyte(fileno(stream), (uchar_t)c));
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate * returns:
2050Sstevel@tonic-gate * nbyte on success
2060Sstevel@tonic-gate * -1 on error (errno set)
2070Sstevel@tonic-gate * -2 on security error
2080Sstevel@tonic-gate */
2090Sstevel@tonic-gate ssize_t
secure_write(int fd,const void * inbuf,size_t nbyte)2100Sstevel@tonic-gate secure_write(int fd, const void *inbuf, size_t nbyte)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate uint_t i;
2130Sstevel@tonic-gate int c;
2140Sstevel@tonic-gate uchar_t *buf = (uchar_t *)inbuf;
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate if (dlevel == PROT_C)
2170Sstevel@tonic-gate return (write(fd, buf, nbyte));
2180Sstevel@tonic-gate for (i = 0; nbyte > 0; nbyte--)
2190Sstevel@tonic-gate if ((c = secure_putbyte(fd, buf[i++])) < 0)
2200Sstevel@tonic-gate return (c);
2210Sstevel@tonic-gate return (i);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * returns:
2260Sstevel@tonic-gate * 0 on success
2270Sstevel@tonic-gate * -1 on error, errno set
2280Sstevel@tonic-gate * -2 on security error
2290Sstevel@tonic-gate */
secure_putbuf(int fd,uchar_t * buf,uint_t nbyte)2300Sstevel@tonic-gate static int secure_putbuf(int fd, uchar_t *buf, uint_t nbyte)
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate static char *outbuf; /* output ciphertext */
2330Sstevel@tonic-gate static uint_t bufsize; /* size of outbuf */
2340Sstevel@tonic-gate int length;
2350Sstevel@tonic-gate uint_t net_len;
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate /* Other auth types go here ... */
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (auth_type == AUTHTYPE_GSSAPI) {
2400Sstevel@tonic-gate gss_buffer_desc in_buf, out_buf;
2410Sstevel@tonic-gate OM_uint32 maj_stat, min_stat;
2420Sstevel@tonic-gate int conf_state;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate in_buf.value = buf;
2450Sstevel@tonic-gate in_buf.length = nbyte;
2460Sstevel@tonic-gate maj_stat = gss_seal(&min_stat, gcontext,
2470Sstevel@tonic-gate (dlevel == PROT_P), /* confidential */
2480Sstevel@tonic-gate GSS_C_QOP_DEFAULT,
2490Sstevel@tonic-gate &in_buf, &conf_state,
2500Sstevel@tonic-gate &out_buf);
2510Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate * generally need to deal
2540Sstevel@tonic-gate * ie. should loop, but for now just fail
2550Sstevel@tonic-gate */
2560Sstevel@tonic-gate user_gss_error(maj_stat, min_stat, dlevel == PROT_P?
2570Sstevel@tonic-gate "GSSAPI seal failed" : "GSSAPI sign failed");
2580Sstevel@tonic-gate return (ERR);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate if (bufsize < out_buf.length) {
2620Sstevel@tonic-gate outbuf = outbuf ?
2630Sstevel@tonic-gate realloc(outbuf, (size_t)out_buf.length) :
2640Sstevel@tonic-gate malloc((size_t)out_buf.length);
2650Sstevel@tonic-gate if (outbuf)
2660Sstevel@tonic-gate bufsize = out_buf.length;
2670Sstevel@tonic-gate else {
2680Sstevel@tonic-gate bufsize = 0;
2690Sstevel@tonic-gate secure_error("%s (in malloc of PROT buffer)",
2700Sstevel@tonic-gate strerror(errno));
2710Sstevel@tonic-gate return (ERR);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate memcpy(outbuf, out_buf.value, length = out_buf.length);
2760Sstevel@tonic-gate gss_release_buffer(&min_stat, &out_buf);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate net_len = htonl((uint32_t)length);
2790Sstevel@tonic-gate if (looping_write(fd, (char *)&net_len, 4) == -1)
2800Sstevel@tonic-gate return (-1);
2810Sstevel@tonic-gate if (looping_write(fd, outbuf, length) != length)
2820Sstevel@tonic-gate return (-1);
2830Sstevel@tonic-gate return (0);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate
286*473Sbw static int
secure_getbyte(int fd)2870Sstevel@tonic-gate secure_getbyte(int fd)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate /* number of chars in ucbuf, pointer into ucbuf */
2900Sstevel@tonic-gate static uint_t nin, bufp;
2910Sstevel@tonic-gate int kerror;
2920Sstevel@tonic-gate uint_t length;
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate if (nin == 0) {
2950Sstevel@tonic-gate if ((kerror =
2960Sstevel@tonic-gate looping_read(fd, (char *)&length, sizeof (length)))
2970Sstevel@tonic-gate != sizeof (length)) {
2980Sstevel@tonic-gate secure_error("Couldn't read PROT buffer length: %d/%s",
2990Sstevel@tonic-gate kerror, (kerror == -1) ? strerror(errno) :
3000Sstevel@tonic-gate "premature EOF");
3010Sstevel@tonic-gate return (ERR);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate if ((length = ntohl((uint32_t)length)) > maxbuf) {
3040Sstevel@tonic-gate secure_error("Length (%d) of PROT buffer > PBSZ=%u",
3050Sstevel@tonic-gate length, maxbuf);
3060Sstevel@tonic-gate return (ERR);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate if ((kerror = looping_read(fd, (char *)ucbuf, length))
3090Sstevel@tonic-gate != length) {
3100Sstevel@tonic-gate secure_error("Couldn't read %u byte PROT buffer: %s",
3110Sstevel@tonic-gate length, kerror == -1 ?
3120Sstevel@tonic-gate strerror(errno) : "premature EOF");
3130Sstevel@tonic-gate return (ERR);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate /* Other auth types go here ... */
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate if (auth_type == AUTHTYPE_GSSAPI) {
3180Sstevel@tonic-gate gss_buffer_desc xmit_buf, msg_buf;
3190Sstevel@tonic-gate OM_uint32 maj_stat, min_stat;
3200Sstevel@tonic-gate int conf_state;
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate xmit_buf.value = ucbuf;
3230Sstevel@tonic-gate xmit_buf.length = length;
3240Sstevel@tonic-gate conf_state = (dlevel == PROT_P);
3250Sstevel@tonic-gate /* decrypt/verify the message */
3260Sstevel@tonic-gate maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
3270Sstevel@tonic-gate &msg_buf, &conf_state, NULL);
3280Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
3290Sstevel@tonic-gate user_gss_error(maj_stat, min_stat,
3300Sstevel@tonic-gate (dlevel == PROT_P)?
3310Sstevel@tonic-gate "failed unsealing ENC message":
3320Sstevel@tonic-gate "failed unsealing MIC message");
3330Sstevel@tonic-gate return (ERR);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate memcpy(ucbuf, msg_buf.value,
3370Sstevel@tonic-gate nin = bufp = msg_buf.length);
3380Sstevel@tonic-gate gss_release_buffer(&min_stat, &msg_buf);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate /* Other auth types go here ... */
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate return ((nin == 0) ? EOF : ucbuf[bufp - nin--]);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate * returns:
3470Sstevel@tonic-gate * 0 on success
3480Sstevel@tonic-gate * -1 on EOF
3490Sstevel@tonic-gate * -2 on security error
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate int
secure_getc(FILE * stream)3520Sstevel@tonic-gate secure_getc(FILE *stream)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate if (dlevel == PROT_C)
3550Sstevel@tonic-gate return (getc(stream));
3560Sstevel@tonic-gate return (secure_getbyte(fileno(stream)));
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /*
3600Sstevel@tonic-gate * returns:
3610Sstevel@tonic-gate * > 0 on success (n == # of bytes read)
3620Sstevel@tonic-gate * 0 on EOF
3630Sstevel@tonic-gate * -1 on error, errno set, only for PROT_C
3640Sstevel@tonic-gate * -2 on security error (ERR = -2)
3650Sstevel@tonic-gate */
3660Sstevel@tonic-gate ssize_t
secure_read(int fd,void * inbuf,size_t nbyte)3670Sstevel@tonic-gate secure_read(int fd, void *inbuf, size_t nbyte)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate int c, i;
3700Sstevel@tonic-gate char *buf = (char *)inbuf;
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate if (dlevel == PROT_C)
3730Sstevel@tonic-gate return (read(fd, buf, nbyte));
3740Sstevel@tonic-gate if (goteof)
3750Sstevel@tonic-gate return (goteof = 0);
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate for (i = 0; nbyte > 0; nbyte--)
3780Sstevel@tonic-gate switch (c = secure_getbyte(fd)) {
3790Sstevel@tonic-gate case ERR:
3800Sstevel@tonic-gate return (c);
3810Sstevel@tonic-gate case EOF:
3820Sstevel@tonic-gate goteof = i ? 1 : 0;
3830Sstevel@tonic-gate return (i);
3840Sstevel@tonic-gate default:
3850Sstevel@tonic-gate buf[i++] = c;
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate return (i);
3880Sstevel@tonic-gate }
389