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 "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"
33 :
34 : #include "dns.h"
35 :
36 65 : 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)
40 : {
41 65 : TALLOC_CTX *frame = talloc_stackframe();
42 65 : struct dns_request *req = NULL;
43 65 : struct dns_buffer *buf = NULL;
44 65 : DATA_BLOB in = { .length = 0, };
45 65 : DATA_BLOB out = { .length = 0, };
46 0 : NTSTATUS status;
47 0 : DNS_ERROR err;
48 :
49 0 : do {
50 130 : status = gensec_update(gensec, frame, in, &out);
51 130 : data_blob_free(&in);
52 130 : if (GENSEC_UPDATE_IS_NTERROR(status)) {
53 0 : err = ERROR_DNS_GSS_ERROR;
54 0 : goto error;
55 : }
56 :
57 130 : if (out.length != 0) {
58 0 : struct dns_rrec *rec;
59 :
60 65 : time_t t = time(NULL);
61 :
62 65 : err = dns_create_query(frame, keyname, QTYPE_TKEY,
63 : DNS_CLASS_IN, &req);
64 65 : if (!ERR_DNS_IS_OK(err)) goto error;
65 :
66 65 : err = dns_create_tkey_record(
67 : req, keyname, "gss.microsoft.com", t,
68 : t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
69 65 : out.length, out.data,
70 : &rec );
71 65 : if (!ERR_DNS_IS_OK(err)) goto error;
72 :
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 */
76 :
77 65 : if ( srv_type == DNS_SRV_WIN2000 ) {
78 0 : err = dns_add_rrec(req, rec, &req->num_answers,
79 0 : &req->answers);
80 : } else {
81 65 : err = dns_add_rrec(req, rec, &req->num_additionals,
82 65 : &req->additional);
83 : }
84 :
85 65 : if (!ERR_DNS_IS_OK(err)) goto error;
86 :
87 65 : err = dns_marshall_request(frame, req, &buf);
88 65 : if (!ERR_DNS_IS_OK(err)) goto error;
89 :
90 65 : err = dns_send(conn, buf);
91 65 : if (!ERR_DNS_IS_OK(err)) goto error;
92 :
93 65 : TALLOC_FREE(buf);
94 65 : TALLOC_FREE(req);
95 :
96 65 : err = dns_receive(frame, conn, &buf);
97 65 : if (!ERR_DNS_IS_OK(err)) goto error;
98 : }
99 :
100 130 : if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
101 0 : struct dns_request *resp;
102 0 : struct dns_tkey_record *tkey;
103 65 : struct dns_rrec *tkey_answer = NULL;
104 0 : uint16_t i;
105 :
106 65 : if (buf == NULL) {
107 0 : err = ERROR_DNS_BAD_RESPONSE;
108 0 : goto error;
109 : }
110 :
111 65 : err = dns_unmarshall_request(buf, buf, &resp);
112 65 : if (!ERR_DNS_IS_OK(err)) goto error;
113 :
114 : /*
115 : * TODO: Compare id and keyname
116 : */
117 :
118 130 : for (i=0; i < resp->num_answers; i++) {
119 65 : if (resp->answers[i]->type != QTYPE_TKEY) {
120 0 : continue;
121 : }
122 :
123 65 : tkey_answer = resp->answers[i];
124 : }
125 :
126 65 : if (tkey_answer == NULL) {
127 0 : err = ERROR_DNS_INVALID_MESSAGE;
128 0 : goto error;
129 : }
130 :
131 65 : err = dns_unmarshall_tkey_record(
132 65 : frame, resp->answers[0], &tkey);
133 65 : if (!ERR_DNS_IS_OK(err)) goto error;
134 :
135 65 : in = data_blob_const(tkey->key, tkey->key_length);
136 :
137 65 : TALLOC_FREE(buf);
138 : }
139 :
140 130 : } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
141 :
142 : /* If we arrive here, we have a valid security context */
143 :
144 65 : err = ERROR_DNS_SUCCESS;
145 :
146 65 : error:
147 :
148 65 : TALLOC_FREE(frame);
149 65 : return err;
150 : }
151 :
152 65 : DNS_ERROR dns_negotiate_sec_ctx(const char *servername,
153 : const char *keyname,
154 : struct gensec_security *gensec,
155 : enum dns_ServerType srv_type)
156 : {
157 65 : TALLOC_CTX *frame = talloc_stackframe();
158 0 : DNS_ERROR err;
159 65 : struct dns_connection *conn = NULL;
160 :
161 65 : err = dns_open_connection( servername, DNS_TCP, frame, &conn );
162 65 : if (!ERR_DNS_IS_OK(err)) goto error;
163 :
164 65 : err = dns_negotiate_gss_ctx_int(conn, keyname,
165 : gensec,
166 : srv_type);
167 65 : if (!ERR_DNS_IS_OK(err)) goto error;
168 :
169 65 : error:
170 65 : TALLOC_FREE(frame);
171 :
172 65 : return err;
173 : }
174 :
175 65 : 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)
180 : {
181 65 : TALLOC_CTX *frame = talloc_stackframe();
182 0 : struct dns_buffer *buf;
183 0 : DNS_ERROR err;
184 0 : struct dns_domain_name *key, *algorithm;
185 0 : struct dns_rrec *rec;
186 65 : DATA_BLOB mic = { .length = 0, };
187 0 : NTSTATUS status;
188 :
189 65 : err = dns_marshall_update_request(frame, req, &buf);
190 65 : if (!ERR_DNS_IS_OK(err)) return err;
191 :
192 65 : err = dns_domain_name_from_string(frame, keyname, &key);
193 65 : if (!ERR_DNS_IS_OK(err)) goto error;
194 :
195 65 : err = dns_domain_name_from_string(frame, algorithmname, &algorithm);
196 65 : if (!ERR_DNS_IS_OK(err)) goto error;
197 :
198 65 : dns_marshall_domain_name(buf, key);
199 65 : dns_marshall_uint16(buf, DNS_CLASS_ANY);
200 65 : dns_marshall_uint32(buf, 0); /* TTL */
201 65 : dns_marshall_domain_name(buf, algorithm);
202 65 : dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
203 65 : dns_marshall_uint32(buf, time_signed);
204 65 : dns_marshall_uint16(buf, fudge);
205 65 : dns_marshall_uint16(buf, 0); /* error */
206 65 : dns_marshall_uint16(buf, 0); /* other len */
207 :
208 65 : err = buf->error;
209 65 : if (!ERR_DNS_IS_OK(buf->error)) goto error;
210 :
211 65 : status = gensec_sign_packet(gensec,
212 : frame,
213 65 : buf->data,
214 65 : buf->offset,
215 65 : buf->data,
216 65 : buf->offset,
217 : &mic);
218 65 : if (!NT_STATUS_IS_OK(status)) {
219 0 : err = ERROR_DNS_GSS_ERROR;
220 0 : goto error;
221 : }
222 :
223 65 : if (mic.length > 0xffff) {
224 0 : err = ERROR_DNS_GSS_ERROR;
225 0 : goto error;
226 : }
227 :
228 65 : err = dns_create_tsig_record(frame, keyname, algorithmname, time_signed,
229 65 : fudge, mic.length, mic.data,
230 65 : req->id, 0, &rec);
231 65 : if (!ERR_DNS_IS_OK(err)) goto error;
232 :
233 65 : err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
234 :
235 65 : error:
236 65 : TALLOC_FREE(frame);
237 65 : return err;
238 : }
|