lib/addns: remove pointless check for resp->num_additionals != 1
[Samba.git] / lib / addns / dnsgss.c
blobfe7c6ca536e56610dbc7d87cea0285e3f09de6a4
1 /*
2 Public Interface file for Linux DNS client library implementation
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
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
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.
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.
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/>.
25 #include "dns.h"
26 #include <ctype.h>
29 #ifdef HAVE_GSSAPI_SUPPORT
31 /*********************************************************************
32 *********************************************************************/
34 #ifndef HAVE_STRUPR
35 static int strupr( char *szDomainName )
37 if ( !szDomainName ) {
38 return ( 0 );
40 while ( *szDomainName != '\0' ) {
41 *szDomainName = toupper( *szDomainName );
42 szDomainName++;
44 return ( 0 );
46 #endif
48 #if 0
49 /*********************************************************************
50 *********************************************************************/
52 static void display_status_1( const char *m, OM_uint32 code, int type )
54 OM_uint32 maj_stat, min_stat;
55 gss_buffer_desc msg;
56 OM_uint32 msg_ctx;
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 );
67 if ( !msg_ctx )
68 break;
72 /*********************************************************************
73 *********************************************************************/
75 void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
77 display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
78 display_status_1( msg, min_stat, GSS_C_MECH_CODE );
80 #endif
82 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 )
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;
94 gss_OID_desc krb5_oid_desc =
95 { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
97 *ctx = GSS_C_NO_CONTEXT;
98 input_ptr = NULL;
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 );
109 if (input_ptr != NULL) {
110 TALLOC_FREE(input_desc.value);
113 if (output_desc.length != 0) {
115 struct dns_request *req;
116 struct dns_rrec *rec;
117 struct dns_buffer *buf;
119 time_t t = time(NULL);
121 err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
122 DNS_CLASS_IN, &req);
123 if (!ERR_DNS_IS_OK(err)) goto error;
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;
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 */
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);
144 if (!ERR_DNS_IS_OK(err)) goto error;
146 err = dns_marshall_request(req, req, &buf);
147 if (!ERR_DNS_IS_OK(err)) goto error;
149 err = dns_send(conn, buf);
150 if (!ERR_DNS_IS_OK(err)) goto error;
152 TALLOC_FREE(req);
155 gss_release_buffer(&minor, &output_desc);
157 if ((major != GSS_S_COMPLETE) &&
158 (major != GSS_S_CONTINUE_NEEDED)) {
159 return ERROR_DNS_GSS_ERROR;
162 if (major == GSS_S_CONTINUE_NEEDED) {
164 struct dns_request *resp;
165 struct dns_buffer *buf;
166 struct dns_tkey_record *tkey;
168 err = dns_receive(mem_ctx, conn, &buf);
169 if (!ERR_DNS_IS_OK(err)) goto error;
171 err = dns_unmarshall_request(buf, buf, &resp);
172 if (!ERR_DNS_IS_OK(err)) goto error;
175 * TODO: Compare id and keyname
178 if ((resp->num_answers == 0) ||
179 (resp->answers[0]->type != QTYPE_TKEY)) {
180 err = ERROR_DNS_INVALID_MESSAGE;
181 goto error;
184 err = dns_unmarshall_tkey_record(
185 mem_ctx, resp->answers[0], &tkey);
186 if (!ERR_DNS_IS_OK(err)) goto error;
188 input_desc.length = tkey->key_length;
189 input_desc.value = talloc_move(mem_ctx, &tkey->key);
191 input_ptr = &input_desc;
193 TALLOC_FREE(buf);
196 } while ( major == GSS_S_CONTINUE_NEEDED );
198 /* If we arrive here, we have a valid security context */
200 err = ERROR_DNS_SUCCESS;
202 error:
204 return err;
207 DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
208 const char *servername,
209 const char *keyname,
210 gss_ctx_id_t *gss_ctx,
211 enum dns_ServerType srv_type )
213 OM_uint32 major, minor;
215 char *upcaserealm, *targetname;
216 DNS_ERROR err;
218 gss_buffer_desc input_name;
219 struct dns_connection *conn;
221 gss_name_t targ_name;
223 gss_OID_desc nt_host_oid_desc =
224 {10, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
226 TALLOC_CTX *mem_ctx;
228 if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
229 return ERROR_DNS_NO_MEMORY;
232 err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
233 if (!ERR_DNS_IS_OK(err)) goto error;
235 if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
236 err = ERROR_DNS_NO_MEMORY;
237 goto error;
240 strupr(upcaserealm);
242 if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
243 servername, upcaserealm))) {
244 err = ERROR_DNS_NO_MEMORY;
245 goto error;
248 input_name.value = targetname;
249 input_name.length = strlen(targetname);
251 major = gss_import_name( &minor, &input_name,
252 &nt_host_oid_desc, &targ_name );
254 if (major) {
255 err = ERROR_DNS_GSS_ERROR;
256 goto error;
259 err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
260 targ_name, gss_ctx, srv_type );
262 gss_release_name( &minor, &targ_name );
264 error:
265 TALLOC_FREE(mem_ctx);
267 return err;
270 DNS_ERROR dns_sign_update(struct dns_update_request *req,
271 gss_ctx_id_t gss_ctx,
272 const char *keyname,
273 const char *algorithmname,
274 time_t time_signed, uint16 fudge)
276 struct dns_buffer *buf;
277 DNS_ERROR err;
278 struct dns_domain_name *key, *algorithm;
279 struct gss_buffer_desc_struct msg, mic;
280 OM_uint32 major, minor;
281 struct dns_rrec *rec;
283 err = dns_marshall_update_request(req, req, &buf);
284 if (!ERR_DNS_IS_OK(err)) return err;
286 err = dns_domain_name_from_string(buf, keyname, &key);
287 if (!ERR_DNS_IS_OK(err)) goto error;
289 err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
290 if (!ERR_DNS_IS_OK(err)) goto error;
292 dns_marshall_domain_name(buf, key);
293 dns_marshall_uint16(buf, DNS_CLASS_ANY);
294 dns_marshall_uint32(buf, 0); /* TTL */
295 dns_marshall_domain_name(buf, algorithm);
296 dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
297 dns_marshall_uint32(buf, time_signed);
298 dns_marshall_uint16(buf, fudge);
299 dns_marshall_uint16(buf, 0); /* error */
300 dns_marshall_uint16(buf, 0); /* other len */
302 err = buf->error;
303 if (!ERR_DNS_IS_OK(buf->error)) goto error;
305 msg.value = (void *)buf->data;
306 msg.length = buf->offset;
308 major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
309 if (major != 0) {
310 err = ERROR_DNS_GSS_ERROR;
311 goto error;
314 if (mic.length > 0xffff) {
315 gss_release_buffer(&minor, &mic);
316 err = ERROR_DNS_GSS_ERROR;
317 goto error;
320 err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
321 fudge, mic.length, (uint8 *)mic.value,
322 req->id, 0, &rec);
323 gss_release_buffer(&minor, &mic);
324 if (!ERR_DNS_IS_OK(err)) goto error;
326 err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals);
328 error:
329 TALLOC_FREE(buf);
330 return err;
333 #endif /* HAVE_GSSAPI_SUPPORT */