1 /*
2 * decode_tds.c
3 *
4 * Tabular Data Stream (Sybase, Microsoft SQL). See www.freetds.org.
5 *
6 * Thanks to antilove!@#$% and Ben Lowery <blowery@monkey.org> for
7 * providing me with packet traces.
8 *
9 * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
10 * Copyright (c) 2001 Paul van Maaren <P.v.Maaren@reseau.nl>
11 *
12 * $Id: decode_tds.c,v 1.10 2001/03/15 08:33:02 dugsong Exp $
13 */
14
15 #include "config.h"
16
17 #include <sys/types.h>
18 #include <netinet/in.h>
19
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "decode.h"
24
25 struct tds_hdr {
26 u_char type;
27 u_char last;
28 u_short size;
29 u_int32_t zero;
30 };
31
32 struct tds_login {
33 char hostname[30];
34 u_char hostlen;
35 char username[30];
36 u_char userlen;
37 char password[30];
38 u_char passlen;
39 char process[30];
40 u_char proclen;
41 char magic1[6];
42 u_char bulkcopy;
43 char magic2[9];
44 char appname[30];
45 u_char applen;
46 char servername[30];
47 u_char serverlen;
48 u_char zero;
49 u_char pass2len;
50 char password2[30];
51 char magic3[223];
52 u_char pass2len2;
53 char version[4];
54 char libname[10];
55 u_char liblen;
56 char magic4[3];
57 char language[30];
58 u_char langlen;
59 u_char nolang;
60 u_short magic5;
61 u_char encrypted;
62 char magic6[10];
63 char charset[30];
64 u_char charlen;
65 u_char magic7;
66 char blocksize[6];
67 u_char blocklen;
68 char magic8[4]; /* 4.2: 8, 4.6: 4, 5.0: 25 */
69 };
70
71 u_char tds7_magic1[] = {
72 0x6, 0x83, 0xf2, 0xf8, 0xff, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x03, 0x0,
73 0x0, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00
74 };
75
76 struct tds7_login {
77 u_short size;
78 char zero1[5];
79 u_char byte1; /* 0x70 */
80 char zero2[7];
81 char magic1[21];
82 u_short servpos;
83 u_short servlen;
84 u_short userpos; /* XXX - freetds got this wrong? */
85 u_short userlen;
86 u_short passpos;
87 u_short passlen;
88 u_short somepos;
89 u_short somelen;
90 u_short apppos;
91 u_short applen;
92 char zero4[4];
93 u_short libpos;
94 u_short liblen;
95 char skip1[8];
96 char magic2[6];
97 char skip2[8];
98 /* char servername[servlen]; */
99 /* char username[userlen]; */
100 /* char password[passlen]; */
101 /* char appname[applen]; */
102 /* char server[servlen]; */
103 /* char library[liblen]; */
104 /* char magic3[48]; */
105 };
106
107 static void
deunicode(u_char * buf,int len)108 deunicode(u_char *buf, int len)
109 {
110 int i;
111
112 for (i = 0; i < len; i++) {
113 buf[i] = buf[i * 2];
114 }
115 buf[i] = '\0';
116 }
117
118
119 static void
tds7_decrypt(u_char * buf,int len)120 tds7_decrypt(u_char *buf, int len)
121 {
122 int i;
123
124 for (i = 0; i < len; i++) {
125 buf[i] = ((buf[i] << 4) | (buf[i] >> 4)) ^ 0x5a;
126 }
127 buf[i] = '\0';
128 }
129
130
131 int
decode_tds(u_char * buf,int len,u_char * obuf,int olen)132 decode_tds(u_char *buf, int len, u_char *obuf, int olen)
133 {
134 struct tds_hdr *th;
135 struct tds_login *tl;
136 struct tds7_login *t7l, *myt7l;
137 u_char *user, *pass, *serv;
138 u_short userlen, passlen, servlen;
139
140 obuf[0] = '\0';
141
142 for (th = (struct tds_hdr *)buf;
143 len > sizeof(*th) && len >= ntohs(th->size);
144 buf += ntohs(th->size), len -= ntohs(th->size)) {
145
146 if (th->type == 2) {
147 /* Version 4.x, 5.0 */
148 if (len < sizeof(*th) + sizeof(*tl))
149 return (0);
150
151 tl = (struct tds_login *)(th + 1);
152
153 if (tl->userlen > sizeof(tl->username))
154 return (0);
155
156 tl->username[tl->userlen] = '\0';
157 strlcat(obuf, tl->username, olen);
158 strlcat(obuf, "\n", olen);
159
160 if (tl->passlen > sizeof(tl->password))
161 return (0);
162
163 tl->password[tl->passlen] = '\0';
164 strlcat(obuf, tl->password, olen);
165 strlcat(obuf, "\n", olen);
166 }
167 else if (th->type == 16 && th->last == 1) {
168 /* Version 7.0 */
169 if (len < sizeof(*th) + sizeof(*t7l))
170 return (0);
171
172 t7l = (struct tds7_login *)(th + 1);
173
174 myt7l = (struct tds7_login *)(buf + sizeof(*th));
175
176 userlen = pletohs(&t7l->userlen);
177 passlen = pletohs(&t7l->passlen);
178 servlen = pletohs(&t7l->servlen);
179
180 if (len < sizeof(*th) + sizeof(*t7l) +
181 (2 * (userlen + passlen))) {
182 return (0);
183 }
184
185 serv = (u_char *)(t7l + 1);
186 deunicode(serv, servlen);
187
188 user = serv + (2 * servlen);
189 pass = user + (2 * userlen);
190
191 deunicode(user, userlen);
192
193 /* XXX - when to call? */
194 tds7_decrypt(pass, 2 * passlen);
195
196 deunicode(pass, passlen);
197
198 snprintf(obuf + strlen(obuf),
199 olen - strlen(obuf),
200 "%s\n%s\n", user, pass);
201 return(strlen(obuf));
202 }
203 }
204 return (strlen(obuf));
205 }
206
207
208