From 747be76abf12365c82104a9327761473a5429389 Mon Sep 17 00:00:00 2001 From: Assar Westerlund Date: Sun, 5 Sep 1999 17:14:06 +0000 Subject: [PATCH] (send_and_recv): handle EINTR properly. return on EOF. always free data. check return value from realloc. (send_and_recv_tcp, send_and_recv_http): check advertised length against actual length git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@6896 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/krb5/send_to_kdc.c | 118 ++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 30 deletions(-) diff --git a/lib/krb5/send_to_kdc.c b/lib/krb5/send_to_kdc.c index c9741fe5c..6de858502 100644 --- a/lib/krb5/send_to_kdc.c +++ b/lib/krb5/send_to_kdc.c @@ -40,6 +40,12 @@ RCSID("$Id$"); +/* + * send the data in `req' on the socket `fd' (which is datagram iff udp) + * waiting `tmout' for a reply and returning the reply in `rep'. + * returns 0 and data in `rep' if succesful, otherwise -1 + */ + static int send_and_recv (int fd, time_t tmout, @@ -54,27 +60,38 @@ send_and_recv (int fd, if (send (fd, req->data, req->length, 0) < 0) return -1; - rep->data = NULL; - rep->length = 0; + krb5_data_zero(rep); do{ FD_ZERO(&fdset); FD_SET(fd, &fdset); timeout.tv_sec = tmout; timeout.tv_usec = 0; ret = select (fd + 1, &fdset, NULL, NULL, &timeout); - if (ret <= 0) + if (ret < 0) { + if (errno == EINTR) + continue; return -1; - else { + } else if (ret == 0) { + return 0; + } else { + void *tmp; - if (ioctl (fd, FIONREAD, &nbytes) < 0) + if (ioctl (fd, FIONREAD, &nbytes) < 0) { + krb5_data_free (rep); return -1; + } if(nbytes == 0) return 0; - rep->data = realloc(rep->data, rep->length + nbytes); - ret = recv (fd, (char*)rep->data + rep->length, nbytes, 0); + tmp = realloc (rep->data, rep->length + nbytes); + if (tmp == NULL) { + krb5_data_free (rep); + return -1; + } + rep->data = tmp; + ret = recv (fd, (char*)tmp + rep->length, nbytes, 0); if (ret < 0) { - free (rep->data); + krb5_data_free (rep); return -1; } rep->length += ret; @@ -83,72 +100,113 @@ send_and_recv (int fd, return 0; } +/* + * Send kerberos requests and receive a reply on a udp or any other kind + * of a datagram socket. See `send_and_recv'. + */ + static int send_and_recv_udp(int fd, time_t tmout, - const krb5_data *send, - krb5_data *recv) + const krb5_data *req, + krb5_data *rep) { - return send_and_recv(fd, tmout, 1, send, recv); + return send_and_recv(fd, tmout, 1, req, rep); } +/* + * `send_and_recv' for a TCP (or any other stream) socket. + * Since there are no record limits on a stream socket the protocol here + * is to prepend the request with 4 bytes of its length and the reply + * is similarly encoded. + */ + static int send_and_recv_tcp(int fd, time_t tmout, - const krb5_data *Send, - krb5_data *recv) + const krb5_data *req, + krb5_data *rep) { unsigned char len[4]; - _krb5_put_int(len, Send->length, 4); - send(fd, len, sizeof(len), 0); - if(send_and_recv(fd, tmout, 0, Send, recv)) + unsigned long rep_len; + + _krb5_put_int(len, req->length, 4); + if(send(fd, len, sizeof(len), 0) < 0) return -1; - if(recv->length < 4) + if(send_and_recv(fd, tmout, 0, req, rep)) return -1; - memmove(recv->data, (char*)recv->data + 4, recv->length - 4); - recv->length -= 4; + if(rep->length < 4) { + krb5_data_free (rep); + return -1; + } + _krb5_get_int(rep->data, &rep_len, 4); + memmove(rep->data, (char*)rep->data + 4, rep->length - 4); + rep->length -= 4; + if (rep_len != rep->length) { + krb5_data_free (rep); + return -1; + } return 0; } +/* + * `send_and_recv' tailored for the HTTP protocol. + */ + static int send_and_recv_http(int fd, time_t tmout, const char *prefix, - const krb5_data *send, - krb5_data *recv) + const krb5_data *req, + krb5_data *rep) { char *request; char *str; krb5_data r; int ret; - int len = base64_encode(send->data, send->length, &str); + int len = base64_encode(req->data, req->length, &str); + if(len < 0) return -1; asprintf(&request, "GET %s%s HTTP/1.0\r\n\r\n", prefix, str); free(str); - r.data = request; + if (request == NULL) + return -1; + r.data = request; r.length = strlen(request); - ret = send_and_recv(fd, tmout, 0, &r, recv); + ret = send_and_recv(fd, tmout, 0, &r, rep); free(request); if(ret) return ret; { + unsigned long rep_len; char *s, *p; - s = realloc(recv->data, recv->length + 1); - s[recv->length] = 0; + + s = realloc(rep->data, rep->length + 1); + if (s == NULL) { + krb5_data_free (rep); + return -1; + } + s[rep->length] = 0; p = strstr(s, "\r\n\r\n"); if(p == NULL) { free(s); return -1; } p += 4; - recv->data = s; - recv->length -= p - s; - if(recv->length < 4) { /* remove length */ + rep->data = s; + rep->length -= p - s; + if(rep->length < 4) { /* remove length */ free(s); return -1; } - memmove(recv->data, p + 4, recv->length - 4); + rep->length -= 4; + _krb5_get_int(p, &rep_len, 4); + if (rep_len != rep->length) { + free(s); + return -1; + } + memmove(rep->data, p + 4, rep->length); } return 0; }