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