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