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
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/>.
29 #ifdef HAVE_GSSAPI_SUPPORT
31 /*********************************************************************
32 *********************************************************************/
35 static int strupr( char *szDomainName
)
37 if ( !szDomainName
) {
40 while ( *szDomainName
!= '\0' ) {
41 *szDomainName
= toupper( *szDomainName
);
49 /*********************************************************************
50 *********************************************************************/
52 static void display_status_1( const char *m
, OM_uint32 code
, int type
)
54 OM_uint32 maj_stat
, min_stat
;
60 maj_stat
= gss_display_status( &min_stat
, code
,
63 fprintf( stdout
, "GSS-API error %s: %s\n", m
,
64 ( char * ) msg
.value
);
65 ( void ) gss_release_buffer( &min_stat
, &msg
);
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
);
82 static DNS_ERROR
dns_negotiate_gss_ctx_int( TALLOC_CTX
*mem_ctx
,
83 struct dns_connection
*conn
,
85 const gss_name_t target_name
,
87 enum dns_ServerType srv_type
)
89 struct gss_buffer_desc_struct input_desc
, *input_ptr
, output_desc
;
90 OM_uint32 major
, minor
;
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
;
101 major
= gss_init_sec_context(
102 &minor
, NULL
, ctx
, target_name
, &krb5_oid_desc
,
103 GSS_C_REPLAY_FLAG
| GSS_C_MUTUAL_FLAG
|
106 0, NULL
, input_ptr
, NULL
, &output_desc
,
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
,
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
,
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
,
140 err
= dns_add_rrec(req
, rec
, &req
->num_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
;
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_additionals
!= 1) ||
179 (resp
->num_answers
== 0) ||
180 (resp
->answers
[0]->type
!= QTYPE_TKEY
)) {
181 err
= ERROR_DNS_INVALID_MESSAGE
;
185 err
= dns_unmarshall_tkey_record(
186 mem_ctx
, resp
->answers
[0], &tkey
);
187 if (!ERR_DNS_IS_OK(err
)) goto error
;
189 input_desc
.length
= tkey
->key_length
;
190 input_desc
.value
= talloc_move(mem_ctx
, &tkey
->key
);
192 input_ptr
= &input_desc
;
197 } while ( major
== GSS_S_CONTINUE_NEEDED
);
199 /* If we arrive here, we have a valid security context */
201 err
= ERROR_DNS_SUCCESS
;
208 DNS_ERROR
dns_negotiate_sec_ctx( const char *target_realm
,
209 const char *servername
,
211 gss_ctx_id_t
*gss_ctx
,
212 enum dns_ServerType srv_type
)
214 OM_uint32 major
, minor
;
216 char *upcaserealm
, *targetname
;
219 gss_buffer_desc input_name
;
220 struct dns_connection
*conn
;
222 gss_name_t targ_name
;
224 gss_OID_desc nt_host_oid_desc
=
225 {10, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
229 if (!(mem_ctx
= talloc_init("dns_negotiate_sec_ctx"))) {
230 return ERROR_DNS_NO_MEMORY
;
233 err
= dns_open_connection( servername
, DNS_TCP
, mem_ctx
, &conn
);
234 if (!ERR_DNS_IS_OK(err
)) goto error
;
236 if (!(upcaserealm
= talloc_strdup(mem_ctx
, target_realm
))) {
237 err
= ERROR_DNS_NO_MEMORY
;
243 if (!(targetname
= talloc_asprintf(mem_ctx
, "dns/%s@%s",
244 servername
, upcaserealm
))) {
245 err
= ERROR_DNS_NO_MEMORY
;
249 input_name
.value
= targetname
;
250 input_name
.length
= strlen(targetname
);
252 major
= gss_import_name( &minor
, &input_name
,
253 &nt_host_oid_desc
, &targ_name
);
256 err
= ERROR_DNS_GSS_ERROR
;
260 err
= dns_negotiate_gss_ctx_int(mem_ctx
, conn
, keyname
,
261 targ_name
, gss_ctx
, srv_type
);
263 gss_release_name( &minor
, &targ_name
);
266 TALLOC_FREE(mem_ctx
);
271 DNS_ERROR
dns_sign_update(struct dns_update_request
*req
,
272 gss_ctx_id_t gss_ctx
,
274 const char *algorithmname
,
275 time_t time_signed
, uint16 fudge
)
277 struct dns_buffer
*buf
;
279 struct dns_domain_name
*key
, *algorithm
;
280 struct gss_buffer_desc_struct msg
, mic
;
281 OM_uint32 major
, minor
;
282 struct dns_rrec
*rec
;
284 err
= dns_marshall_update_request(req
, req
, &buf
);
285 if (!ERR_DNS_IS_OK(err
)) return err
;
287 err
= dns_domain_name_from_string(buf
, keyname
, &key
);
288 if (!ERR_DNS_IS_OK(err
)) goto error
;
290 err
= dns_domain_name_from_string(buf
, algorithmname
, &algorithm
);
291 if (!ERR_DNS_IS_OK(err
)) goto error
;
293 dns_marshall_domain_name(buf
, key
);
294 dns_marshall_uint16(buf
, DNS_CLASS_ANY
);
295 dns_marshall_uint32(buf
, 0); /* TTL */
296 dns_marshall_domain_name(buf
, algorithm
);
297 dns_marshall_uint16(buf
, 0); /* Time prefix for 48-bit time_t */
298 dns_marshall_uint32(buf
, time_signed
);
299 dns_marshall_uint16(buf
, fudge
);
300 dns_marshall_uint16(buf
, 0); /* error */
301 dns_marshall_uint16(buf
, 0); /* other len */
304 if (!ERR_DNS_IS_OK(buf
->error
)) goto error
;
306 msg
.value
= (void *)buf
->data
;
307 msg
.length
= buf
->offset
;
309 major
= gss_get_mic(&minor
, gss_ctx
, 0, &msg
, &mic
);
311 err
= ERROR_DNS_GSS_ERROR
;
315 if (mic
.length
> 0xffff) {
316 gss_release_buffer(&minor
, &mic
);
317 err
= ERROR_DNS_GSS_ERROR
;
321 err
= dns_create_tsig_record(buf
, keyname
, algorithmname
, time_signed
,
322 fudge
, mic
.length
, (uint8
*)mic
.value
,
324 gss_release_buffer(&minor
, &mic
);
325 if (!ERR_DNS_IS_OK(err
)) goto error
;
327 err
= dns_add_rrec(req
, rec
, &req
->num_additionals
, &req
->additionals
);
334 #endif /* HAVE_GSSAPI_SUPPORT */