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