| /* |
| * decode_tds.c |
| * |
| * Tabular Data Stream (Sybase, Microsoft SQL). See www.freetds.org. |
| * |
| * Thanks to antilove!@#$% and Ben Lowery <blowery@monkey.org> for |
| * providing me with packet traces. |
| * |
| * Copyright (c) 2000 Dug Song <dugsong@monkey.org> |
| * Copyright (c) 2001 Paul van Maaren <P.v.Maaren@reseau.nl> |
| * |
| * $Id: decode_tds.c,v 1.10 2001/03/15 08:33:02 dugsong Exp $ |
| */ |
| |
| #include "config.h" |
| |
| #include <sys/types.h> |
| #include <netinet/in.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "decode.h" |
| |
| struct tds_hdr { |
| u_char type; |
| u_char last; |
| u_short size; |
| u_int32_t zero; |
| }; |
| |
| struct tds_login { |
| char hostname[30]; |
| u_char hostlen; |
| char username[30]; |
| u_char userlen; |
| char password[30]; |
| u_char passlen; |
| char process[30]; |
| u_char proclen; |
| char magic1[6]; |
| u_char bulkcopy; |
| char magic2[9]; |
| char appname[30]; |
| u_char applen; |
| char servername[30]; |
| u_char serverlen; |
| u_char zero; |
| u_char pass2len; |
| char password2[30]; |
| char magic3[223]; |
| u_char pass2len2; |
| char version[4]; |
| char libname[10]; |
| u_char liblen; |
| char magic4[3]; |
| char language[30]; |
| u_char langlen; |
| u_char nolang; |
| u_short magic5; |
| u_char encrypted; |
| char magic6[10]; |
| char charset[30]; |
| u_char charlen; |
| u_char magic7; |
| char blocksize[6]; |
| u_char blocklen; |
| char magic8[4]; /* 4.2: 8, 4.6: 4, 5.0: 25 */ |
| }; |
| |
| u_char tds7_magic1[] = { |
| 0x6, 0x83, 0xf2, 0xf8, 0xff, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x03, 0x0, |
| 0x0, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00 |
| }; |
| |
| struct tds7_login { |
| u_short size; |
| char zero1[5]; |
| u_char byte1; /* 0x70 */ |
| char zero2[7]; |
| char magic1[21]; |
| u_short servpos; |
| u_short servlen; |
| u_short userpos; /* XXX - freetds got this wrong? */ |
| u_short userlen; |
| u_short passpos; |
| u_short passlen; |
| u_short somepos; |
| u_short somelen; |
| u_short apppos; |
| u_short applen; |
| char zero4[4]; |
| u_short libpos; |
| u_short liblen; |
| char skip1[8]; |
| char magic2[6]; |
| char skip2[8]; |
| /* char servername[servlen]; */ |
| /* char username[userlen]; */ |
| /* char password[passlen]; */ |
| /* char appname[applen]; */ |
| /* char server[servlen]; */ |
| /* char library[liblen]; */ |
| /* char magic3[48]; */ |
| }; |
| |
| static void |
| deunicode(u_char *buf, int len) |
| { |
| int i; |
| |
| for (i = 0; i < len; i++) { |
| buf[i] = buf[i * 2]; |
| } |
| buf[i] = '\0'; |
| } |
| |
| |
| static void |
| tds7_decrypt(u_char *buf, int len) |
| { |
| int i; |
| |
| for (i = 0; i < len; i++) { |
| buf[i] = ((buf[i] << 4) | (buf[i] >> 4)) ^ 0x5a; |
| } |
| buf[i] = '\0'; |
| } |
| |
| |
| int |
| decode_tds(u_char *buf, int len, u_char *out_buf, int olen) |
| { |
| char *obuf = (char *)out_buf; |
| struct tds_hdr *th; |
| struct tds_login *tl; |
| struct tds7_login *t7l;//, *myt7l; |
| u_char *user, *pass, *serv; |
| u_short userlen, passlen, servlen; |
| obuf[0] = '\0'; |
| |
| for (th = (struct tds_hdr *)buf; |
| len > sizeof(*th) && len >= ntohs(th->size); |
| buf += ntohs(th->size), len -= ntohs(th->size)) { |
| if (th->type == 2) { |
| /* Version 4.x, 5.0 */ |
| if (len < sizeof(*th) + sizeof(*tl)) |
| return (0); |
| tl = (struct tds_login *)(th + 1); |
| if (tl->userlen > sizeof(tl->username)) |
| return (0); |
| tl->username[tl->userlen] = '\0'; |
| strlcat(obuf, tl->username, olen); |
| strlcat(obuf, "\n", olen); |
| if (tl->passlen > sizeof(tl->password)) |
| return (0); |
| tl->password[tl->passlen] = '\0'; |
| strlcat(obuf, tl->password, olen); |
| strlcat(obuf, "\n", olen); |
| } |
| else if (th->type == 16 && th->last == 1) { |
| /* Version 7.0 */ |
| if (len < sizeof(*th) + sizeof(*t7l)) |
| return (0); |
| t7l = (struct tds7_login *)(th + 1); |
| //myt7l = (struct tds7_login *)(buf + sizeof(*th)); |
| |
| userlen = pletohs(&t7l->userlen); |
| passlen = pletohs(&t7l->passlen); |
| servlen = pletohs(&t7l->servlen); |
| |
| if (len < sizeof(*th) + sizeof(*t7l) + |
| (2 * (userlen + passlen))) { |
| return (0); |
| } |
| |
| serv = (u_char *)(t7l + 1); |
| deunicode(serv, servlen); |
| |
| user = serv + (2 * servlen); |
| pass = user + (2 * userlen); |
| deunicode(user, userlen); |
| /* XXX - when to call? */ |
| tds7_decrypt(pass, 2 * passlen); |
| |
| deunicode(pass, passlen); |
| snprintf(obuf + strlen(obuf), |
| olen - strlen(obuf), |
| "%s\n%s\n", user, pass); |
| return(strlen(obuf)); |
| } |
| } |
| return (strlen(obuf)); |
| } |