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