Line data Source code
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
30 :
31 : /*********************************************************************
32 : *********************************************************************/
33 :
34 : #ifndef HAVE_STRUPR
35 42 : static int strupr( char *szDomainName )
36 : {
37 42 : if ( !szDomainName ) {
38 0 : return ( 0 );
39 : }
40 968 : while ( *szDomainName != '\0' ) {
41 926 : *szDomainName = toupper( *szDomainName );
42 926 : szDomainName++;
43 : }
44 42 : return ( 0 );
45 : }
46 : #endif
47 :
48 : #if 0
49 : /*********************************************************************
50 : *********************************************************************/
51 :
52 : static 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 :
75 : void 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 :
82 42 : static 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 0 : struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
90 0 : OM_uint32 major, minor;
91 0 : OM_uint32 ret_flags;
92 42 : struct dns_request *req = NULL;
93 42 : struct dns_buffer *buf = NULL;
94 0 : DNS_ERROR err;
95 :
96 42 : gss_OID_desc krb5_oid_desc =
97 : { 9, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
98 :
99 42 : *ctx = GSS_C_NO_CONTEXT;
100 42 : input_ptr = NULL;
101 :
102 0 : do {
103 84 : major = gss_init_sec_context(
104 : &minor, NULL, ctx, target_name, &krb5_oid_desc,
105 : GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
106 : GSS_C_CONF_FLAG |
107 : GSS_C_INTEG_FLAG,
108 : 0, NULL, input_ptr, NULL, &output_desc,
109 : &ret_flags, NULL );
110 :
111 84 : if (input_ptr != NULL) {
112 42 : TALLOC_FREE(input_desc.value);
113 : }
114 :
115 84 : if (output_desc.length != 0) {
116 :
117 0 : struct dns_rrec *rec;
118 :
119 42 : time_t t = time(NULL);
120 :
121 42 : err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
122 : DNS_CLASS_IN, &req);
123 42 : if (!ERR_DNS_IS_OK(err)) goto error;
124 :
125 42 : err = dns_create_tkey_record(
126 : req, keyname, "gss.microsoft.com", t,
127 : t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
128 42 : output_desc.length, (uint8_t *)output_desc.value,
129 : &rec );
130 42 : 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 section like Windows 2003 */
135 :
136 42 : if ( srv_type == DNS_SRV_WIN2000 ) {
137 0 : err = dns_add_rrec(req, rec, &req->num_answers,
138 0 : &req->answers);
139 : } else {
140 42 : err = dns_add_rrec(req, rec, &req->num_additionals,
141 42 : &req->additional);
142 : }
143 :
144 42 : if (!ERR_DNS_IS_OK(err)) goto error;
145 :
146 42 : err = dns_marshall_request(mem_ctx, req, &buf);
147 42 : if (!ERR_DNS_IS_OK(err)) goto error;
148 :
149 42 : err = dns_send(conn, buf);
150 42 : if (!ERR_DNS_IS_OK(err)) goto error;
151 :
152 42 : TALLOC_FREE(buf);
153 42 : TALLOC_FREE(req);
154 : }
155 :
156 84 : gss_release_buffer(&minor, &output_desc);
157 :
158 84 : if ((major != GSS_S_COMPLETE) &&
159 : (major != GSS_S_CONTINUE_NEEDED)) {
160 0 : return ERROR_DNS_GSS_ERROR;
161 : }
162 :
163 84 : if (major == GSS_S_CONTINUE_NEEDED) {
164 :
165 0 : struct dns_request *resp;
166 0 : struct dns_tkey_record *tkey;
167 42 : struct dns_rrec *tkey_answer = NULL;
168 0 : uint16_t i;
169 :
170 42 : err = dns_receive(mem_ctx, conn, &buf);
171 42 : if (!ERR_DNS_IS_OK(err)) goto error;
172 :
173 42 : err = dns_unmarshall_request(buf, buf, &resp);
174 42 : if (!ERR_DNS_IS_OK(err)) goto error;
175 :
176 : /*
177 : * TODO: Compare id and keyname
178 : */
179 :
180 84 : for (i=0; i < resp->num_answers; i++) {
181 42 : if (resp->answers[i]->type != QTYPE_TKEY) {
182 0 : continue;
183 : }
184 :
185 42 : tkey_answer = resp->answers[i];
186 : }
187 :
188 42 : if (tkey_answer == NULL) {
189 0 : err = ERROR_DNS_INVALID_MESSAGE;
190 0 : goto error;
191 : }
192 :
193 42 : err = dns_unmarshall_tkey_record(
194 42 : mem_ctx, resp->answers[0], &tkey);
195 42 : if (!ERR_DNS_IS_OK(err)) goto error;
196 :
197 42 : input_desc.length = tkey->key_length;
198 42 : input_desc.value = talloc_move(mem_ctx, &tkey->key);
199 :
200 42 : input_ptr = &input_desc;
201 :
202 42 : TALLOC_FREE(buf);
203 : }
204 :
205 84 : } while ( major == GSS_S_CONTINUE_NEEDED );
206 :
207 : /* If we arrive here, we have a valid security context */
208 :
209 42 : err = ERROR_DNS_SUCCESS;
210 :
211 42 : error:
212 :
213 42 : TALLOC_FREE(buf);
214 42 : TALLOC_FREE(req);
215 42 : return err;
216 : }
217 :
218 42 : DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
219 : const char *servername,
220 : const char *keyname,
221 : gss_ctx_id_t *gss_ctx,
222 : enum dns_ServerType srv_type )
223 : {
224 0 : OM_uint32 major, minor;
225 :
226 0 : char *upcaserealm, *targetname;
227 0 : DNS_ERROR err;
228 :
229 0 : gss_buffer_desc input_name;
230 0 : struct dns_connection *conn;
231 :
232 0 : gss_name_t targ_name;
233 :
234 42 : gss_OID_desc nt_host_oid_desc =
235 : {10, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
236 :
237 0 : TALLOC_CTX *mem_ctx;
238 :
239 42 : if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
240 0 : return ERROR_DNS_NO_MEMORY;
241 : }
242 :
243 42 : err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
244 42 : if (!ERR_DNS_IS_OK(err)) goto error;
245 :
246 42 : if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
247 0 : err = ERROR_DNS_NO_MEMORY;
248 0 : goto error;
249 : }
250 :
251 42 : strupr(upcaserealm);
252 :
253 42 : if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
254 : servername, upcaserealm))) {
255 0 : err = ERROR_DNS_NO_MEMORY;
256 0 : goto error;
257 : }
258 :
259 42 : input_name.value = targetname;
260 42 : input_name.length = strlen(targetname);
261 :
262 42 : major = gss_import_name( &minor, &input_name,
263 : &nt_host_oid_desc, &targ_name );
264 :
265 42 : if (major) {
266 0 : err = ERROR_DNS_GSS_ERROR;
267 0 : goto error;
268 : }
269 :
270 42 : err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
271 : targ_name, gss_ctx, srv_type );
272 :
273 42 : gss_release_name( &minor, &targ_name );
274 :
275 42 : error:
276 42 : TALLOC_FREE(mem_ctx);
277 :
278 42 : return err;
279 : }
280 :
281 42 : DNS_ERROR dns_sign_update(struct dns_update_request *req,
282 : gss_ctx_id_t gss_ctx,
283 : const char *keyname,
284 : const char *algorithmname,
285 : time_t time_signed, uint16_t fudge)
286 : {
287 0 : struct dns_buffer *buf;
288 0 : DNS_ERROR err;
289 0 : struct dns_domain_name *key, *algorithm;
290 0 : struct gss_buffer_desc_struct msg, mic;
291 0 : OM_uint32 major, minor;
292 0 : struct dns_rrec *rec;
293 :
294 42 : err = dns_marshall_update_request(req, req, &buf);
295 42 : if (!ERR_DNS_IS_OK(err)) return err;
296 :
297 42 : err = dns_domain_name_from_string(buf, keyname, &key);
298 42 : if (!ERR_DNS_IS_OK(err)) goto error;
299 :
300 42 : err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
301 42 : if (!ERR_DNS_IS_OK(err)) goto error;
302 :
303 42 : dns_marshall_domain_name(buf, key);
304 42 : dns_marshall_uint16(buf, DNS_CLASS_ANY);
305 42 : dns_marshall_uint32(buf, 0); /* TTL */
306 42 : dns_marshall_domain_name(buf, algorithm);
307 42 : dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
308 42 : dns_marshall_uint32(buf, time_signed);
309 42 : dns_marshall_uint16(buf, fudge);
310 42 : dns_marshall_uint16(buf, 0); /* error */
311 42 : dns_marshall_uint16(buf, 0); /* other len */
312 :
313 42 : err = buf->error;
314 42 : if (!ERR_DNS_IS_OK(buf->error)) goto error;
315 :
316 42 : msg.value = (void *)buf->data;
317 42 : msg.length = buf->offset;
318 :
319 42 : major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
320 42 : if (major != 0) {
321 0 : err = ERROR_DNS_GSS_ERROR;
322 0 : goto error;
323 : }
324 :
325 42 : if (mic.length > 0xffff) {
326 0 : gss_release_buffer(&minor, &mic);
327 0 : err = ERROR_DNS_GSS_ERROR;
328 0 : goto error;
329 : }
330 :
331 42 : err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
332 42 : fudge, mic.length, (uint8_t *)mic.value,
333 42 : req->id, 0, &rec);
334 42 : gss_release_buffer(&minor, &mic);
335 42 : if (!ERR_DNS_IS_OK(err)) goto error;
336 :
337 42 : err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
338 :
339 42 : error:
340 42 : TALLOC_FREE(buf);
341 42 : return err;
342 : }
343 :
344 : #endif /* HAVE_GSSAPI */
|