Home | History | Annotate | Download | only in in.ftpd
      1 /*
      2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /*
      9  * gssutil.c
     10  *
     11  * Utility routines for providing security related services to
     12  * the FTP server.  This code uses the GSSAPI (RFC 2743, 2744)
     13  * to provide a generic security layer to the application.  The
     14  * security mechanism providing the actual security functions
     15  * is abstracted from the application itself.  In the case of the FTP
     16  * server, the security mechanism is based on what the client chooses
     17  * to use when it makes the secure connection.  If the client's
     18  * choice of GSS mechanism is not supported by the FTP server, the
     19  * connection may be rejected or fall back to standard Unix/PAM
     20  * authentication.
     21  *
     22  * This code is primarily intended to work with clients who choose
     23  * the Kerberos V5 GSSAPI mechanism as their security service.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if defined(USE_GSS)
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <sys/types.h>
     32 #include <ctype.h>
     33 #include <stdlib.h>
     34 #include <signal.h>
     35 #include <pwd.h>
     36 
     37 #include <netinet/in.h>
     38 #include <netinet/in_systm.h>
     39 #include <netinet/ip.h>
     40 
     41 #include <errno.h>
     42 #include <sys/param.h>
     43 #include <netdb.h>
     44 #ifdef HAVE_SYS_SYSLOG_H
     45 #include <sys/syslog.h>
     46 #endif
     47 
     48 /* CSTYLED */
     49 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
     50 #include <syslog.h>
     51 #endif
     52 
     53 #ifdef HAVE_SYSINFO
     54 #include <sys/systeminfo.h>
     55 #endif
     56 
     57 #include <arpa/ftp.h>
     58 
     59 #include "gssutil.h"
     60 #include "proto.h"
     61 
     62 static char *gss_services[] = { "ftp", "host", 0 };
     63 
     64 gss_info_t gss_info = {
     65 	/* context */ GSS_C_NO_CONTEXT,
     66 	/* mechoid */ GSS_C_NULL_OID,
     67 	/* client */  NULL,
     68 	/* display_name */ NULL,
     69 	/* data_prot */  PROT_C,
     70 	/* ctrl_prot */  PROT_C,
     71 	/* authstate */  GSS_AUTH_NONE,
     72 	/* want_creds */ 0,
     73 	/* have_creds */ 0,
     74 	/* must_auth  */ 0
     75 };
     76 
     77 
     78 extern char *cur_auth_type;
     79 extern struct SOCKSTORAGE his_addr;
     80 extern struct SOCKSTORAGE ctrl_addr;
     81 extern int debug;
     82 
     83 static char *radixN =
     84 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     85 
     86 static char pad = '=';
     87 
     88 #define	DEF_GSSBUF_SIZE 2028
     89 #define	DECODELEN(l)		(((3 * (l)) / 4) + 4)
     90 #define	ENCODELEN(l)		(((4 * (l)) / 3) + 4)
     91 
     92 typedef struct {
     93 	char   *buf;
     94 	size_t alloc_len;
     95 	size_t len;  /* max length of buffer */
     96 	size_t idx;  /* offset to beginning of read/write data */
     97 	size_t clen;  /* length of the remaining, decrypted data from client */
     98 }bufrec;
     99 
    100 static bufrec obr = {NULL, 0, 0, 0, 0};
    101 static bufrec ibr = {NULL, 0, 0, 0, 0};
    102 
    103 static int looping_write(int fd, const char *buf, size_t len);
    104 static int looping_read(int fd, char *buf, size_t len);
    105 static int radix_encode(unsigned char *inbuf, unsigned char *outbuf,
    106 			size_t len, int *outlen, int decode);
    107 static char *radix_error(int e);
    108 static void reply_gss_error(int code, OM_uint32 maj_stat,
    109 			OM_uint32 min_stat, gss_OID mechoid, char *s);
    110 static void cleanup_bufrec(bufrec *brec);
    111 static int alloc_bufrec(bufrec *brec, size_t newsz);
    112 static int sec_putbuf(int fd, unsigned char *buf, int len);
    113 static int sec_getbytes(int fd, char *buf, int nbytes);
    114 
    115 /*
    116  * Provide a routine so that ftpd can know the max amount to read
    117  */
    118 size_t
    119 gss_getinbufsz(void) {
    120 	return (ibr.len);
    121 }
    122 
    123 /*
    124  * gss_adjust_buflen
    125  *
    126  * Called when the protection method changes so we can adjust the
    127  * "useable" length of our output buffer accordingly.
    128  */
    129 void
    130 gss_adjust_buflen()
    131 {
    132 	OM_uint32 maj_stat, min_stat, mlen;
    133 
    134 	/*
    135 	 * If we switched to CLEAR protection, we can use the entire buffer
    136 	 */
    137 	if (gss_info.data_prot == PROT_C) {
    138 		obr.len = obr.alloc_len;
    139 		return;
    140 	}
    141 
    142 	/*
    143 	 * Otherwise, determine the maximum size that will allow for
    144 	 * the GSSAPI overhead to fit into the buffer size.
    145 	 */
    146 	maj_stat = gss_wrap_size_limit(&min_stat, gss_info.context,
    147 					(gss_info.data_prot == PROT_P),
    148 					GSS_C_QOP_DEFAULT,
    149 					(OM_uint32)obr.alloc_len, &mlen);
    150 	if (maj_stat != GSS_S_COMPLETE) {
    151 			reply_gss_error(535, maj_stat, min_stat,
    152 					gss_info.mechoid,
    153 					"GSSAPI fudge determination");
    154 			return;
    155 	}
    156 	obr.len = mlen;
    157 
    158 	if (debug)
    159 		syslog(LOG_DEBUG, "GSSAPI alloc_len = %d len = %d",
    160 		    obr.alloc_len, obr.len);
    161 }
    162 
    163 static int
    164 looping_write(int fd, const char *buf, size_t len)
    165 {
    166 	int cc;
    167 	register size_t wrlen = len;
    168 
    169 	do {
    170 		cc = write(fd, buf, wrlen);
    171 		if (cc < 0) {
    172 			if (errno == EINTR)
    173 				continue;
    174 			return (cc);
    175 		} else {
    176 			buf += cc;
    177 			wrlen -= cc;
    178 		}
    179 	} while (wrlen > 0);
    180 
    181 	return (len);
    182 }
    183 
    184 static int
    185 looping_read(int fd, char *buf, size_t len)
    186 {
    187 	int cc;
    188 	size_t len2 = 0;
    189 
    190 	do {
    191 		cc = read(fd, buf, len);
    192 		if (cc < 0) {
    193 			if (errno == EINTR)
    194 				continue;
    195 			return (cc);		 /* errno is already set */
    196 		} else if (cc == 0) {
    197 			return (len2);
    198 		} else {
    199 			buf += cc;
    200 			len2 += cc;
    201 			len -= cc;
    202 		}
    203 	} while (len > 0);
    204 	return (len2);
    205 }
    206 
    207 static int
    208 radix_encode(unsigned char *inbuf, unsigned char *outbuf,
    209 		size_t buflen, int *outlen, int decode)
    210 {
    211 	register int i, j, D;
    212 	char *p;
    213 	unsigned char c;
    214 
    215 	if (decode) {
    216 		for (i = 0, j = 0; (j < buflen) &&
    217 		    inbuf[i] && inbuf[i] != pad; i++) {
    218 			if ((p = strchr(radixN, inbuf[i])) == NULL)
    219 				return (1);
    220 			D = p - radixN;
    221 			switch (i&3) {
    222 			case 0:
    223 				outbuf[j] = D <<2;
    224 				break;
    225 			case 1:
    226 				outbuf[j++] |= D >>4;
    227 				outbuf[j] = (D&15)<<4;
    228 				break;
    229 			case 2:
    230 				outbuf[j++] |= D >>2;
    231 				outbuf[j] = (D&3)<<6;
    232 				break;
    233 			case 3:
    234 				outbuf[j++] |= D;
    235 			}
    236 		}
    237 		if (j == buflen && (inbuf[i] && inbuf[i] != pad)) {
    238 			/* Oops, we ran out of space in the output buffer */
    239 			return (4);
    240 		}
    241 		switch (i&3) {
    242 		case 1:
    243 			return (3);
    244 		case 2: if (D&15)
    245 				return (3);
    246 			if (strcmp((char *)&inbuf[i], "=="))
    247 				return (2);
    248 			break;
    249 		case 3: if (D&3)
    250 				return (3);
    251 			if (strcmp((char *)&inbuf[i], "="))
    252 				return (2);
    253 		}
    254 		*outlen = j;
    255 	} else {
    256 		for (i = 0, j = 0; i < *outlen && j < buflen; i++)
    257 			switch (i%3) {
    258 			case 0:
    259 				outbuf[j++] = radixN[inbuf[i]>>2];
    260 				c = (inbuf[i]&3)<<4;
    261 				break;
    262 			case 1:
    263 				outbuf[j++] = radixN[c|inbuf[i]>>4];
    264 				c = (inbuf[i]&15)<<2;
    265 				break;
    266 			case 2:
    267 				outbuf[j++] = radixN[c|inbuf[i]>>6];
    268 				outbuf[j++] = radixN[inbuf[i]&63];
    269 				c = 0;
    270 		}
    271 		if (j == buflen && i < *outlen) {
    272 			/* output buffer is not big enough */
    273 			return (4);
    274 		}
    275 
    276 		if (i%3) outbuf[j++] = radixN[c];
    277 		switch (i%3) {
    278 		case 1: outbuf[j++] = pad;
    279 		case 2: outbuf[j++] = pad;
    280 		}
    281 		outbuf[*outlen = j] = '\0';
    282 	}
    283 	return (0);
    284 }
    285 
    286 static char *
    287 radix_error(int e)
    288 {
    289 	switch (e) {
    290 		case 0:  return ("Success");
    291 		case 1:  return ("Bad character in encoding");
    292 		case 2:  return ("Encoding not properly padded");
    293 		case 3:  return ("Decoded # of bits not a multiple of 8");
    294 		case 4:  return ("Buffer size error");
    295 		default: return ("Unknown error");
    296 	}
    297 }
    298 
    299 static void
    300 reply_gss_error(int code, OM_uint32 maj_stat,
    301 	OM_uint32 min_stat, gss_OID mechoid, char *s)
    302 {
    303 	/* a lot of work just to report the error */
    304 	OM_uint32 gmaj_stat, gmin_stat;
    305 	gss_buffer_desc msg;
    306 	int msg_ctx;
    307 	msg_ctx = 0;
    308 
    309 	gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
    310 					GSS_C_GSS_CODE,
    311 					mechoid,
    312 					(OM_uint32 *)&msg_ctx, &msg);
    313 	if (gmaj_stat == GSS_S_COMPLETE) {
    314 		lreply(code, "GSSAPI error major: %s",
    315 			(char *)msg.value);
    316 			(void) gss_release_buffer(&gmin_stat, &msg);
    317 	}
    318 
    319 	gmaj_stat = gss_display_status(&gmin_stat, min_stat,
    320 					GSS_C_MECH_CODE,
    321 					mechoid,
    322 					(OM_uint32 *)&msg_ctx, &msg);
    323 	if (gmaj_stat == GSS_S_COMPLETE) {
    324 		lreply(code, "GSSAPI error minor: %s", (char *)msg.value);
    325 				(void) gss_release_buffer(&gmin_stat, &msg);
    326 	}
    327 
    328 	reply(code, "GSSAPI error: %s", s);
    329 }
    330 
    331 
    332 static void
    333 log_status(char *msg,
    334 	OM_uint32 status_code,
    335 	int status_type)
    336 {
    337 	OM_uint32 message_context;
    338 	gss_buffer_desc status_string;
    339 	OM_uint32 maj_status;
    340 	OM_uint32 min_status;
    341 
    342 	/* From RFC2744: */
    343 	message_context = 0;
    344 
    345 	do {
    346 		maj_status = gss_display_status(
    347 			&min_status,
    348 			status_code,
    349 			status_type,
    350 			GSS_C_NO_OID,
    351 			&message_context,
    352 			&status_string);
    353 
    354 		if (maj_status == GSS_S_COMPLETE) {
    355 			syslog(LOG_ERR,
    356 			    "GSSAPI Error %s: %.*s\n",
    357 			    msg ? msg : "<null>",
    358 			    (int)status_string.length,
    359 			    (char *)status_string.value);
    360 
    361 			(void) gss_release_buffer(&min_status,
    362 						&status_string);
    363 		} else {
    364 			syslog(LOG_ERR,
    365 		"log_status internal error: gss_display_status failed");
    366 			return;
    367 		}
    368 	} while (message_context != 0);
    369 
    370 }
    371 
    372 static void
    373 log_gss_error(char *msg,
    374 	    OM_uint32 maj_stat,
    375 	    OM_uint32 min_stat)
    376 {
    377 	log_status(msg, maj_stat, GSS_C_GSS_CODE);
    378 	log_status(msg, min_stat, GSS_C_MECH_CODE);
    379 }
    380 
    381 
    382 static void
    383 log_gss_info(int priority,
    384 	    char *luser,
    385 	    char *remprinc,
    386 	    gss_OID mechoid,
    387 	    char *s)
    388 {
    389 	const char *mechStr = __gss_oid_to_mech(mechoid);
    390 
    391 	syslog(priority,
    392 	    "%s: local user=`%s', remote princ=`%s', mech=%s",
    393 	    s ? s : "<null>",
    394 	    luser ? luser : "<null>",
    395 	    remprinc ? remprinc : "<unknown>",
    396 	    mechStr ? mechStr : "<unknown>");
    397 }
    398 
    399 /*
    400  * gss_user
    401  *
    402  * Handle USER command after AUTH GSSAPI
    403  *
    404  * Check if the remote user can login to the local system w/out a passwd.
    405  * Use the Solaris (private) interface (__gss_userok) if possible, else do
    406  * a basic GSS-API compare.
    407  *
    408  * return 0 == BAD
    409  *        1 == OK
    410  */
    411 int
    412 gss_user(struct passwd *user_pw)
    413 {
    414 	int retval = 0;
    415 	OM_uint32 status, minor;
    416 
    417 #ifdef SOLARIS_GSS_USEROK
    418 
    419 	int user_ok = 0;
    420 
    421 	if (debug)
    422 		log_gss_info(LOG_DEBUG,
    423 			    user_pw->pw_name, gss_info.display_name,
    424 			    gss_info.mechoid,
    425 			    "gss_user: start (gss_userok)");
    426 
    427 	/* gss_auth_rules(5) */
    428 	status = __gss_userok(&minor, gss_info.client,
    429 			    user_pw->pw_name, &user_ok);
    430 	if (status == GSS_S_COMPLETE) {
    431 		if (user_ok) {
    432 			retval = 1;  /* remote user is a-ok */
    433 		}
    434 	}
    435 
    436 #else /* SOLARIS_GSS_USEROK */
    437 
    438 	gss_name_t imported_name;
    439 	gss_name_t canon_name;
    440 	gss_buffer_desc gss_user;
    441 	OM_uint32 tmpMinor;
    442 	int match = 0;
    443 
    444 	if (debug)
    445 		log_gss_info(LOG_DEBUG,
    446 			    user_pw->pw_name, gss_info.display_name,
    447 			    gss_info.mechoid, "gss_user: start");
    448 
    449 	gss_user.value = user_pw->pw_name;
    450 	gss_user.length = strlen(gss_user.value);
    451 
    452 	status = gss_import_name(&minor,
    453 				&gss_user,
    454 				GSS_C_NT_USER_NAME,
    455 				&imported_name);
    456 	if (status != GSS_S_COMPLETE) {
    457 		goto out;
    458 	}
    459 
    460 	status = gss_canonicalize_name(&minor,
    461 				imported_name,
    462 				gss_info.mechoid,
    463 				&canon_name);
    464 	if (status != GSS_S_COMPLETE) {
    465 		(void) gss_release_name(&tmpMinor, &imported_name);
    466 		goto out;
    467 	}
    468 
    469 	status = gss_compare_name(&minor,
    470 				canon_name,
    471 				gss_info.client,
    472 				&match);
    473 	(void) gss_release_name(&tmpMinor, &canon_name);
    474 	(void) gss_release_name(&tmpMinor, &imported_name);
    475 	if (status == GSS_S_COMPLETE) {
    476 		if (match) {
    477 			retval = 1; /* remote user is a-ok */
    478 		}
    479 	}
    480 
    481 out:
    482 
    483 #endif /* SOLARIS_GSS_USEROK */
    484 
    485 	if (status != GSS_S_COMPLETE) {
    486 		log_gss_info(LOG_ERR, user_pw->pw_name,
    487 			    gss_info.display_name, gss_info.mechoid,
    488 			    "gss_user failed");
    489 		log_gss_error("gss_user failed", status, minor);
    490 	}
    491 
    492 	if (debug)
    493 		syslog(LOG_DEBUG, "gss_user: end: retval=%d", retval);
    494 
    495 	return (retval);
    496 }
    497 
    498 
    499 /*
    500  * gss_adat
    501  *
    502  * Handle ADAT(Authentication Data) command data.
    503  */
    504 int
    505 gss_adat(char *adatstr)
    506 {
    507 	int kerror, length;
    508 	int replied = 0;
    509 	int ret_flags;
    510 	gss_buffer_desc tok, out_tok;
    511 	gss_cred_id_t deleg_creds = NULL;
    512 	OM_uint32 accept_maj, accept_min;
    513 	OM_uint32 stat_maj, stat_min;
    514 	uchar_t *gout_buf;
    515 	size_t outlen;
    516 
    517 	length = strlen(adatstr);
    518 	outlen = DECODELEN(length);
    519 
    520 	gout_buf = (uchar_t *)malloc(outlen);
    521 	if (gout_buf == NULL) {
    522 		reply(501, "Couldn't decode ADAT, not enough memory");
    523 		syslog(LOG_ERR, "Couldn't decode ADAT, not enough memory");
    524 		return (0);
    525 	}
    526 
    527 	if ((kerror = radix_encode((unsigned char *)adatstr,
    528 				(unsigned char *)gout_buf,
    529 				outlen, &length, 1))) {
    530 		reply(501, "Couldn't decode ADAT(%s)",
    531 		    radix_error(kerror));
    532 		syslog(LOG_ERR, "Couldn't decode ADAT(%s)",
    533 		    radix_error(kerror));
    534 		return (0);
    535 	}
    536 	tok.value = gout_buf;
    537 	tok.length = length;
    538 
    539 	gss_info.context = GSS_C_NO_CONTEXT;
    540 
    541 	/*
    542 	 * Call accept_sec_context w/GSS_C_NO_CREDENTIAL to request
    543 	 * default cred and to not limit the service name to one name
    544 	 * but rather accept what the clnt requests if service
    545 	 * princ/keys are available.
    546 	 */
    547 	if (debug)
    548 		syslog(LOG_DEBUG,
    549 		    "gss_adat: accept_sec_context will try default cred");
    550 
    551 	out_tok.value = NULL;
    552 	out_tok.length = 0;
    553 
    554 	accept_maj = gss_accept_sec_context(&accept_min,
    555 					    &gss_info.context,
    556 					    GSS_C_NO_CREDENTIAL,
    557 					    &tok, /* ADAT data */
    558 					    GSS_C_NO_CHANNEL_BINDINGS,
    559 					    &gss_info.client,
    560 					    &gss_info.mechoid,
    561 					    &out_tok, /* output_token */
    562 					    (unsigned int *)&ret_flags,
    563 					    NULL, /* ignore time_rec */
    564 					    NULL); /* delegated creds */
    565 
    566 
    567 	if (debug) {
    568 		if (accept_maj == GSS_S_COMPLETE)
    569 			syslog(LOG_DEBUG,
    570 			    "gss_adat: accept_maj = GSS_S_COMPLETE");
    571 		else if (accept_maj == GSS_S_CONTINUE_NEEDED)
    572 			syslog(LOG_DEBUG,
    573 			    "gss_adat: accept_maj = GSS_S_CONTINUE_NEEDED");
    574 	}
    575 	free(gout_buf);
    576 
    577 	if (accept_maj != GSS_S_COMPLETE &&
    578 	    accept_maj != GSS_S_CONTINUE_NEEDED) {
    579 		reply_gss_error(535, accept_maj, accept_min,
    580 				GSS_C_NO_OID, "accepting context");
    581 		syslog(LOG_ERR, "failed accepting context");
    582 		if ((ret_flags & GSS_C_DELEG_FLAG) &&
    583 		    deleg_creds != NULL)
    584 			(void) gss_release_cred(&stat_min,
    585 						&deleg_creds);
    586 
    587 		(void) gss_release_buffer(&stat_min, &out_tok);
    588 		return (0);
    589 	}
    590 
    591 	if (debug)
    592 		syslog(LOG_DEBUG, "gss_adat: out_tok.length=%d",
    593 			out_tok.length);
    594 	if (out_tok.length) {
    595 		size_t buflen = ENCODELEN(out_tok.length);
    596 		uchar_t *gbuf = (uchar_t *)malloc(buflen);
    597 		if (gbuf == NULL) {
    598 			reply(535, "Couldn't encode ADAT reply, "
    599 			    "not enough memory.");
    600 			syslog(LOG_ERR, "Couldn't encode ADAT reply, "
    601 			    "not enough memory.");
    602 			(void) gss_release_buffer(&stat_min, &out_tok);
    603 			return (0);
    604 		}
    605 		if ((kerror = radix_encode(out_tok.value,
    606 					(unsigned char *)gbuf,
    607 					buflen, (int *)&out_tok.length,
    608 					0))) {
    609 			reply(535, "Couldn't encode ADAT reply(%s)",
    610 			    radix_error(kerror));
    611 			syslog(LOG_ERR, "couldn't encode ADAT reply");
    612 			if ((ret_flags & GSS_C_DELEG_FLAG) &&
    613 				deleg_creds != NULL)
    614 				(void) gss_release_cred(&stat_min,
    615 							&deleg_creds);
    616 
    617 			(void) gss_release_buffer(&stat_min, &out_tok);
    618 			free(gbuf);
    619 			return (0);
    620 		}
    621 
    622 		if (accept_maj == GSS_S_COMPLETE) {
    623 			reply(235, "ADAT=%s", gbuf);
    624 			replied = 1;
    625 		} else {
    626 			/*
    627 			 * If the server accepts the security data, and
    628 			 * requires additional data, it should respond
    629 			 * with reply code 335.
    630 			 */
    631 			reply(335, "ADAT=%s", gbuf);
    632 		}
    633 		free(gbuf);
    634 		(void) gss_release_buffer(&stat_min, &out_tok);
    635 	}
    636 	if (accept_maj == GSS_S_COMPLETE) {
    637 		gss_buffer_desc namebuf;
    638 		gss_OID out_oid;
    639 
    640 		/* GSSAPI authentication succeeded */
    641 		gss_info.authstate = GSS_ADAT_DONE;
    642 		(void) alloc_bufrec(&obr, DEF_GSSBUF_SIZE);
    643 		(void) alloc_bufrec(&ibr, DEF_GSSBUF_SIZE);
    644 		/*
    645 		 * RFC 2228 - "..., once a security data exchange completes
    646 		 * successfully, if the security mechanism supports
    647 		 * integrity, then integrity(via the MIC or ENC command,
    648 		 * and 631 or 632 reply) must be used, ..."
    649 		 */
    650 		gss_info.ctrl_prot = PROT_S;
    651 
    652 		stat_maj = gss_display_name(&stat_min, gss_info.client,
    653 					    &namebuf, &out_oid);
    654 		if (stat_maj != GSS_S_COMPLETE) {
    655 			/*
    656 			 * RFC 2228 -
    657 			 * "If the server rejects the security data(if
    658 			 * a checksum fails, for instance), it should
    659 			 * respond with reply code 535."
    660 			 */
    661 			reply_gss_error(535, stat_maj, stat_min,
    662 					gss_info.mechoid,
    663 					"extracting GSSAPI identity name");
    664 			syslog(LOG_ERR, "gssapi error extracting identity");
    665 			if ((ret_flags & GSS_C_DELEG_FLAG) &&
    666 			    deleg_creds != NULL)
    667 				(void) gss_release_cred(&stat_min,
    668 							&deleg_creds);
    669 			return (0);
    670 		}
    671 		gss_info.display_name = (char *)namebuf.value;
    672 
    673 		if (ret_flags & GSS_C_DELEG_FLAG) {
    674 			gss_info.have_creds = 1;
    675 			if (deleg_creds != NULL)
    676 				(void) gss_release_cred(&stat_min,
    677 							&deleg_creds);
    678 		}
    679 
    680 		/*
    681 		 * If the server accepts the security data, but does
    682 		 * not require any additional data(i.e., the security
    683 		 * data exchange has completed successfully), it must
    684 		 * respond with reply code 235.
    685 		 */
    686 		if (!replied) {
    687 			if ((ret_flags & GSS_C_DELEG_FLAG) &&
    688 			    !gss_info.have_creds)
    689 				reply(235,
    690 				    "GSSAPI Authentication succeeded, but "
    691 				    "could not accept forwarded credentials");
    692 			else
    693 				reply(235, "GSSAPI Authentication succeeded");
    694 		}
    695 		return (1);
    696 	} else if (accept_maj == GSS_S_CONTINUE_NEEDED) {
    697 		/*
    698 		 * If the server accepts the security data, and
    699 		 * requires additional data, it should respond with
    700 		 * reply code 335.
    701 		 */
    702 		reply(335, "more data needed");
    703 		if ((ret_flags & GSS_C_DELEG_FLAG) &&
    704 		    deleg_creds != NULL)
    705 			(void) gss_release_cred(&stat_min, &deleg_creds);
    706 	}
    707 
    708 	return (0);
    709 }
    710 
    711 /*
    712  * cleanup_bufrec
    713  *
    714  * cleanup the secure buffers
    715  */
    716 static void
    717 cleanup_bufrec(bufrec *brec)
    718 {
    719 	if (brec->buf)
    720 		free(brec->buf);
    721 	brec->len = 0;
    722 	brec->clen = 0;
    723 	brec->idx = 0;
    724 }
    725 
    726 static int
    727 alloc_bufrec(bufrec *brec, size_t newsz)
    728 {
    729 	/*
    730 	 * Try to allocate a buffer, if it fails,
    731 	 * divide by 2 and try again.
    732 	 */
    733 	cleanup_bufrec(brec);
    734 
    735 	while (newsz > 0 && !(brec->buf = malloc(newsz))) {
    736 		syslog(LOG_ERR,
    737 		    "malloc bufrec(%d bytes) failed, trying %d",
    738 		    newsz >>= 1);
    739 	}
    740 
    741 	if (brec->buf == NULL)
    742 		return (-1);
    743 
    744 	brec->alloc_len = newsz;
    745 	brec->len = newsz;
    746 	brec->clen = 0;
    747 	brec->idx = 0;
    748 	return (0);
    749 }
    750 
    751 /*
    752  * Handle PBSZ command data, return value to caller.
    753  * RFC 2228 says this is a 32 bit int, so limit max value here.
    754  */
    755 unsigned int
    756 gss_setpbsz(char *pbszstr)
    757 {
    758 	unsigned int newsz = 0;
    759 	char *endp;
    760 #define	MAX_PBSZ 4294967295U
    761 
    762 	errno = 0;
    763 	newsz = (unsigned int)strtol(pbszstr, &endp, 10);
    764 	if (errno != 0 || newsz > MAX_PBSZ || *endp != '\0') {
    765 		reply(501, "Bad value for PBSZ: %s", pbszstr);
    766 		return (0);
    767 	}
    768 
    769 	if (newsz > ibr.len) {
    770 		if (alloc_bufrec(&obr, newsz) == -1) {
    771 			perror_reply(421, "Local resource failure: malloc");
    772 			dologout(1);
    773 		}
    774 		if (alloc_bufrec(&ibr, newsz) == -1) {
    775 			perror_reply(421, "Local resource failure: malloc");
    776 			dologout(1);
    777 		}
    778 	}
    779 	reply(200, "PBSZ =%lu", ibr.len);
    780 
    781 	return (ibr.len);
    782 }
    783 
    784 /*
    785  * sec_putbuf
    786  *
    787  * Wrap the plaintext 'buf' data using gss_wrap and send
    788  * it out.
    789  *
    790  * returns:
    791  *    bytes written (success)
    792  *   -1 on error(errno set)
    793  *   -2 on security error
    794  */
    795 static int
    796 sec_putbuf(int fd, unsigned char *buf, int len)
    797 {
    798 	unsigned long net_len;
    799 	int ret = 0;
    800 	gss_buffer_desc in_buf, out_buf;
    801 	OM_uint32 maj_stat, min_stat;
    802 	int conf_state;
    803 
    804 	in_buf.value = buf;
    805 	in_buf.length = len;
    806 	maj_stat = gss_wrap(&min_stat, gss_info.context,
    807 			    (gss_info.data_prot == PROT_P),
    808 			    GSS_C_QOP_DEFAULT,
    809 			    &in_buf, &conf_state,
    810 			    &out_buf);
    811 
    812 	if (maj_stat != GSS_S_COMPLETE) {
    813 		reply_gss_error(535, maj_stat, min_stat,
    814 				gss_info.mechoid,
    815 				gss_info.data_prot == PROT_P ?
    816 				"GSSAPI wrap failed":
    817 				"GSSAPI sign failed");
    818 		return (-2);
    819 	}
    820 
    821 	net_len = (unsigned long)htonl((unsigned long) out_buf.length);
    822 
    823 	if ((ret = looping_write(fd, (const char *)&net_len, 4)) != 4) {
    824 		syslog(LOG_ERR, "Error writing net_len(%d): %m", net_len);
    825 		ret = -1;
    826 		goto putbuf_done;
    827 	}
    828 
    829 	if ((ret = looping_write(fd, out_buf.value, out_buf.length)) !=
    830 		out_buf.length) {
    831 		syslog(LOG_ERR, "Error writing %d bytes: %m", out_buf.length);
    832 		ret = -1;
    833 		goto putbuf_done;
    834 	}
    835 putbuf_done:
    836 
    837 	gss_release_buffer(&min_stat, &out_buf);
    838 	return (ret);
    839 }
    840 
    841 /*
    842  * sec_write
    843  *
    844  * If GSSAPI security is established, encode the output
    845  * and write it to the client.  Else, just write it directly.
    846  */
    847 int
    848 sec_write(int fd, char *buf, int len)
    849 {
    850 	int nbytes = 0;
    851 	if (gss_info.data_prot == PROT_C ||
    852 	    !IS_GSSAUTH(cur_auth_type) ||
    853 	    !(gss_info.authstate & GSS_ADAT_DONE))
    854 		nbytes = write(fd, buf, len);
    855 	else {
    856 		/*
    857 		 * Fill up the buffer before actually encrypting
    858 		 * and writing it out.
    859 		 */
    860 		while ((obr.idx < obr.len) && (len > 0)) {
    861 			int n, ret;
    862 
    863 			/* how many bytes can we fit into the buffer? */
    864 			n = (len < (obr.len - obr.idx) ? len :
    865 			    obr.len - obr.idx);
    866 			memcpy(obr.buf + obr.idx, buf, n);
    867 
    868 			obr.idx += n;
    869 
    870 			if (obr.idx >= obr.len) {
    871 				ret = sec_putbuf(fd, (unsigned char *)obr.buf,
    872 					obr.idx);
    873 				obr.idx = 0;
    874 				if (ret < 0)
    875 					return (ret);
    876 			}
    877 			len -= n;
    878 			nbytes += n;
    879 		}
    880 	}
    881 
    882 	return (nbytes);
    883 }
    884 
    885 /*
    886  * CCC
    887  *
    888  * Clear Command Channel.
    889  *
    890  * We will understand this command but not allow it in a secure
    891  * connection.  It is very dangerous to allow someone to degrade
    892  * the security of the command channel.  See RFC2228 for more info.
    893  */
    894 void
    895 ccc(void)
    896 {
    897 	/*
    898 	 * Once we have negotiated security successfully,
    899 	 * do not allow the control channel to be downgraded.
    900 	 * It should be at least SAFE if not PRIVATE.
    901 	 */
    902 	if (IS_GSSAUTH(cur_auth_type) &&
    903 	    (gss_info.authstate & GSS_ADAT_DONE) == GSS_ADAT_DONE)
    904 		reply(534, "Control channel may not be downgraded");
    905 	else {
    906 		gss_info.ctrl_prot = PROT_C;
    907 		reply(200, "CCC ok");
    908 	}
    909 }
    910 
    911 int
    912 sec_putc(int c, FILE *stream)
    913 {
    914 	int ret = 0;
    915 	/*
    916 	 * If we are NOT protecting the data
    917 	 * OR not using the GSSAPI authentication
    918 	 * OR GSSAPI data is not yet completed, send
    919 	 * plaintext.
    920 	 */
    921 	if (gss_info.data_prot == PROT_C ||
    922 	    !IS_GSSAUTH(cur_auth_type) ||
    923 	    !(gss_info.authstate & GSS_ADAT_DONE))
    924 		return (putc(c, stream));
    925 
    926 	/*
    927 	 * Add the latest byte to the current buffer
    928 	 */
    929 	if (obr.idx < obr.len) {
    930 		obr.buf[obr.idx++] = (unsigned char)(c & 0xff);
    931 	}
    932 
    933 	if (obr.idx == obr.len) {
    934 		ret = sec_putbuf(fileno(stream), (uchar_t *)obr.buf, obr.idx);
    935 		if (ret >= 0)
    936 			ret = 0;
    937 		obr.idx = 0;
    938 	}
    939 
    940 	return ((ret == 0 ? c : ret));
    941 }
    942 
    943 int
    944 sec_fprintf(FILE *stream, char *fmt, ...)
    945 {
    946 	int ret;
    947 	va_list ap;
    948 	va_start(ap, fmt);
    949 
    950 	if (gss_info.data_prot == PROT_C ||
    951 	    !IS_GSSAUTH(cur_auth_type) ||
    952 	    !(gss_info.authstate & GSS_ADAT_DONE)) {
    953 		ret = vfprintf(stream, fmt, ap);
    954 	} else {
    955 		(void) vsnprintf(obr.buf, obr.len, fmt, ap);
    956 		ret = sec_putbuf(fileno(stream), (unsigned char *)obr.buf,
    957 				strlen(obr.buf));
    958 	}
    959 	va_end(ap);
    960 	return (ret);
    961 }
    962 
    963 /*
    964  * sec_fflush
    965  *
    966  * If GSSAPI protection is configured, write out whatever remains
    967  * in the output buffer using the secure routines, otherwise
    968  * just flush the stream.
    969  */
    970 int
    971 sec_fflush(FILE *stream)
    972 {
    973 	int ret = 0;
    974 	if (gss_info.data_prot == PROT_C ||
    975 	    !IS_GSSAUTH(cur_auth_type) ||
    976 	    !(gss_info.authstate & GSS_ADAT_DONE)) {
    977 		fflush(stream);
    978 		return (0);
    979 	}
    980 	if (obr.idx > 0) {
    981 		ret = sec_putbuf(fileno(stream),
    982 				(unsigned char *)obr.buf, obr.idx);
    983 		obr.idx = 0;
    984 	}
    985 
    986 	if (ret >= 0)
    987 		ret = sec_putbuf(fileno(stream), (unsigned char *)"", 0);
    988 	/*
    989 	 * putbuf returns number of bytes or a negative value,
    990 	 * but fflush must return 0 or -1, so adjust the return
    991 	 * value so that a positive value is interpreted as success.
    992 	 */
    993 	return (ret >= 0 ? 0 : ret);
    994 }
    995 
    996 /*
    997  * sec_getbytes
    998  *
    999  * Read and decrypt from the secure data channel.
   1000  *
   1001  * Return:
   1002  *   > 0 == number of bytes available in gssbuf
   1003  *   EOF == End of file.
   1004  *   -2 == GSS error.
   1005  *
   1006  */
   1007 static int
   1008 sec_getbytes(int fd, char *buf, int nbytes)
   1009 {
   1010 	/*
   1011 	 * Only read from the network if our current buffer
   1012 	 * is all used up.
   1013 	 */
   1014 	if (ibr.idx >= ibr.clen) {
   1015 		int kerror;
   1016 		int conf_state;
   1017 		unsigned int length;
   1018 		gss_buffer_desc xmit_buf, msg_buf;
   1019 		OM_uint32 maj_stat, min_stat;
   1020 
   1021 		if ((kerror = looping_read(fd, (char *)&length, 4)) != 4) {
   1022 			reply(535, "Couldn't read PROT buffer length: %d/%s",
   1023 			    kerror,
   1024 			    (kerror == -1) ? strerror(errno) : "premature EOF");
   1025 			return (-2);
   1026 		}
   1027 
   1028 		if ((length = (unsigned int)ntohl(length)) > ibr.len) {
   1029 			reply(535, "Length(%d) > PBSZ(%d)", length, ibr.len);
   1030 			return (-2);
   1031 		}
   1032 
   1033 		if (length > 0) {
   1034 			if ((kerror = looping_read(fd, ibr.buf, length)) !=
   1035 				length) {
   1036 				reply(535, "Couldn't read %u byte PROT buf: %s",
   1037 					length, (kerror == -1) ?
   1038 					strerror(errno) : "premature EOF");
   1039 				return (-2);
   1040 			}
   1041 
   1042 			xmit_buf.value = (char *)ibr.buf;
   1043 			xmit_buf.length = length;
   1044 
   1045 			conf_state = (gss_info.data_prot == PROT_P);
   1046 
   1047 			/* decrypt/verify the message */
   1048 			maj_stat = gss_unwrap(&min_stat, gss_info.context,
   1049 					&xmit_buf, &msg_buf, &conf_state, NULL);
   1050 			if (maj_stat != GSS_S_COMPLETE) {
   1051 				reply_gss_error(535, maj_stat, min_stat,
   1052 					gss_info.mechoid,
   1053 					(gss_info.data_prot == PROT_P)?
   1054 					"failed unwrapping ENC message":
   1055 					"failed unwrapping MIC message");
   1056 				return (-2);
   1057 			}
   1058 
   1059 			memcpy(ibr.buf, msg_buf.value, msg_buf.length);
   1060 			ibr.clen = msg_buf.length;
   1061 			ibr.idx = 0;
   1062 
   1063 			gss_release_buffer(&min_stat, &msg_buf);
   1064 		} else {
   1065 			ibr.idx = 0;
   1066 			ibr.clen = 0;
   1067 			return (EOF);
   1068 		}
   1069 	}
   1070 
   1071 	/*
   1072 	 * If there are 'nbytes' of plain text available, use them, else
   1073 	 * get whats available.
   1074 	 */
   1075 	nbytes = (nbytes < (ibr.clen - ibr.idx) ? nbytes : ibr.clen - ibr.idx);
   1076 
   1077 	memcpy(buf, ibr.buf + ibr.idx, nbytes);
   1078 	ibr.idx += nbytes;
   1079 
   1080 	return ((nbytes == 0 ? EOF : nbytes));
   1081 }
   1082 
   1083 /*
   1084  * Get a buffer of 'maxlen' bytes from the client.
   1085  * If we are using GSSAPI protection, use the secure
   1086  * input buffer.
   1087  */
   1088 int
   1089 sec_read(int fd, char *buf, int maxlen)
   1090 {
   1091 	int nbytes = 0;
   1092 
   1093 	if (gss_info.data_prot != PROT_C &&
   1094 	    IS_GSSAUTH(cur_auth_type) &&
   1095 	    (gss_info.authstate & GSS_ADAT_DONE)) {
   1096 		/* Get as much data as possible */
   1097 		nbytes = sec_getbytes(fd, buf, maxlen);
   1098 		if (nbytes == EOF)
   1099 			nbytes = 0;
   1100 	} else {
   1101 		nbytes = read(fd, buf, maxlen);
   1102 	}
   1103 	return (nbytes);
   1104 }
   1105 
   1106 /*
   1107  * sec_getc
   1108  *
   1109  * Get a single character from the secure network buffer.
   1110  */
   1111 int
   1112 sec_getc(FILE *stream)
   1113 {
   1114 	int nbytes;
   1115 	unsigned char c;
   1116 
   1117 	if (gss_info.data_prot != PROT_C &&
   1118 	    IS_GSSAUTH(cur_auth_type) &&
   1119 	    (gss_info.authstate & GSS_ADAT_DONE)) {
   1120 		nbytes = sec_getbytes(fileno(stream), (char *)&c, 1);
   1121 		if (nbytes > 0)
   1122 			nbytes = (int)c;
   1123 		return (nbytes);
   1124 	} else
   1125 		return (getc(stream));
   1126 }
   1127 
   1128 /*
   1129  * sec_reply
   1130  *
   1131  * Securely encode a reply destined for the ftp client
   1132  * depending on the GSSAPI settings.
   1133  */
   1134 int
   1135 sec_reply(char *buf, int bufsiz, int n)
   1136 {
   1137 	char  *out = NULL, *in = NULL;
   1138 	size_t inlen;
   1139 	gss_buffer_desc in_buf, out_buf;
   1140 	OM_uint32 maj_stat, min_stat;
   1141 	int conf_state, length, kerror;
   1142 	int ret = 0;
   1143 
   1144 	if (debug)
   1145 		syslog(LOG_DEBUG, "encoding %s", buf);
   1146 
   1147 	in_buf.value = buf;
   1148 	in_buf.length = strlen(buf) + 1;
   1149 	maj_stat = gss_wrap(&min_stat, gss_info.context,
   1150 			    gss_info.ctrl_prot == PROT_P,
   1151 			    GSS_C_QOP_DEFAULT,
   1152 			    &in_buf, &conf_state,
   1153 			    &out_buf);
   1154 	if (maj_stat != GSS_S_COMPLETE) {
   1155 		syslog(LOG_ERR, "gss_wrap %s did not complete",
   1156 		    (gss_info.ctrl_prot == PROT_P) ? "ENC": "MIC");
   1157 		ret = -2;
   1158 		gss_release_buffer(&min_stat, &out_buf);
   1159 		goto end;
   1160 	} else if ((gss_info.ctrl_prot == PROT_P) && !conf_state) {
   1161 		syslog(LOG_ERR, "gss_wrap did not encrypt message");
   1162 		ret = -2;
   1163 		gss_release_buffer(&min_stat, &out_buf);
   1164 		goto end;
   1165 	} else {
   1166 		out = (char *)malloc(out_buf.length);
   1167 		if (out == NULL) {
   1168 			syslog(LOG_ERR, "Memory error allocating buffer");
   1169 			ret = -2;
   1170 			gss_release_buffer(&min_stat, &out_buf);
   1171 			goto end;
   1172 		}
   1173 		memcpy(out, out_buf.value, out_buf.length);
   1174 		length = out_buf.length;
   1175 		gss_release_buffer(&min_stat, &out_buf);
   1176 		ret = 0;
   1177 	}
   1178 	/*
   1179 	 * Base64 encode the reply.  encrypted "out" becomes
   1180 	 * encoded "in" buffer.
   1181 	 * Stick it all back in 'buf' for final output.
   1182 	 */
   1183 	inlen = ENCODELEN(length);
   1184 	in = (char *)malloc(inlen);
   1185 	if (in == NULL) {
   1186 		syslog(LOG_ERR, "Memory error allocating buffer");
   1187 		ret = -2;
   1188 		goto end;
   1189 	}
   1190 	if ((kerror = radix_encode((unsigned char *)out,
   1191 				(unsigned char *)in, inlen,
   1192 				&length, 0))) {
   1193 		syslog(LOG_ERR, "Couldn't encode reply(%s)",
   1194 		    radix_error(kerror));
   1195 		strncpy(buf, in, bufsiz-1);
   1196 		buf[bufsiz - 1] = '\0';
   1197 	} else {
   1198 		snprintf(buf, bufsiz, "%s%c%s",
   1199 			gss_info.ctrl_prot == PROT_P ? "632" : "631",
   1200 			n ? ' ' : '-', in);
   1201 	}
   1202 end:
   1203 	if (in) free(in);
   1204 	if (out) free(out);
   1205 
   1206 	return (ret);
   1207 }
   1208 
   1209 /*
   1210  * sec_decode_command
   1211  *
   1212  * If a command is received which is encoded(ENC, MIC, or CONF),
   1213  * decode it here using GSSAPI.
   1214  */
   1215 char *
   1216 sec_decode_command(char *cmd)
   1217 {
   1218 	char *out = NULL, *cp;
   1219 	int len, mic, outlen;
   1220 	gss_buffer_desc xmit_buf, msg_buf;
   1221 	OM_uint32 maj_stat, min_stat;
   1222 	int conf_state;
   1223 	int kerror;
   1224 	char *cs;
   1225 	char *s = cmd;
   1226 
   1227 	if ((cs = strpbrk(s, " \r\n")))
   1228 		*cs++ = '\0';
   1229 	upper(s);
   1230 
   1231 	if ((mic = strcmp(s, "ENC")) != 0 && strcmp(s, "MIC") &&
   1232 		strcmp(s, "CONF")) {
   1233 		reply(533, "All commands must be protected.");
   1234 		syslog(LOG_ERR, "Unprotected command received %s", s);
   1235 		*s = '\0';
   1236 		return (s);
   1237 	}
   1238 
   1239 	if ((cp = strpbrk(cs, " \r\n")))
   1240 		*cp = '\0';
   1241 
   1242 	outlen = DECODELEN(strlen(cs));
   1243 
   1244 	out = (char *)malloc(outlen);
   1245 	if (out == NULL) {
   1246 		reply(501, "Cannot decode response - not enough memory");
   1247 		syslog(LOG_ERR, "Cannot decode response - not enough memory");
   1248 		*s = '\0';
   1249 		return (s);
   1250 	}
   1251 	len = strlen(cs);
   1252 	if ((kerror = radix_encode((unsigned char *)cs,
   1253 					(unsigned char *)out,
   1254 					outlen, &len, 1))) {
   1255 		reply(501, "Can't base 64 decode argument to %s command(%s)",
   1256 			mic ? "MIC" : "ENC", radix_error(kerror));
   1257 		*s = '\0';
   1258 		free(out);
   1259 		return (s);
   1260 	}
   1261 
   1262 	if (debug)
   1263 		syslog(LOG_DEBUG, "getline got %d from %s <%s >\n",
   1264 			len, cs, mic ? "MIC" : "ENC");
   1265 
   1266 	xmit_buf.value = out;
   1267 	xmit_buf.length = len;
   1268 
   1269 	/* decrypt the message */
   1270 	conf_state = !mic;
   1271 	maj_stat = gss_unwrap(&min_stat, gss_info.context, &xmit_buf,
   1272 			    &msg_buf, &conf_state, NULL);
   1273 	if (maj_stat == GSS_S_CONTINUE_NEEDED) {
   1274 		if (debug) syslog(LOG_DEBUG, "%s-unwrap continued",
   1275 				mic ? "MIC" : "ENC");
   1276 		reply(535, "%s-unwrap continued, oops", mic ? "MIC" : "ENC");
   1277 		*s = 0;
   1278 		free(out);
   1279 		return (s);
   1280 	}
   1281 
   1282 	free(out);
   1283 	if (maj_stat != GSS_S_COMPLETE) {
   1284 		reply_gss_error(535, maj_stat, min_stat,
   1285 				gss_info.mechoid,
   1286 				mic ? "failed unwrapping MIC message":
   1287 				"failed unwrapping ENC message");
   1288 		*s = 0;
   1289 		return (s);
   1290 	}
   1291 
   1292 	memcpy(s, msg_buf.value, msg_buf.length);
   1293 	strcpy(s + msg_buf.length-(s[msg_buf.length-1] ? 0 : 1), "\r\n");
   1294 	gss_release_buffer(&min_stat, &msg_buf);
   1295 
   1296 	return (s);
   1297 }
   1298 
   1299 #endif /* defined(USE_GSS) */
   1300