Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdarg.h>
23 : #include <stdio.h>
24 : #include <assert.h>
25 :
26 : #if HAVE_STDLIB_H
27 : #include <stdlib.h>
28 : #endif /* HAVE_STDLIB_H */
29 :
30 : #if HAVE_STRING_H
31 : #include <string.h>
32 : #endif /* HAVE_STRING_H */
33 :
34 : #if HAVE_UNISTD_H
35 : #include <unistd.h>
36 : #endif /* HAVE_UNISTD_H */
37 :
38 : #if HAVE_SYS_TYPES_H
39 : #include <sys/types.h>
40 : #endif /* HAVE_SYS_TYPES_H */
41 :
42 : #if HAVE_SYS_SOCKET_H
43 : #include <sys/socket.h>
44 : #endif /* HAVE_SYS_SOCKET_H */
45 :
46 : #if HAVE_NETINET_IN_H
47 : #include <netinet/in.h>
48 : #endif /* HAVE_NETINET_IN_H */
49 :
50 : #if HAVE_ARPA_INET_H
51 : #include <arpa/inet.h>
52 : #endif /* HAVE_ARPA_INET_H */
53 :
54 : #include <freetds/tds.h>
55 : #include <freetds/iconv.h>
56 : #include <freetds/server.h>
57 : #include <freetds/utils.h>
58 :
59 : unsigned char *
60 742 : tds7_decrypt_pass(const unsigned char *crypt_pass, int len, unsigned char *clear_pass)
61 : {
62 : int i;
63 742 : const unsigned char xormask = 0x5A;
64 : unsigned char hi_nibble, lo_nibble;
65 :
66 16850 : for (i = 0; i < len; i++) {
67 16108 : lo_nibble = (crypt_pass[i] << 4) ^ (xormask & 0xF0);
68 16108 : hi_nibble = (crypt_pass[i] >> 4) ^ (xormask & 0x0F);
69 16108 : clear_pass[i] = hi_nibble | lo_nibble;
70 : }
71 742 : return clear_pass;
72 : }
73 :
74 : TDSSOCKET *
75 0 : tds_listen(TDSCONTEXT * ctx, int ip_port)
76 : {
77 : TDSSOCKET *tds;
78 : TDS_SYS_SOCKET fd, s;
79 : socklen_t len;
80 0 : int optval = 1;
81 : #ifdef AF_INET6
82 : struct sockaddr_in6 sin;
83 :
84 0 : memset(&sin, 0, sizeof(sin));
85 0 : sin.sin6_port = htons((short) ip_port);
86 0 : sin.sin6_family = AF_INET6;
87 :
88 0 : s = socket(AF_INET6, SOCK_STREAM, 0);
89 : #else
90 : struct sockaddr_in sin;
91 :
92 : sin.sin_addr.s_addr = INADDR_ANY;
93 : sin.sin_port = htons((short) ip_port);
94 : sin.sin_family = AF_INET;
95 :
96 : s = socket(AF_INET, SOCK_STREAM, 0);
97 : #endif
98 :
99 0 : if (TDS_IS_SOCKET_INVALID(s)) {
100 0 : perror("socket");
101 0 : return NULL;
102 : }
103 0 : setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &optval, sizeof(optval));
104 0 : if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
105 0 : perror("bind");
106 0 : CLOSESOCKET(s);
107 0 : return NULL;
108 : }
109 0 : listen(s, 5);
110 0 : len = sizeof(sin);
111 0 : fd = tds_accept(s, (struct sockaddr *) &sin, &len);
112 0 : if (TDS_IS_SOCKET_INVALID(fd)) {
113 0 : perror("accept");
114 0 : CLOSESOCKET(s);
115 0 : return NULL;
116 : }
117 0 : tds_socket_set_nodelay(fd);
118 0 : CLOSESOCKET(s);
119 0 : tds = tds_alloc_socket(ctx, 4096);
120 0 : if (!tds) {
121 0 : CLOSESOCKET(fd);
122 0 : fprintf(stderr, "out of memory");
123 0 : return NULL;
124 : }
125 0 : tds_set_s(tds, fd);
126 0 : tds->out_flag = TDS_LOGIN;
127 : /* TODO proper charset */
128 0 : tds_iconv_open(tds->conn, "ISO8859-1", 0);
129 : /* get_incoming(tds->s); */
130 0 : tds->state = TDS_IDLE;
131 0 : return tds;
132 : }
133 :
134 : static int tds_read_string(TDSSOCKET * tds, DSTR * s, int size);
135 :
136 : int
137 0 : tds_read_login(TDSSOCKET * tds, TDSLOGIN * login)
138 : {
139 0 : DSTR blockstr = DSTR_INITIALIZER;
140 : TDS_USMALLINT major;
141 0 : int res = 1;
142 :
143 : /*
144 : while (len = tds_read_packet(tds)) {
145 : for (i=0;i<len;i++)
146 : printf("%d %d %c\n",i, tds->in_buf[i], (tds->in_buf[i]>=' ' && tds->in_buf[i]<='z') ? tds->in_buf[i] : ' ');
147 : }
148 : */
149 0 : res = res && tds_read_string(tds, &login->client_host_name, 30);
150 0 : res = res && tds_read_string(tds, &login->user_name, 30);
151 0 : res = res && tds_read_string(tds, &login->password, 30);
152 0 : tds_get_n(tds, NULL, 31); /* host process, junk for now */
153 0 : tds_get_n(tds, NULL, 16); /* magic */
154 0 : res = res && tds_read_string(tds, &login->app_name, 30);
155 0 : res = res && tds_read_string(tds, &login->server_name, 30);
156 0 : tds_get_n(tds, NULL, 256); /* secondary passwd...encryption? */
157 0 : major = tds_get_byte(tds);
158 0 : login->tds_version = (major << 8) | tds_get_byte(tds);
159 0 : tds_get_smallint(tds); /* unused part of protocol field */
160 0 : res = res && tds_read_string(tds, &login->library, 10);
161 0 : tds_get_byte(tds); /* program version, junk it */
162 0 : tds_get_byte(tds);
163 0 : tds_get_smallint(tds);
164 0 : tds_get_n(tds, NULL, 3); /* magic */
165 0 : res = res && tds_read_string(tds, &login->language, 30);
166 0 : tds_get_n(tds, NULL, 14); /* magic */
167 0 : res = res && tds_read_string(tds, &login->server_charset, 30);
168 0 : tds_get_n(tds, NULL, 1); /* magic */
169 0 : res = res && tds_read_string(tds, &blockstr, 6);
170 0 : printf("block size %s\n", tds_dstr_cstr(&blockstr));
171 0 : login->block_size = atoi(tds_dstr_cstr(&blockstr));
172 0 : tds_dstr_free(&blockstr);
173 0 : tds_get_n(tds, NULL, tds->in_len - tds->in_pos); /* read junk at end */
174 :
175 0 : return res;
176 : }
177 :
178 : int
179 742 : tds7_read_login(TDSSOCKET * tds, TDSLOGIN * login)
180 : {
181 : int a;
182 : unsigned host_name_len, user_name_len, app_name_len, server_name_len;
183 : unsigned library_name_len, language_name_len;
184 : unsigned auth_len, database_name_len, ext_len;
185 : size_t unicode_len, password_len;
186 : char *unicode_string, *psrc;
187 : char *pbuf;
188 742 : int res = 1;
189 : unsigned packet_start, len, start;
190 : TDS_UINT packet_len;
191 :
192 742 : packet_len = tds_get_uint(tds); /*total packet size */
193 742 : a = tds_get_int(tds); /*TDS version */
194 742 : if ((a & 0xff) == 7)
195 0 : tds_set_version(login, a & 0xff, (a >> 8) & 0xff);
196 : else
197 742 : tds_set_version(login, (a >> 28) & 0xf, (a >> 24) & 0xf);
198 742 : tds_get_int(tds); /*desired packet size being requested by client */
199 : /* client prog ver (4 byte) + pid (int) + connection id (4 byte) + flag1 (byte) */
200 742 : tds_get_n(tds, NULL, 13);
201 742 : login->option_flag2 = tds_get_byte(tds);
202 : /* sql type (byte) + flag3 (byte) + timezone (int) + collation (4 byte) */
203 742 : tds_get_n(tds, NULL, 10);
204 :
205 742 : packet_start = IS_TDS72_PLUS(login) ? 86 + 8 : 86; /* ? */
206 742 : if (packet_len < packet_start)
207 : return 0;
208 :
209 : #define READ_BUF(len, base_len) do { \
210 : start = tds_get_usmallint(tds); \
211 : len = tds_get_usmallint(tds); \
212 : if (len != 0 && (start < packet_start || start + base_len * len > packet_len)) \
213 : return 0; \
214 : } while(0)
215 :
216 : /* hostname */
217 742 : READ_BUF(host_name_len, 2);
218 :
219 : /* username */
220 742 : READ_BUF(user_name_len, 2);
221 :
222 : /* password */
223 742 : READ_BUF(password_len, 2);
224 :
225 : /* app name */
226 742 : READ_BUF(app_name_len, 2);
227 :
228 : /* server */
229 742 : READ_BUF(server_name_len, 2);
230 :
231 : /* unknown */
232 742 : READ_BUF(ext_len, 1);
233 :
234 : /* library */
235 742 : READ_BUF(library_name_len, 2);
236 :
237 : /* language */
238 742 : READ_BUF(language_name_len, 2);
239 :
240 : /* database */
241 742 : READ_BUF(database_name_len, 2);
242 :
243 : /* client mac address */
244 742 : tds_get_n(tds, NULL, 6);
245 :
246 : /* authentication */
247 742 : READ_BUF(auth_len, 1);
248 :
249 : /* db file */
250 742 : READ_BUF(len, 2);
251 :
252 742 : if (IS_TDS72_PLUS(login)) {
253 : /* new password */
254 20 : READ_BUF(len, 2);
255 : /* SSPI */
256 20 : tds_get_int(tds);
257 : }
258 :
259 742 : res = res && tds_dstr_get(tds, &login->client_host_name, host_name_len);
260 742 : res = res && tds_dstr_get(tds, &login->user_name, user_name_len);
261 :
262 742 : unicode_len = password_len * 2;
263 742 : unicode_string = tds_new(char, unicode_len);
264 742 : if (!unicode_string || !tds_dstr_alloc(&login->password, password_len)) {
265 0 : free(unicode_string);
266 0 : return 0;
267 : }
268 742 : tds_get_n(tds, unicode_string, unicode_len);
269 742 : tds7_decrypt_pass((unsigned char *) unicode_string, unicode_len, (unsigned char *) unicode_string);
270 1484 : pbuf = tds_dstr_buf(&login->password);
271 :
272 742 : memset(&tds->conn->char_convs[client2ucs2]->suppress, 0, sizeof(tds->conn->char_convs[client2ucs2]->suppress));
273 742 : psrc = unicode_string;
274 742 : a = tds_iconv(tds, tds->conn->char_convs[client2ucs2], to_client, (const char **) &psrc, &unicode_len, &pbuf,
275 : &password_len);
276 742 : if (a < 0 ) {
277 0 : fprintf(stderr, "error: %s:%d: tds7_read_login: tds_iconv() failed\n", __FILE__, __LINE__);
278 0 : free(unicode_string);
279 0 : return 0;
280 : }
281 1484 : tds_dstr_setlen(&login->password, pbuf - tds_dstr_buf(&login->password));
282 742 : free(unicode_string);
283 :
284 742 : res = res && tds_dstr_get(tds, &login->app_name, app_name_len);
285 742 : res = res && tds_dstr_get(tds, &login->server_name, server_name_len);
286 742 : tds_get_n(tds, NULL, ext_len);
287 742 : res = res && tds_dstr_get(tds, &login->library, library_name_len);
288 742 : res = res && tds_dstr_get(tds, &login->language, language_name_len);
289 742 : res = res && tds_dstr_get(tds, &login->database, database_name_len);
290 :
291 742 : tds_get_n(tds, NULL, auth_len);
292 :
293 742 : tds_dstr_empty(&login->server_charset); /*empty char_set for TDS 7.0 */
294 742 : login->block_size = 0; /*0 block size for TDS 7.0 */
295 742 : login->encryption_level = TDS_ENCRYPTION_OFF;
296 :
297 742 : tds->conn->tds_version = login->tds_version;
298 :
299 742 : return res;
300 : }
301 :
302 : static int
303 0 : tds_read_string(TDSSOCKET * tds, DSTR * s, int size)
304 : {
305 : int len;
306 :
307 : /* FIXME this can fails... */
308 0 : if (!tds_dstr_alloc(s, size))
309 : return 0;
310 0 : tds_get_n(tds, tds_dstr_buf(s), size);
311 0 : len = tds_get_byte(tds);
312 0 : if (len <= size)
313 0 : tds_dstr_setlen(s, len);
314 : return 1;
315 : }
316 :
317 : /**
318 : * Allocate a TDSLOGIN structure, read a login packet into it, and return it.
319 : * This is smart enough to distinguish between TDS4/5 or TDS7. The calling
320 : * function should call tds_free_login() on the returned structure when it is
321 : * no longer needed.
322 : * \param tds The socket to read from
323 : * \return Returns NULL if no login was received. The calling function can
324 : * use IS_TDSDEAD(tds) to distinguish between an error/shutdown on the socket,
325 : * or the receipt of an unexpected packet type. In the latter case,
326 : * tds->in_flag will indicate the return type.
327 : * Microsoft products require tds_version TDS72+, and SSMS requires a
328 : * product_version. Currently the highest this method will set is TDS71,
329 : * override after if necessary.
330 : */
331 : TDSLOGIN *
332 20 : tds_alloc_read_login(TDSSOCKET * tds)
333 : {
334 : TDSLOGIN * login;
335 :
336 : /*
337 : * This should only be done on a server connection, and the server
338 : * always sends 0x04 packets.
339 : */
340 20 : tds->out_flag = TDS_REPLY;
341 :
342 : /* Pre-read the next packet so we know what kind of packet it is */
343 20 : if (tds_read_packet(tds) < 1) {
344 : return NULL;
345 : }
346 :
347 : /* Allocate the login packet */
348 20 : login = tds_alloc_login(true);
349 20 : if (!login)
350 : return NULL;
351 :
352 : /* Use the packet type to determine which login format to expect */
353 20 : switch (tds->in_flag) {
354 0 : case TDS_LOGIN: /* TDS4/5 login */
355 0 : tds->conn->tds_version = 0x402;
356 0 : if (!tds_read_login(tds, login)) {
357 0 : tds_free_login(login);
358 0 : return NULL;
359 : }
360 0 : if (login->block_size == 0) {
361 0 : login->block_size = 512;
362 : }
363 : break;
364 :
365 0 : case TDS7_LOGIN: /* TDS7+ login */
366 0 : tds->conn->tds_version = 0x700;
367 0 : if (!tds7_read_login(tds, login)) {
368 0 : tds_free_login(login);
369 0 : return NULL;
370 : }
371 : break;
372 :
373 20 : case TDS71_PRELOGIN: /* TDS7.1+ prelogin, hopefully followed by a login */
374 20 : tds->conn->tds_version = 0x701;
375 : /* ignore client and just send our reply TODO... finish */
376 20 : tds71_send_prelogin(tds);
377 20 : tds_flush_packet(tds);
378 20 : if (tds_read_packet(tds) < 0 || tds->in_flag != TDS7_LOGIN) {
379 0 : tds_free_login(login);
380 0 : return NULL;
381 : }
382 20 : if (!tds7_read_login(tds, login)) {
383 0 : tds_free_login(login);
384 0 : return NULL;
385 : }
386 : break;
387 :
388 0 : default:
389 : /* unexpected packet */
390 0 : tds_free_login(login);
391 0 : return NULL;
392 : }
393 :
394 : /* Return it */
395 : return login;
396 : }
|