Coverage Report

Created: 2025-07-23 07:04

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