xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/gssutil.c (revision 530:bbb8de18489d)
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
gss_getinbufsz(void)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
gss_adjust_buflen()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
looping_write(int fd,const char * buf,size_t len)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
looping_read(int fd,char * buf,size_t len)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
radix_encode(unsigned char * inbuf,unsigned char * outbuf,size_t buflen,int * outlen,int decode)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 *
radix_error(int e)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
reply_gss_error(int code,OM_uint32 maj_stat,OM_uint32 min_stat,gss_OID mechoid,char * s)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
log_status(char * msg,OM_uint32 status_code,int status_type)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
log_gss_error(char * msg,OM_uint32 maj_stat,OM_uint32 min_stat)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
log_gss_info(int priority,char * luser,char * remprinc,gss_OID mechoid,char * s)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
gss_user(struct passwd * user_pw)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
gss_adat(char * adatstr)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
cleanup_bufrec(bufrec * brec)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
alloc_bufrec(bufrec * brec,size_t newsz)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
gss_setpbsz(char * pbszstr)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
sec_putbuf(int fd,unsigned char * buf,int len)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
sec_write(int fd,char * buf,int len)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
ccc(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
sec_putc(int c,FILE * stream)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
sec_fprintf(FILE * stream,char * fmt,...)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
sec_fflush(FILE * stream)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
sec_getbytes(int fd,char * buf,int nbytes)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
sec_read(int fd,char * buf,int maxlen)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
sec_getc(FILE * stream)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
sec_reply(char * buf,int bufsiz,int n)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 *
sec_decode_command(char * cmd)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