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