source: branches/samba-3.5.x/source3/libaddns/dnsgss.c

Last change on this file was 773, checked in by Herwig Bauernfeind, 12 years ago

Samba Server 3.5: Update branch to 3.5.20

File size: 8.8 KB
Line 
1/*
2 Public Interface file for Linux DNS client library implementation
3
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
6
7 ** NOTE! The following LGPL license applies to the libaddns
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "dns.h"
26#include <ctype.h>
27
28
29#ifdef HAVE_GSSAPI_SUPPORT
30
31/*********************************************************************
32*********************************************************************/
33
34#ifndef HAVE_STRUPR
35static int strupr( char *szDomainName )
36{
37 if ( !szDomainName ) {
38 return ( 0 );
39 }
40 while ( *szDomainName != '\0' ) {
41 *szDomainName = toupper( *szDomainName );
42 szDomainName++;
43 }
44 return ( 0 );
45}
46#endif
47
48#if 0
49/*********************************************************************
50*********************************************************************/
51
52static void display_status_1( const char *m, OM_uint32 code, int type )
53{
54 OM_uint32 maj_stat, min_stat;
55 gss_buffer_desc msg;
56 OM_uint32 msg_ctx;
57
58 msg_ctx = 0;
59 while ( 1 ) {
60 maj_stat = gss_display_status( &min_stat, code,
61 type, GSS_C_NULL_OID,
62 &msg_ctx, &msg );
63 fprintf( stdout, "GSS-API error %s: %s\n", m,
64 ( char * ) msg.value );
65 ( void ) gss_release_buffer( &min_stat, &msg );
66
67 if ( !msg_ctx )
68 break;
69 }
70}
71
72/*********************************************************************
73*********************************************************************/
74
75void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
76{
77 display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
78 display_status_1( msg, min_stat, GSS_C_MECH_CODE );
79}
80#endif
81
82static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
83 struct dns_connection *conn,
84 const char *keyname,
85 const gss_name_t target_name,
86 gss_ctx_id_t *ctx,
87 enum dns_ServerType srv_type )
88{
89 struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
90 OM_uint32 major, minor;
91 OM_uint32 ret_flags;
92 DNS_ERROR err;
93
94 gss_OID_desc krb5_oid_desc =
95 { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
96
97 *ctx = GSS_C_NO_CONTEXT;
98 input_ptr = NULL;
99
100 do {
101 major = gss_init_sec_context(
102 &minor, NULL, ctx, target_name, &krb5_oid_desc,
103 GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
104 GSS_C_CONF_FLAG |
105 GSS_C_INTEG_FLAG,
106 0, NULL, input_ptr, NULL, &output_desc,
107 &ret_flags, NULL );
108
109 if (input_ptr != NULL) {
110 TALLOC_FREE(input_desc.value);
111 }
112
113 if (output_desc.length != 0) {
114
115 struct dns_request *req;
116 struct dns_rrec *rec;
117 struct dns_buffer *buf;
118
119 time_t t = time(NULL);
120
121 err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
122 DNS_CLASS_IN, &req);
123 if (!ERR_DNS_IS_OK(err)) goto error;
124
125 err = dns_create_tkey_record(
126 req, keyname, "gss.microsoft.com", t,
127 t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
128 output_desc.length, (uint8 *)output_desc.value,
129 &rec );
130 if (!ERR_DNS_IS_OK(err)) goto error;
131
132 /* Windows 2000 DNS is broken and requires the
133 TKEY payload in the Answer section instead
134 of the Additional seciton like Windows 2003 */
135
136 if ( srv_type == DNS_SRV_WIN2000 ) {
137 err = dns_add_rrec(req, rec, &req->num_answers,
138 &req->answers);
139 } else {
140 err = dns_add_rrec(req, rec, &req->num_additionals,
141 &req->additionals);
142 }
143
144 if (!ERR_DNS_IS_OK(err)) goto error;
145
146 err = dns_marshall_request(req, req, &buf);
147 if (!ERR_DNS_IS_OK(err)) goto error;
148
149 err = dns_send(conn, buf);
150 if (!ERR_DNS_IS_OK(err)) goto error;
151
152 TALLOC_FREE(req);
153 }
154
155 gss_release_buffer(&minor, &output_desc);
156
157 if ((major != GSS_S_COMPLETE) &&
158 (major != GSS_S_CONTINUE_NEEDED)) {
159 return ERROR_DNS_GSS_ERROR;
160 }
161
162 if (major == GSS_S_CONTINUE_NEEDED) {
163
164 struct dns_request *resp;
165 struct dns_buffer *buf;
166 struct dns_tkey_record *tkey;
167 struct dns_rrec *tkey_answer = NULL;
168 uint16_t i;
169
170 err = dns_receive(mem_ctx, conn, &buf);
171 if (!ERR_DNS_IS_OK(err)) goto error;
172
173 err = dns_unmarshall_request(buf, buf, &resp);
174 if (!ERR_DNS_IS_OK(err)) goto error;
175
176 /*
177 * TODO: Compare id and keyname
178 */
179
180 for (i=0; i < resp->num_answers; i++) {
181 if (resp->answers[i]->type != QTYPE_TKEY) {
182 continue;
183 }
184
185 tkey_answer = resp->answers[i];
186 }
187
188 if (tkey_answer == NULL) {
189 err = ERROR_DNS_INVALID_MESSAGE;
190 goto error;
191 }
192
193 err = dns_unmarshall_tkey_record(
194 mem_ctx, resp->answers[0], &tkey);
195 if (!ERR_DNS_IS_OK(err)) goto error;
196
197 input_desc.length = tkey->key_length;
198 input_desc.value = talloc_move(mem_ctx, &tkey->key);
199
200 input_ptr = &input_desc;
201
202 TALLOC_FREE(buf);
203 }
204
205 } while ( major == GSS_S_CONTINUE_NEEDED );
206
207 /* If we arrive here, we have a valid security context */
208
209 err = ERROR_DNS_SUCCESS;
210
211 error:
212
213 return err;
214}
215
216DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
217 const char *servername,
218 const char *keyname,
219 gss_ctx_id_t *gss_ctx,
220 enum dns_ServerType srv_type )
221{
222 OM_uint32 major, minor;
223
224 char *upcaserealm, *targetname;
225 DNS_ERROR err;
226
227 gss_buffer_desc input_name;
228 struct dns_connection *conn;
229
230 gss_name_t targ_name;
231
232 gss_OID_desc nt_host_oid_desc =
233 {10, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
234
235 TALLOC_CTX *mem_ctx;
236
237 if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
238 return ERROR_DNS_NO_MEMORY;
239 }
240
241 err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
242 if (!ERR_DNS_IS_OK(err)) goto error;
243
244 if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
245 err = ERROR_DNS_NO_MEMORY;
246 goto error;
247 }
248
249 strupr(upcaserealm);
250
251 if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
252 servername, upcaserealm))) {
253 err = ERROR_DNS_NO_MEMORY;
254 goto error;
255 }
256
257 input_name.value = targetname;
258 input_name.length = strlen(targetname);
259
260 major = gss_import_name( &minor, &input_name,
261 &nt_host_oid_desc, &targ_name );
262
263 if (major) {
264 err = ERROR_DNS_GSS_ERROR;
265 goto error;
266 }
267
268 err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
269 targ_name, gss_ctx, srv_type );
270
271 gss_release_name( &minor, &targ_name );
272
273 error:
274 TALLOC_FREE(mem_ctx);
275
276 return err;
277}
278
279DNS_ERROR dns_sign_update(struct dns_update_request *req,
280 gss_ctx_id_t gss_ctx,
281 const char *keyname,
282 const char *algorithmname,
283 time_t time_signed, uint16 fudge)
284{
285 struct dns_buffer *buf;
286 DNS_ERROR err;
287 struct dns_domain_name *key, *algorithm;
288 struct gss_buffer_desc_struct msg, mic;
289 OM_uint32 major, minor;
290 struct dns_rrec *rec;
291
292 err = dns_marshall_update_request(req, req, &buf);
293 if (!ERR_DNS_IS_OK(err)) return err;
294
295 err = dns_domain_name_from_string(buf, keyname, &key);
296 if (!ERR_DNS_IS_OK(err)) goto error;
297
298 err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
299 if (!ERR_DNS_IS_OK(err)) goto error;
300
301 dns_marshall_domain_name(buf, key);
302 dns_marshall_uint16(buf, DNS_CLASS_ANY);
303 dns_marshall_uint32(buf, 0); /* TTL */
304 dns_marshall_domain_name(buf, algorithm);
305 dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
306 dns_marshall_uint32(buf, time_signed);
307 dns_marshall_uint16(buf, fudge);
308 dns_marshall_uint16(buf, 0); /* error */
309 dns_marshall_uint16(buf, 0); /* other len */
310
311 err = buf->error;
312 if (!ERR_DNS_IS_OK(buf->error)) goto error;
313
314 msg.value = (void *)buf->data;
315 msg.length = buf->offset;
316
317 major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
318 if (major != 0) {
319 err = ERROR_DNS_GSS_ERROR;
320 goto error;
321 }
322
323 if (mic.length > 0xffff) {
324 gss_release_buffer(&minor, &mic);
325 err = ERROR_DNS_GSS_ERROR;
326 goto error;
327 }
328
329 err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
330 fudge, mic.length, (uint8 *)mic.value,
331 req->id, 0, &rec);
332 gss_release_buffer(&minor, &mic);
333 if (!ERR_DNS_IS_OK(err)) goto error;
334
335 err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals);
336
337 error:
338 TALLOC_FREE(buf);
339 return err;
340}
341
342#endif /* HAVE_GSSAPI_SUPPORT */
Note: See TracBrowser for help on using the repository browser.