File: decode_tds.c

package info (click to toggle)
dsniff 2.4b1+debian-29
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 2,020 kB
  • sloc: ansic: 10,803; sh: 152; makefile: 126
file content (213 lines) | stat: -rw-r--r-- 4,222 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * 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 <stdio.h>
#include <string.h>
#include <strlcat.h>
#include <arpa/inet.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 *obuf, int olen)
{
	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->size != 8) {
			/* wrong header length */
			break;
		}

		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));
}