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
tds5_negotiate_free(TDSCONNECTION * conn,TDSAUTHENTICATION * tds_auth)68 tds5_negotiate_free(TDSCONNECTION * conn, TDSAUTHENTICATION * tds_auth)
69 {
70 TDS5NEGOTIATE *auth = (TDS5NEGOTIATE *) tds_auth;
71
72 free(auth->tds_auth.packet);
73 free(auth);
74
75 return TDS_SUCCESS;
76 }
77
78 static void
tds5_send_msg(TDSSOCKET * tds,uint16_t msg_type)79 tds5_send_msg(TDSSOCKET *tds, uint16_t msg_type)
80 {
81 tds_put_tinyint(tds, TDS_MSG_TOKEN);
82 tds_put_tinyint(tds, 3); /* length */
83 tds_put_tinyint(tds, 1); /* status, 1=has params */
84 tds_put_smallint(tds, msg_type);
85 }
86
87 static TDSRET
tds5_negotiate_handle_next(TDSSOCKET * tds,TDSAUTHENTICATION * tds_auth,size_t len)88 tds5_negotiate_handle_next(TDSSOCKET * tds, TDSAUTHENTICATION * tds_auth, size_t len)
89 {
90 TDSPARAMINFO *info;
91 void *rsa, *nonce = NULL;
92 size_t rsa_len, nonce_len = 0;
93 void *em;
94 size_t em_size;
95 TDSRET rc = TDS_FAIL;
96
97 /* send next data for authentication */
98
99 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 if (tds_auth->msg_type != TDS5_MSG_SEC_ENCRYPT3)
110 goto error;
111
112 info = tds->param_info;
113 if (!info || info->num_cols < 2)
114 goto error;
115
116 if (info->columns[1]->column_type != SYBLONGBINARY)
117 goto error;
118 if (info->num_cols >= 3 && info->columns[2]->column_type != SYBLONGBINARY)
119 goto error;
120 rsa = ((TDSBLOB*) info->columns[1]->column_data)->textvalue;
121 rsa_len = info->columns[1]->column_size;
122 if (info->num_cols >= 3) {
123 nonce = ((TDSBLOB*) info->columns[2]->column_data)->textvalue;
124 nonce_len = info->columns[2]->column_size;
125 }
126
127 em = tds5_rsa_encrypt(rsa, rsa_len, nonce, nonce_len, tds_dstr_cstr(&tds->login->password), &em_size);
128 if (!em)
129 goto error;
130
131 tds->out_flag = TDS_NORMAL;
132
133 /* password */
134 tds5_send_msg(tds, TDS5_MSG_SEC_LOGPWD3);
135 tds_put_n(tds, "\xec\x0e\x00\x01\x00\x00\x00\x00\x00\x00\x00\xe1\xff\xff\xff\x7f\x00", 0x11);
136 tds_put_byte(tds, TDS5_PARAMS_TOKEN);
137 tds_put_int(tds, em_size);
138 tds_put_n(tds, em, em_size);
139
140 /* remote password */
141 tds5_send_msg(tds, TDS5_MSG_SEC_REMPWD3);
142 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 tds_put_byte(tds, TDS5_PARAMS_TOKEN);
144 tds_put_byte(tds, 0);
145 tds_put_int(tds, em_size);
146 tds_put_n(tds, em, em_size);
147
148 free(em);
149
150 rc = tds_flush_packet(tds);
151
152 error:
153 tds5_negotiate_free(tds->conn, tds_auth);
154 tds->conn->authentication = NULL;
155
156 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 *
tds5_negotiate_get_auth(TDSSOCKET * tds)165 tds5_negotiate_get_auth(TDSSOCKET * tds)
166 {
167 TDS5NEGOTIATE *auth;
168
169 if (!tds->login)
170 return NULL;
171
172 auth = tds_new0(TDS5NEGOTIATE, 1);
173 if (!auth)
174 return NULL;
175
176 auth->tds_auth.free = tds5_negotiate_free;
177 auth->tds_auth.handle_next = tds5_negotiate_handle_next;
178
179 return (TDSAUTHENTICATION *) auth;
180 }
181
182 #else /* not HAVE_GNUTLS or HAVE_OPENSSL */
183
184 TDSAUTHENTICATION *
tds5_negotiate_get_auth(TDSSOCKET * tds)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
197