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