s3-lsa: Fix policy handle memleak and handle type check in _lsa_DeleteObject().
[ira/wip.git] / source3 / libaddns / dnsgss.c
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
34 static 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
50 static 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
73 void 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
80 static 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
206 DNS_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
269 DNS_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 */