LCOV - code coverage report
Current view: top level - src/server - login.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 72 165 43.6 %
Date: 2025-12-14 09:18:45 Functions: 3 6 50.0 %

          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             : }

Generated by: LCOV version 1.13