s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / lib / addns / dnsgss.c
blob8800ac24c8aea2f68b0ff76b27f130e245ecf515
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 "replace.h"
26 #include <talloc.h>
27 #include "lib/util/talloc_stack.h"
28 #include "lib/util/data_blob.h"
29 #include "lib/util/time.h"
30 #include "lib/util/charset/charset.h"
31 #include "libcli/util/ntstatus.h"
32 #include "auth/gensec/gensec.h"
34 #include "dns.h"
36 static DNS_ERROR dns_negotiate_gss_ctx_int(struct dns_connection *conn,
37 const char *keyname,
38 struct gensec_security *gensec,
39 enum dns_ServerType srv_type)
41 TALLOC_CTX *frame = talloc_stackframe();
42 struct dns_request *req = NULL;
43 struct dns_buffer *buf = NULL;
44 DATA_BLOB in = { .length = 0, };
45 DATA_BLOB out = { .length = 0, };
46 NTSTATUS status;
47 DNS_ERROR err;
49 do {
50 status = gensec_update(gensec, frame, in, &out);
51 data_blob_free(&in);
52 if (GENSEC_UPDATE_IS_NTERROR(status)) {
53 err = ERROR_DNS_GSS_ERROR;
54 goto error;
57 if (out.length != 0) {
58 struct dns_rrec *rec;
60 time_t t = time(NULL);
62 err = dns_create_query(frame, keyname, QTYPE_TKEY,
63 DNS_CLASS_IN, &req);
64 if (!ERR_DNS_IS_OK(err)) goto error;
66 err = dns_create_tkey_record(
67 req, keyname, "gss.microsoft.com", t,
68 t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
69 out.length, out.data,
70 &rec );
71 if (!ERR_DNS_IS_OK(err)) goto error;
73 /* Windows 2000 DNS is broken and requires the
74 TKEY payload in the Answer section instead
75 of the Additional section like Windows 2003 */
77 if ( srv_type == DNS_SRV_WIN2000 ) {
78 err = dns_add_rrec(req, rec, &req->num_answers,
79 &req->answers);
80 } else {
81 err = dns_add_rrec(req, rec, &req->num_additionals,
82 &req->additional);
85 if (!ERR_DNS_IS_OK(err)) goto error;
87 err = dns_marshall_request(frame, req, &buf);
88 if (!ERR_DNS_IS_OK(err)) goto error;
90 err = dns_send(conn, buf);
91 if (!ERR_DNS_IS_OK(err)) goto error;
93 TALLOC_FREE(buf);
94 TALLOC_FREE(req);
96 err = dns_receive(frame, conn, &buf);
97 if (!ERR_DNS_IS_OK(err)) goto error;
100 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
101 struct dns_request *resp;
102 struct dns_tkey_record *tkey;
103 struct dns_rrec *tkey_answer = NULL;
104 uint16_t i;
106 if (buf == NULL) {
107 err = ERROR_DNS_BAD_RESPONSE;
108 goto error;
111 err = dns_unmarshall_request(buf, buf, &resp);
112 if (!ERR_DNS_IS_OK(err)) goto error;
115 * TODO: Compare id and keyname
118 for (i=0; i < resp->num_answers; i++) {
119 if (resp->answers[i]->type != QTYPE_TKEY) {
120 continue;
123 tkey_answer = resp->answers[i];
126 if (tkey_answer == NULL) {
127 err = ERROR_DNS_INVALID_MESSAGE;
128 goto error;
131 err = dns_unmarshall_tkey_record(
132 frame, resp->answers[0], &tkey);
133 if (!ERR_DNS_IS_OK(err)) goto error;
135 in = data_blob_const(tkey->key, tkey->key_length);
137 TALLOC_FREE(buf);
140 } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
142 /* If we arrive here, we have a valid security context */
144 err = ERROR_DNS_SUCCESS;
146 error:
148 TALLOC_FREE(frame);
149 return err;
152 DNS_ERROR dns_negotiate_sec_ctx(const char *servername,
153 const char *keyname,
154 struct gensec_security *gensec,
155 enum dns_ServerType srv_type)
157 TALLOC_CTX *frame = talloc_stackframe();
158 DNS_ERROR err;
159 struct dns_connection *conn = NULL;
161 err = dns_open_connection( servername, DNS_TCP, frame, &conn );
162 if (!ERR_DNS_IS_OK(err)) goto error;
164 err = dns_negotiate_gss_ctx_int(conn, keyname,
165 gensec,
166 srv_type);
167 if (!ERR_DNS_IS_OK(err)) goto error;
169 error:
170 TALLOC_FREE(frame);
172 return err;
175 DNS_ERROR dns_sign_update(struct dns_update_request *req,
176 struct gensec_security *gensec,
177 const char *keyname,
178 const char *algorithmname,
179 time_t time_signed, uint16_t fudge)
181 TALLOC_CTX *frame = talloc_stackframe();
182 struct dns_buffer *buf;
183 DNS_ERROR err;
184 struct dns_domain_name *key, *algorithm;
185 struct dns_rrec *rec;
186 DATA_BLOB mic = { .length = 0, };
187 NTSTATUS status;
189 err = dns_marshall_update_request(frame, req, &buf);
190 if (!ERR_DNS_IS_OK(err)) return err;
192 err = dns_domain_name_from_string(frame, keyname, &key);
193 if (!ERR_DNS_IS_OK(err)) goto error;
195 err = dns_domain_name_from_string(frame, algorithmname, &algorithm);
196 if (!ERR_DNS_IS_OK(err)) goto error;
198 dns_marshall_domain_name(buf, key);
199 dns_marshall_uint16(buf, DNS_CLASS_ANY);
200 dns_marshall_uint32(buf, 0); /* TTL */
201 dns_marshall_domain_name(buf, algorithm);
202 dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
203 dns_marshall_uint32(buf, time_signed);
204 dns_marshall_uint16(buf, fudge);
205 dns_marshall_uint16(buf, 0); /* error */
206 dns_marshall_uint16(buf, 0); /* other len */
208 err = buf->error;
209 if (!ERR_DNS_IS_OK(buf->error)) goto error;
211 status = gensec_sign_packet(gensec,
212 frame,
213 buf->data,
214 buf->offset,
215 buf->data,
216 buf->offset,
217 &mic);
218 if (!NT_STATUS_IS_OK(status)) {
219 err = ERROR_DNS_GSS_ERROR;
220 goto error;
223 if (mic.length > 0xffff) {
224 err = ERROR_DNS_GSS_ERROR;
225 goto error;
228 err = dns_create_tsig_record(frame, keyname, algorithmname, time_signed,
229 fudge, mic.length, mic.data,
230 req->id, 0, &rec);
231 if (!ERR_DNS_IS_OK(err)) goto error;
233 err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
235 error:
236 TALLOC_FREE(frame);
237 return err;