diff options
Diffstat (limited to 'ktalkd/ktalkd/repairs.c')
-rw-r--r-- | ktalkd/ktalkd/repairs.c | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/ktalkd/ktalkd/repairs.c b/ktalkd/ktalkd/repairs.c new file mode 100644 index 00000000..9473a473 --- /dev/null +++ b/ktalkd/ktalkd/repairs.c @@ -0,0 +1,274 @@ +/* + * Copyright 1998 David A. Holland. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder(s) nor the names of their + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +char repairs_rcsid[] = + "$Id$"; + +/* + * Most, but not quite all, of the voodoo for detecting and handling + * malformed packets goes here. + * + * Basically anything which we can detect by examining the packet we + * try to do in rationalize_packet(). We return a quirk code for what + * we did so we can send back replies that will make sense to the other + * end. That's irrationalize_reply(). + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <string.h> +#include <syslog.h> +#include "prot_talkd.h" +#include "proto.h" + +uint32_t +byte_swap32(uint32_t k) +{ + return (k<<24) | ((k&0xff00) << 8) | ((k>>8) & 0xff00) | (k>>24); +} + +static uint16_t +byte_swap16(uint16_t k) +{ + return (k<<8) | (k>>8); +} + +/***************************************************/ + +/* + * probe for strings that are meaningful in talkd packets. + * rejects all control characters and delete. newlines and tabs have + * no business in tty names or usernames. + */ +static int probe_string(const char *buf, size_t len) { + size_t i; + int ch; + for (i=0; i<len; i++) { + if (buf[i]==0) return 0; /* success */ + ch = (unsigned char) buf[i]; + if ((ch&127) < 32 || (ch&127)==127) return -1; + } + return -1; /* no null-terminator, assume it's not a string */ +} + +/* + * Check if an address from a talk packet matches the actual sender + * address. If it doesn't, it's a good bet it's not the right packet format. + * Allow assorted endianness though. + * In an ideal world we'd save the endianness info for use elsewhere instead + * of reprobing it, but oh well. + */ +static int probe_addr(struct talk_addr *ta, struct sockaddr_in *sn) { + uint16_t family = sn->sin_family; + uint16_t xfamily = byte_swap16(family); + uint16_t port = sn->sin_port; + uint16_t xport = byte_swap16(port); + uint32_t addr = sn->sin_addr.s_addr; + uint32_t xaddr = byte_swap32(addr); + + if (ta->ta_family != family && ta->ta_family != xfamily) return -1; + if (ta->ta_port != port && ta->ta_port != xport) return -1; + if (ta->ta_addr != addr && ta->ta_addr != xaddr) return -1; + return 0; +} + +/***************************************************/ + +/* + * warning warning: in some cases this packet may need compiler + * pragmas to force the compiler to not pad it. shouldn't with + * gcc though. + */ + +#define OTALK_PACKET_SIZE 76 + +#define OLD_NAME_SIZE 9 +struct otalk_packet { + char type; + char l_name[OLD_NAME_SIZE]; + char r_name[OLD_NAME_SIZE]; + char filler; + uint32_t id_num; + uint32_t pid; + char r_tty[TTY_SIZE]; + struct talk_addr addr; + struct talk_addr ctl_addr; +}; + +struct otalk_reply { + char type; + char answer; + uint16_t filler; + uint32_t id_num; + struct talk_addr addr; +}; + +/* additional types */ +#define OLD_DELETE_INVITE 4 +#define OLD_AUTO_LOOK_UP 5 +#define OLD_AUTO_DELETE 6 + +static int probe_otalk_packet(char *buf, size_t len, size_t maxlen, + struct sockaddr_in *sn) +{ + struct otalk_packet otp; + CTL_MSG m; + + ktalk_debug("Probing for QUIRK_OTALK\n"); + + if (sizeof(otp)!=OTALK_PACKET_SIZE) { + syslog(LOG_ERR, "QUIRK_OTALK: struct otalk_packet padding " + "is wrong\n"); + return -1; + } + + if (len!=sizeof(otp)) { + ktalk_debug("QUIRK_OTALK: wrong size\n"); + return -1; + } + + memcpy(&otp, buf, len); + if (probe_string(otp.l_name, sizeof(otp.l_name))) { + ktalk_debug("QUIRK_OTALK: l_name not a string\n"); + return -1; + } + if (probe_string(otp.r_name, sizeof(otp.r_name))) { + ktalk_debug("QUIRK_OTALK: r_name not a string\n"); + return -1; + } + if (probe_string(otp.r_tty, sizeof(otp.r_tty))) { + ktalk_debug("QUIRK_OTALK: r_tty not a string\n"); + return -1; + } + if (probe_addr(&otp.ctl_addr, sn)) { + ktalk_debug("QUIRK_OTALK: addresses do not match\n"); + return -1; + } + + switch (otp.type) { + case LEAVE_INVITE: + case LOOK_UP: + case DELETE: + case ANNOUNCE: + break; + /* I'm not sure these will work. */ + case OLD_DELETE_INVITE: otp.type = DELETE; break; + case OLD_AUTO_LOOK_UP: otp.type = LOOK_UP; break; + case OLD_AUTO_DELETE: otp.type = DELETE; break; + default: + ktalk_debug("QUIRK_OTALK: invalid type field\n"); + return -1; + } + + if (OLD_NAME_SIZE >= NAME_SIZE) { + syslog(LOG_ERR, "QUIRK_OTALK: OLD_NAME_SIZE >= NAME_SIZE\n"); + syslog(LOG_ERR, "QUIRK_OTALK: fix repairs.c and recompile\n"); + return -1; + } + if (maxlen < sizeof(CTL_MSG)) { + syslog(LOG_ERR, "QUIRK_OTALK: maxlen too small; enlarge " + "inbuf[] in talkd.c and recompile\n"); + return -1; + } + + m.vers = TALK_VERSION; + m.type = otp.type; + m.answer = 0; + m.pad = 0; + m.id_num = otp.id_num; + m.addr = otp.addr; + m.ctl_addr = otp.ctl_addr; + m.pid = otp.pid; + memcpy(m.l_name, otp.l_name, OLD_NAME_SIZE); + m.l_name[OLD_NAME_SIZE] = 0; + memcpy(m.r_name, otp.r_name, OLD_NAME_SIZE); + m.r_name[OLD_NAME_SIZE] = 0; + memcpy(m.r_tty, otp.r_tty, TTY_SIZE); + m.r_tty[TTY_SIZE-1] = 0; + memcpy(buf, &m, sizeof(m)); + return 0; +} + +static size_t do_otalk_reply(char *buf, size_t maxlen) { + struct otalk_reply or; + CTL_RESPONSE *r = (CTL_RESPONSE *)buf; + if (sizeof(or) > maxlen) { + syslog(LOG_ERR, "QUIRK_OTALK: reply: maxlen too small; " + "enlarge buf[] in send_packet and recompile\n"); + return sizeof(CTL_RESPONSE); + } + + /* + * If we changed the type above, this might break. Should we encode + * it in the quirk code? + */ + or.type = r->type; + or.answer = r->answer; + or.filler = 0; + or.id_num = r->id_num; + or.addr = r->addr; + memcpy(buf, &or, sizeof(or)); + return sizeof(or); +} + +/***************************************************/ + + +/* + * Return 0 if the packet's normal, -1 if we can't figure it out, + * otherwise a quirk code from the quirk list. + * + * For now, we don't support any quirks. Need more data. + */ +int +rationalize_packet(char *buf, size_t len, size_t mlen, struct sockaddr_in *sn) +{ + if (len == sizeof(CTL_MSG)) { + return 0; + } + + ktalk_debug("Malformed packet (length %u)\n", len); + + if (probe_otalk_packet(buf, len, mlen, sn)==0) { + ktalk_debug("Using QUIRK_OTALK\n"); + return QUIRK_OTALK; + } + return -1; +} + +size_t +irrationalize_reply(char *buf, size_t maxlen, int quirk) +{ + switch (quirk) { + case QUIRK_NONE: return sizeof(CTL_RESPONSE); + case QUIRK_OTALK: return do_otalk_reply(buf, maxlen); + } + /* ? */ + return 0; +} |