Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2015 Frediano Ziglio
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 : #if HAVE_STDLIB_H
23 : #include <stdlib.h>
24 : #endif /* HAVE_STDLIB_H */
25 :
26 : #if HAVE_STDDEF_H
27 : #include <stddef.h>
28 : #endif /* HAVE_STDDEF_H */
29 :
30 : #include <ctype.h>
31 :
32 : #if HAVE_STRING_H
33 : #include <string.h>
34 : #endif /* HAVE_STRING_H */
35 :
36 : #include <freetds/time.h>
37 : #include <freetds/tds.h>
38 : #include <freetds/bytes.h>
39 : #include <freetds/utils/string.h>
40 : #include <freetds/replacements.h>
41 :
42 : #ifdef HAVE_GNUTLS
43 : # include "sec_negotiate_gnutls.h"
44 : #elif defined(HAVE_OPENSSL)
45 : # include "sec_negotiate_openssl.h"
46 : #endif
47 :
48 :
49 : /**
50 : * \ingroup libtds
51 : * \defgroup auth Authentication
52 : * Functions for handling authentication.
53 : */
54 :
55 : /**
56 : * \addtogroup auth
57 : * @{
58 : */
59 :
60 : #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
61 :
62 : typedef struct tds5_negotiate
63 : {
64 : TDSAUTHENTICATION tds_auth;
65 : } TDS5NEGOTIATE;
66 :
67 : static TDSRET
68 0 : tds5_negotiate_free(TDSCONNECTION * conn, TDSAUTHENTICATION * tds_auth)
69 : {
70 0 : TDS5NEGOTIATE *auth = (TDS5NEGOTIATE *) tds_auth;
71 :
72 0 : free(auth->tds_auth.packet);
73 0 : free(auth);
74 :
75 0 : return TDS_SUCCESS;
76 : }
77 :
78 : static void
79 0 : tds5_send_msg(TDSSOCKET *tds, uint16_t msg_type)
80 : {
81 0 : tds_put_tinyint(tds, TDS_MSG_TOKEN);
82 0 : tds_put_tinyint(tds, 3); /* length */
83 0 : tds_put_tinyint(tds, 1); /* status, 1=has params */
84 0 : tds_put_smallint(tds, msg_type);
85 0 : }
86 :
87 : static TDSRET
88 0 : tds5_negotiate_handle_next(TDSSOCKET * tds, TDSAUTHENTICATION * tds_auth, size_t len)
89 : {
90 : TDSPARAMINFO *info;
91 0 : void *rsa, *nonce = NULL;
92 0 : size_t rsa_len, nonce_len = 0;
93 : void *em;
94 : size_t em_size;
95 0 : TDSRET rc = TDS_FAIL;
96 :
97 : /* send next data for authentication */
98 :
99 0 : if (!tds->login)
100 : goto error;
101 :
102 : /* we only support RSA authentication, we should have send 2/3 parameters:
103 : * 1- integer, cipher suite. 1 for RSA
104 : * 2- binary, rsa public key in PEM format
105 : * 3- binary, nonce (optional)
106 : */
107 :
108 : /* message not supported */
109 0 : if (tds_auth->msg_type != TDS5_MSG_SEC_ENCRYPT3)
110 : goto error;
111 :
112 0 : info = tds->param_info;
113 0 : if (!info || info->num_cols < 2)
114 : goto error;
115 :
116 0 : if (info->columns[1]->column_type != SYBLONGBINARY)
117 : goto error;
118 0 : if (info->num_cols >= 3 && info->columns[2]->column_type != SYBLONGBINARY)
119 : goto error;
120 0 : rsa = ((TDSBLOB*) info->columns[1]->column_data)->textvalue;
121 0 : rsa_len = info->columns[1]->column_size;
122 0 : if (info->num_cols >= 3) {
123 0 : nonce = ((TDSBLOB*) info->columns[2]->column_data)->textvalue;
124 0 : nonce_len = info->columns[2]->column_size;
125 : }
126 :
127 0 : em = tds5_rsa_encrypt(rsa, rsa_len, nonce, nonce_len, tds_dstr_cstr(&tds->login->password), &em_size);
128 0 : if (!em)
129 : goto error;
130 :
131 0 : tds->out_flag = TDS_NORMAL;
132 :
133 : /* password */
134 0 : tds5_send_msg(tds, TDS5_MSG_SEC_LOGPWD3);
135 0 : tds_put_n(tds, "\xec\x0e\x00\x01\x00\x00\x00\x00\x00\x00\x00\xe1\xff\xff\xff\x7f\x00", 0x11);
136 0 : tds_put_byte(tds, TDS5_PARAMS_TOKEN);
137 0 : tds_put_int(tds, em_size);
138 0 : tds_put_n(tds, em, em_size);
139 :
140 : /* remote password */
141 0 : tds5_send_msg(tds, TDS5_MSG_SEC_REMPWD3);
142 0 : tds_put_n(tds, "\xec\x17\x00\x02\x00\x00\x00\x00\x00\x00\x00\x27\xff\x00\x00\x00\x00\x00\x00\x00\xe1\xff\xff\xff\x7f\x00", 0x1a);
143 0 : tds_put_byte(tds, TDS5_PARAMS_TOKEN);
144 0 : tds_put_byte(tds, 0);
145 0 : tds_put_int(tds, em_size);
146 0 : tds_put_n(tds, em, em_size);
147 :
148 0 : free(em);
149 :
150 0 : rc = tds_flush_packet(tds);
151 :
152 0 : error:
153 0 : tds5_negotiate_free(tds->conn, tds_auth);
154 0 : tds->conn->authentication = NULL;
155 :
156 0 : return rc;
157 : }
158 :
159 : /**
160 : * Initialize Sybase negotiate handling
161 : * @param tds A pointer to the TDSSOCKET structure managing a client/server operation.
162 : * @return authentication info
163 : */
164 : TDSAUTHENTICATION *
165 0 : tds5_negotiate_get_auth(TDSSOCKET * tds)
166 : {
167 : TDS5NEGOTIATE *auth;
168 :
169 0 : if (!tds->login)
170 : return NULL;
171 :
172 0 : auth = tds_new0(TDS5NEGOTIATE, 1);
173 0 : if (!auth)
174 : return NULL;
175 :
176 0 : auth->tds_auth.free = tds5_negotiate_free;
177 0 : auth->tds_auth.handle_next = tds5_negotiate_handle_next;
178 :
179 0 : return (TDSAUTHENTICATION *) auth;
180 : }
181 :
182 : #else /* not HAVE_GNUTLS or HAVE_OPENSSL */
183 :
184 : TDSAUTHENTICATION *
185 : tds5_negotiate_get_auth(TDSSOCKET * tds)
186 : {
187 : tdsdump_log(TDS_DBG_ERROR,
188 : "Sybase authentication not supported if GnuTLS or OpenSSL are not present\n");
189 :
190 : return NULL;
191 : }
192 :
193 : #endif
194 :
195 : /** @} */
196 :
|