2 * Shared routines for client and server for
3 * secure read(), write(), getc(), and putc().
4 * Only one security context, thus only work on one fd at a time!
7 #include <secure.h> /* stuff which is specific to client or server */
9 #ifdef KRB5_KRB4_COMPAT
13 extern KTEXT_ST ticket;
14 extern MSG_DAT msg_data;
15 extern Key_schedule schedule;
16 #endif /* KRB5_KRB4_COMPAT */
18 #include <gssapi/gssapi.h>
19 #include <gssapi/gssapi_generic.h>
20 extern gss_ctx_id_t gcontext;
30 #include <sys/types.h>
31 #include <netinet/in.h>
34 #ifdef NEED_SYS_ERRLIST
35 extern char *sys_errlist[];
38 #if (SIZEOF_SHORT == 4)
39 typedef unsigned short ftp_uint32;
40 typedef short ftp_int32;
41 #elif (SIZEOF_INT == 4)
42 typedef unsigned int ftp_uint32;
43 typedef int ftp_int32;
44 #elif (SIZEOF_LONG == 4)
45 typedef unsigned long ftp_uint32;
46 typedef long ftp_int32;
50 extern struct sockaddr_in hisaddr;
51 extern struct sockaddr_in myaddr;
53 extern char *auth_type;
55 /* Some libc's (GNU libc, at least) define MAX as a macro. Forget that. */
61 extern unsigned int maxbuf; /* maximum output buffer size */
62 extern unsigned char *ucbuf; /* cleartext buffer */
63 static unsigned int nout, bufp; /* number of chars in ucbuf,
64 * pointer into ucbuf */
66 #ifdef KRB5_KRB4_COMPAT
67 #define FUDGE_FACTOR 32 /* Amount of growth
68 * from cleartext to ciphertext.
69 * krb_mk_priv adds this # bytes.
70 * Must be defined for each auth type.
72 #endif /* KRB5_KRB4_COMPAT */
76 #define FUDGE_FACTOR 64 /*It appears to add 52 byts, but I'm not usre it is a constant--hartmans*/
79 #ifndef FUDGE_FACTOR /* In case no auth types define it. */
80 #define FUDGE_FACTOR 0
83 #ifdef KRB5_KRB4_COMPAT
84 /* XXX - The following must be redefined if KERBEROS_V4 is not used
85 * but some other auth type is. They must have the same properties. */
86 #define looping_write krb_net_write
87 #define looping_read krb_net_read
90 /* perhaps use these in general, certainly use them for GSSAPI */
94 looping_write(fd, buf, len)
96 register const char *buf;
100 register int wrlen = len;
102 cc = write(fd, buf, wrlen);
118 looping_read(fd, buf, len)
126 cc = read(fd, buf, len);
130 return(cc); /* errno is already set */
145 #if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
146 extern secure_error(char *, ...);
148 extern secure_error();
154 secure_putbyte(fd, c)
161 if (nout == MAX - FUDGE_FACTOR) {
163 ret = secure_putbuf(fd, ucbuf, MAX - FUDGE_FACTOR);
171 * -1 on error (errno set)
172 * -2 on security error
179 if (dlevel == PROT_C)
182 if (ret = secure_putbuf(fd, ucbuf, nout))
184 return(secure_putbuf(fd, "", nout = 0));
190 * -2 on security error
192 secure_putc(c, stream)
196 if (dlevel == PROT_C)
197 return(putc(c,stream));
198 return(secure_putbyte(fileno(stream), (unsigned char) c));
203 * -1 on error (errno set)
204 * -2 on security error
206 secure_write(fd, buf, nbyte)
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)
224 * -1 on error (errno set)
225 * -2 on security error
227 secure_putbuf(fd, buf, nbyte)
232 static char *outbuf; /* output ciphertext */
233 static unsigned int bufsize; /* size of outbuf */
237 /* Other auth types go here ... */
238 #ifdef KRB5_KRB4_COMPAT
239 if (bufsize < nbyte + FUDGE_FACTOR) {
241 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
242 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
243 bufsize =nbyte + FUDGE_FACTOR;
246 secure_error("%s (in malloc of PROT buffer)",
252 if (strcmp(auth_type, "KERBEROS_V4") == 0)
253 if ((length = dlevel == PROT_P ?
254 krb_mk_priv(buf, (unsigned char *) outbuf, nbyte, schedule,
255 SESSION, &myaddr, &hisaddr)
256 : krb_mk_safe(buf, (unsigned char *) outbuf, nbyte, SESSION,
257 &myaddr, &hisaddr)) == -1) {
258 secure_error("krb_mk_%s failed for KERBEROS_V4",
259 dlevel == PROT_P ? "priv" : "safe");
262 #endif /* KRB5_KRB4_COMPAT */
264 if (strcmp(auth_type, "GSSAPI") == 0) {
265 gss_buffer_desc in_buf, out_buf;
266 OM_uint32 maj_stat, min_stat;
270 in_buf.length = nbyte;
271 maj_stat = gss_seal(&min_stat, gcontext,
272 (dlevel == PROT_P), /* confidential */
274 &in_buf, &conf_state,
276 if (maj_stat != GSS_S_COMPLETE) {
277 /* generally need to deal */
278 /* ie. should loop, but for now just fail */
279 secure_gss_error(maj_stat, min_stat,
281 "GSSAPI seal failed":
282 "GSSAPI sign failed");
286 if (bufsize < out_buf.length) {
288 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
289 (outbuf = malloc((unsigned) out_buf.length))) {
290 bufsize = out_buf.length;
293 secure_error("%s (in malloc of PROT buffer)",
299 memcpy(outbuf, out_buf.value, length=out_buf.length);
300 gss_release_buffer(&min_stat, &out_buf);
303 net_len = htonl((u_long) length);
304 if (looping_write(fd, &net_len, 4) == -1) return(-1);
305 if (looping_write(fd, outbuf, length) != length) return(-1);
313 /* number of chars in ucbuf, pointer into ucbuf */
314 static unsigned int nin, bufp;
319 if ((kerror = looping_read(fd, &length, sizeof(length)))
321 secure_error("Couldn't read PROT buffer length: %d/%s",
323 kerror == -1 ? sys_errlist[errno]
327 if ((length = (u_long) ntohl(length)) > MAX) {
328 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
332 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
333 secure_error("Couldn't read %u byte PROT buffer: %s",
334 length, kerror == -1 ?
335 sys_errlist[errno] : "premature EOF");
338 /* Other auth types go here ... */
339 #ifdef KRB5_KRB4_COMPAT
340 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
341 if (kerror = dlevel == PROT_P ?
342 krb_rd_priv(ucbuf, length, schedule, SESSION,
343 &hisaddr, &myaddr, &msg_data)
344 : krb_rd_safe(ucbuf, length, SESSION,
345 &hisaddr, &myaddr, &msg_data)) {
346 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
347 dlevel == PROT_P ? "priv" : "safe",
348 krb_get_err_text(kerror));
351 memcpy(ucbuf, msg_data.app_data, msg_data.app_length);
352 nin = bufp = msg_data.app_length;
354 #endif /* KRB5_KRB4_COMPAT */
356 if (strcmp(auth_type, "GSSAPI") == 0) {
357 gss_buffer_desc xmit_buf, msg_buf;
358 OM_uint32 maj_stat, min_stat;
361 xmit_buf.value = ucbuf;
362 xmit_buf.length = length;
363 conf_state = (dlevel == PROT_P);
364 /* decrypt/verify the message */
365 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
366 &msg_buf, &conf_state, NULL);
367 if (maj_stat != GSS_S_COMPLETE) {
368 secure_gss_error(maj_stat, min_stat,
370 "failed unsealing ENC message":
371 "failed unsealing MIC message");
375 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
376 gss_release_buffer(&min_stat, &msg_buf);
379 /* Other auth types go here ... */
383 else return(ucbuf[bufp - nin--]);
389 * -2 on security error
394 if (dlevel == PROT_C)
395 return(getc(stream));
396 return(secure_getbyte(fileno(stream)));
400 * n>0 on success (n == # of bytes read)
402 * -1 on error (errno set), only for PROT_C
403 * -2 on security error
405 secure_read(fd, buf, nbyte)
413 if (dlevel == PROT_C)
414 return(read(fd,buf,nbyte));
417 for (i=0; nbyte>0; nbyte--)
418 switch (c = secure_getbyte(fd)) {
420 case EOF: if (!i) c = 0;
422 default: buf[i++] = c;