LCOV - code coverage report
Current view: top level - lib/addns - dnsgss.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 92 118 78.0 %
Date: 2024-05-31 13:13:24 Functions: 3 3 100.0 %

          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             : }

Generated by: LCOV version 1.14