source: branches/samba-3.3.x/source/libaddns/dnsgss.c@ 309

Last change on this file since 309 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 8.3 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
34static int strupr( char *szDomainName )
35{
36 if ( !szDomainName ) {
37 return ( 0 );
38 }
39 while ( *szDomainName != '\0' ) {
40 *szDomainName = toupper( *szDomainName );
41 szDomainName++;
42 }
43 return ( 0 );
44}
45
46#if 0
47/*********************************************************************
48*********************************************************************/
49
50static void display_status_1( const char *m, OM_uint32 code, int type )
51{
52 OM_uint32 maj_stat, min_stat;
53 gss_buffer_desc msg;
54 OM_uint32 msg_ctx;
55
56 msg_ctx = 0;
57 while ( 1 ) {
58 maj_stat = gss_display_status( &min_stat, code,
59 type, GSS_C_NULL_OID,
60 &msg_ctx, &msg );
61 fprintf( stdout, "GSS-API error %s: %s\n", m,
62 ( char * ) msg.value );
63 ( void ) gss_release_buffer( &min_stat, &msg );
64
65 if ( !msg_ctx )
66 break;
67 }
68}
69
70/*********************************************************************
71*********************************************************************/
72
73void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
74{
75 display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
76 display_status_1( msg, min_stat, GSS_C_MECH_CODE );
77}
78#endif
79
80static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
81 struct dns_connection *conn,
82 const char *keyname,
83 const gss_name_t target_name,
84 gss_ctx_id_t *ctx,
85 enum dns_ServerType srv_type )
86{
87 struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
88 OM_uint32 major, minor;
89 OM_uint32 ret_flags;
90 DNS_ERROR err;
91
92 gss_OID_desc krb5_oid_desc =
93 { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
94
95 *ctx = GSS_C_NO_CONTEXT;
96 input_ptr = NULL;
97
98 do {
99 major = gss_init_sec_context(
100 &minor, NULL, ctx, target_name, &krb5_oid_desc,
101 GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
102 GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
103 GSS_C_INTEG_FLAG | GSS_C_DELEG_FLAG,
104 0, NULL, input_ptr, NULL, &output_desc,
105 &ret_flags, NULL );
106
107 if (input_ptr != NULL) {
108 TALLOC_FREE(input_desc.value);
109 }
110
111 if (output_desc.length != 0) {
112
113 struct dns_request *req;
114 struct dns_rrec *rec;
115 struct dns_buffer *buf;
116
117 time_t t = time(NULL);
118
119 err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
120 DNS_CLASS_IN, &req);
121 if (!ERR_DNS_IS_OK(err)) goto error;
122
123 err = dns_create_tkey_record(
124 req, keyname, "gss.microsoft.com", t,
125 t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
126 output_desc.length, (uint8 *)output_desc.value,
127 &rec );
128 if (!ERR_DNS_IS_OK(err)) goto error;
129
130 /* Windows 2000 DNS is broken and requires the
131 TKEY payload in the Answer section instead
132 of the Additional seciton like Windows 2003 */
133
134 if ( srv_type == DNS_SRV_WIN2000 ) {
135 err = dns_add_rrec(req, rec, &req->num_answers,
136 &req->answers);
137 } else {
138 err = dns_add_rrec(req, rec, &req->num_additionals,
139 &req->additionals);
140 }
141
142 if (!ERR_DNS_IS_OK(err)) goto error;
143
144 err = dns_marshall_request(req, req, &buf);
145 if (!ERR_DNS_IS_OK(err)) goto error;
146
147 err = dns_send(conn, buf);
148 if (!ERR_DNS_IS_OK(err)) goto error;
149
150 TALLOC_FREE(req);
151 }
152
153 gss_release_buffer(&minor, &output_desc);
154
155 if ((major != GSS_S_COMPLETE) &&
156 (major != GSS_S_CONTINUE_NEEDED)) {
157 return ERROR_DNS_GSS_ERROR;
158 }
159
160 if (major == GSS_S_CONTINUE_NEEDED) {
161
162 struct dns_request *resp;
163 struct dns_buffer *buf;
164 struct dns_tkey_record *tkey;
165
166 err = dns_receive(mem_ctx, conn, &buf);
167 if (!ERR_DNS_IS_OK(err)) goto error;
168
169 err = dns_unmarshall_request(buf, buf, &resp);
170 if (!ERR_DNS_IS_OK(err)) goto error;
171
172 /*
173 * TODO: Compare id and keyname
174 */
175
176 if ((resp->num_additionals != 1) ||
177 (resp->num_answers == 0) ||
178 (resp->answers[0]->type != QTYPE_TKEY)) {
179 err = ERROR_DNS_INVALID_MESSAGE;
180 goto error;
181 }
182
183 err = dns_unmarshall_tkey_record(
184 mem_ctx, resp->answers[0], &tkey);
185 if (!ERR_DNS_IS_OK(err)) goto error;
186
187 input_desc.length = tkey->key_length;
188 input_desc.value = talloc_move(mem_ctx, &tkey->key);
189
190 input_ptr = &input_desc;
191
192 TALLOC_FREE(buf);
193 }
194
195 } while ( major == GSS_S_CONTINUE_NEEDED );
196
197 /* If we arrive here, we have a valid security context */
198
199 err = ERROR_DNS_SUCCESS;
200
201 error:
202
203 return err;
204}
205
206DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
207 const char *servername,
208 const char *keyname,
209 gss_ctx_id_t *gss_ctx,
210 enum dns_ServerType srv_type )
211{
212 OM_uint32 major, minor;
213
214 char *upcaserealm, *targetname;
215 DNS_ERROR err;
216
217 gss_buffer_desc input_name;
218 struct dns_connection *conn;
219
220 gss_name_t targ_name;
221
222 gss_OID_desc nt_host_oid_desc =
223 {10, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
224
225 TALLOC_CTX *mem_ctx;
226
227 if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
228 return ERROR_DNS_NO_MEMORY;
229 }
230
231 err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
232 if (!ERR_DNS_IS_OK(err)) goto error;
233
234 if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
235 err = ERROR_DNS_NO_MEMORY;
236 goto error;
237 }
238
239 strupr(upcaserealm);
240
241 if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
242 servername, upcaserealm))) {
243 err = ERROR_DNS_NO_MEMORY;
244 goto error;
245 }
246
247 input_name.value = targetname;
248 input_name.length = strlen(targetname);
249
250 major = gss_import_name( &minor, &input_name,
251 &nt_host_oid_desc, &targ_name );
252
253 if (major) {
254 err = ERROR_DNS_GSS_ERROR;
255 goto error;
256 }
257
258 err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
259 targ_name, gss_ctx, srv_type );
260
261 gss_release_name( &minor, &targ_name );
262
263 error:
264 TALLOC_FREE(mem_ctx);
265
266 return err;
267}
268
269DNS_ERROR dns_sign_update(struct dns_update_request *req,
270 gss_ctx_id_t gss_ctx,
271 const char *keyname,
272 const char *algorithmname,
273 time_t time_signed, uint16 fudge)
274{
275 struct dns_buffer *buf;
276 DNS_ERROR err;
277 struct dns_domain_name *key, *algorithm;
278 struct gss_buffer_desc_struct msg, mic;
279 OM_uint32 major, minor;
280 struct dns_rrec *rec;
281
282 err = dns_marshall_update_request(req, req, &buf);
283 if (!ERR_DNS_IS_OK(err)) return err;
284
285 err = dns_domain_name_from_string(buf, keyname, &key);
286 if (!ERR_DNS_IS_OK(err)) goto error;
287
288 err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
289 if (!ERR_DNS_IS_OK(err)) goto error;
290
291 dns_marshall_domain_name(buf, key);
292 dns_marshall_uint16(buf, DNS_CLASS_ANY);
293 dns_marshall_uint32(buf, 0); /* TTL */
294 dns_marshall_domain_name(buf, algorithm);
295 dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
296 dns_marshall_uint32(buf, time_signed);
297 dns_marshall_uint16(buf, fudge);
298 dns_marshall_uint16(buf, 0); /* error */
299 dns_marshall_uint16(buf, 0); /* other len */
300
301 err = buf->error;
302 if (!ERR_DNS_IS_OK(buf->error)) goto error;
303
304 msg.value = (void *)buf->data;
305 msg.length = buf->offset;
306
307 major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
308 if (major != 0) {
309 err = ERROR_DNS_GSS_ERROR;
310 goto error;
311 }
312
313 if (mic.length > 0xffff) {
314 gss_release_buffer(&minor, &mic);
315 err = ERROR_DNS_GSS_ERROR;
316 goto error;
317 }
318
319 err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
320 fudge, mic.length, (uint8 *)mic.value,
321 req->id, 0, &rec);
322 gss_release_buffer(&minor, &mic);
323 if (!ERR_DNS_IS_OK(err)) goto error;
324
325 err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals);
326
327 error:
328 TALLOC_FREE(buf);
329 return err;
330}
331
332#endif /* HAVE_GSSAPI_SUPPORT */
Note: See TracBrowser for help on using the repository browser.