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
62static char *gss_services[] = { "ftp", "host", 0 };
63
64gss_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
78extern char *cur_auth_type;
79extern struct SOCKSTORAGE his_addr;
80extern struct SOCKSTORAGE ctrl_addr;
81extern int debug;
82
83static char *radixN =
84	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
85
86static 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
92typedef 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
100static bufrec obr = {NULL, 0, 0, 0, 0};
101static bufrec ibr = {NULL, 0, 0, 0, 0};
102
103static int looping_write(int fd, const char *buf, size_t len);
104static int looping_read(int fd, char *buf, size_t len);
105static int radix_encode(unsigned char *inbuf, unsigned char *outbuf,
106			size_t len, int *outlen, int decode);
107static char *radix_error(int e);
108static void reply_gss_error(int code, OM_uint32 maj_stat,
109			OM_uint32 min_stat, gss_OID mechoid, char *s);
110static void cleanup_bufrec(bufrec *brec);
111static int alloc_bufrec(bufrec *brec, size_t newsz);
112static int sec_putbuf(int fd, unsigned char *buf, int len);
113static 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 */
118size_t
119gss_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 */
129void
130gss_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
163static int
164looping_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
184static int
185looping_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
207static int
208radix_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
286static char *
287radix_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
299static void
300reply_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
332static void
333log_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
372static void
373log_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
382static void
383log_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 */
411int
412gss_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
481out:
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 */
504int
505gss_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 */
716static void
717cleanup_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
726static int
727alloc_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 */
755unsigned int
756gss_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 */
795static int
796sec_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	}
835putbuf_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 */
847int
848sec_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 */
894void
895ccc(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
911int
912sec_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
943int
944sec_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 */
970int
971sec_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 */
1007static int
1008sec_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 */
1088int
1089sec_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 */
1111int
1112sec_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 */
1134int
1135sec_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	}
1202end:
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 */
1215char *
1216sec_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