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
looping_write(int fd,const char * buf,int len)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
looping_read(int fd,char * buf,int len)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
secure_error(char * fmt,...)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
secure_determine_constants(void)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
secure_putbyte(int fd,uchar_t c)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
secure_flush(int fd)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
secure_putc(int c,FILE * stream)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
secure_write(int fd,const void * inbuf,size_t nbyte)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 */
secure_putbuf(int fd,uchar_t * buf,uint_t nbyte)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
secure_getbyte(int fd)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
secure_getc(FILE * stream)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
secure_read(int fd,void * inbuf,size_t nbyte)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