LCOV - code coverage report
Current view: top level - source4/dns_server - dlz_bind9.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 603 1025 58.8 %
Date: 2021-09-23 10:06:22 Functions: 34 39 87.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    bind9 dlz driver for Samba
       5             : 
       6             :    Copyright (C) 2010 Andrew Tridgell
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "talloc.h"
      24             : #include "param/param.h"
      25             : #include "lib/events/events.h"
      26             : #include "dsdb/samdb/samdb.h"
      27             : #include "dsdb/common/util.h"
      28             : #include "auth/auth.h"
      29             : #include "auth/session.h"
      30             : #include "auth/gensec/gensec.h"
      31             : #include "librpc/gen_ndr/security.h"
      32             : #include "auth/credentials/credentials.h"
      33             : #include "system/kerberos.h"
      34             : #include "auth/kerberos/kerberos.h"
      35             : #include "gen_ndr/ndr_dnsp.h"
      36             : #include "gen_ndr/server_id.h"
      37             : #include "messaging/messaging.h"
      38             : #include <popt.h>
      39             : #include "lib/util/dlinklist.h"
      40             : #include "dlz_minimal.h"
      41             : #include "dnsserver_common.h"
      42             : #include "lib/util/smb_strtox.h"
      43             : #include "lib/util/access.h"
      44             : 
      45             : #undef strcasecmp
      46             : 
      47             : struct b9_options {
      48             :         const char *url;
      49             :         const char *debug;
      50             : };
      51             : 
      52             : struct b9_zone {
      53             :         char *name;
      54             :         struct b9_zone *prev, *next;
      55             : };
      56             : 
      57             : struct dlz_bind9_data {
      58             :         struct b9_options options;
      59             :         struct ldb_context *samdb;
      60             :         struct tevent_context *ev_ctx;
      61             :         struct loadparm_context *lp;
      62             :         int *transaction_token;
      63             :         uint32_t soa_serial;
      64             :         struct b9_zone *zonelist;
      65             : 
      66             :         /* Used for dynamic update */
      67             :         struct smb_krb5_context *smb_krb5_ctx;
      68             :         struct auth4_context *auth_context;
      69             :         struct auth_session_info *session_info;
      70             :         char *update_name;
      71             : 
      72             :         /* helper functions from the dlz_dlopen driver */
      73             :         log_t *log;
      74             :         dns_sdlz_putrr_t *putrr;
      75             :         dns_sdlz_putnamedrr_t *putnamedrr;
      76             :         dns_dlz_writeablezone_t *writeable_zone;
      77             : };
      78             : 
      79             : static struct dlz_bind9_data *dlz_bind9_state = NULL;
      80             : static int dlz_bind9_state_ref_count = 0;
      81             : 
      82             : static const char *zone_prefixes[] = {
      83             :         "CN=MicrosoftDNS,DC=DomainDnsZones",
      84             :         "CN=MicrosoftDNS,DC=ForestDnsZones",
      85             :         "CN=MicrosoftDNS,CN=System",
      86             :         NULL
      87             : };
      88             : 
      89             : /*
      90             :  * Get a printable string representation of an isc_result_t
      91             :  */
      92           0 : static const char *isc_result_str( const isc_result_t result) {
      93           0 :         switch (result) {
      94           0 :         case ISC_R_SUCCESS:
      95           0 :                 return "ISC_R_SUCCESS";
      96           0 :         case ISC_R_NOMEMORY:
      97           0 :                 return "ISC_R_NOMEMORY";
      98           0 :         case ISC_R_NOPERM:
      99           0 :                 return "ISC_R_NOPERM";
     100           0 :         case ISC_R_NOSPACE:
     101           0 :                 return "ISC_R_NOSPACE";
     102           0 :         case ISC_R_NOTFOUND:
     103           0 :                 return "ISC_R_NOTFOUND";
     104           0 :         case ISC_R_FAILURE:
     105           0 :                 return "ISC_R_FAILURE";
     106           0 :         case ISC_R_NOTIMPLEMENTED:
     107           0 :                 return "ISC_R_NOTIMPLEMENTED";
     108           0 :         case ISC_R_NOMORE:
     109           0 :                 return "ISC_R_NOMORE";
     110           0 :         case ISC_R_INVALIDFILE:
     111           0 :                 return "ISC_R_INVALIDFILE";
     112           0 :         case ISC_R_UNEXPECTED:
     113           0 :                 return "ISC_R_UNEXPECTED";
     114           0 :         case ISC_R_FILENOTFOUND:
     115           0 :                 return "ISC_R_FILENOTFOUND";
     116           0 :         default:
     117           0 :                 return "UNKNOWN";
     118             :         }
     119             : }
     120             : 
     121             : /*
     122             :   return the version of the API
     123             :  */
     124           1 : _PUBLIC_ int dlz_version(unsigned int *flags)
     125             : {
     126           1 :         return DLZ_DLOPEN_VERSION;
     127             : }
     128             : 
     129             : /*
     130             :    remember a helper function from the bind9 dlz_dlopen driver
     131             :  */
     132          35 : static void b9_add_helper(struct dlz_bind9_data *state, const char *helper_name, void *ptr)
     133             : {
     134          35 :         if (strcmp(helper_name, "log") == 0) {
     135          14 :                 state->log = ptr;
     136             :         }
     137          35 :         if (strcmp(helper_name, "putrr") == 0) {
     138           4 :                 state->putrr = ptr;
     139             :         }
     140          35 :         if (strcmp(helper_name, "putnamedrr") == 0) {
     141           4 :                 state->putnamedrr = ptr;
     142             :         }
     143          35 :         if (strcmp(helper_name, "writeable_zone") == 0) {
     144          13 :                 state->writeable_zone = ptr;
     145             :         }
     146          35 : }
     147             : 
     148             : /*
     149             :  * Add a trailing '.' if it's missing
     150             :  */
     151          36 : static const char *b9_format_fqdn(TALLOC_CTX *mem_ctx, const char *str)
     152             : {
     153             :         size_t len;
     154             :         const char *tmp;
     155             : 
     156          36 :         if (str == NULL || str[0] == '\0') {
     157           0 :                 return str;
     158             :         }
     159             : 
     160          36 :         len = strlen(str);
     161          36 :         if (str[len-1] != '.') {
     162          36 :                 tmp = talloc_asprintf(mem_ctx, "%s.", str);
     163             :         } else {
     164           0 :                 tmp = str;
     165             :         }
     166          36 :         return tmp;
     167             : }
     168             : 
     169             : /*
     170             :   format a record for bind9
     171             :  */
     172          43 : static bool b9_format(struct dlz_bind9_data *state,
     173             :                       TALLOC_CTX *mem_ctx,
     174             :                       struct dnsp_DnssrvRpcRecord *rec,
     175             :                       const char **type, const char **data)
     176             : {
     177             :         uint32_t i;
     178             :         char *tmp;
     179             :         const char *fqdn;
     180             : 
     181          43 :         switch (rec->wType) {
     182          19 :         case DNS_TYPE_A:
     183          19 :                 *type = "a";
     184          19 :                 *data = rec->data.ipv4;
     185          19 :                 break;
     186             : 
     187           6 :         case DNS_TYPE_AAAA:
     188           6 :                 *type = "aaaa";
     189           6 :                 *data = rec->data.ipv6;
     190           6 :                 break;
     191             : 
     192           0 :         case DNS_TYPE_CNAME:
     193           0 :                 *type = "cname";
     194           0 :                 *data = b9_format_fqdn(mem_ctx, rec->data.cname);
     195           0 :                 break;
     196             : 
     197           0 :         case DNS_TYPE_TXT:
     198           0 :                 *type = "txt";
     199           0 :                 tmp = talloc_asprintf(mem_ctx, "\"%s\"", rec->data.txt.str[0]);
     200           0 :                 for (i=1; i<rec->data.txt.count; i++) {
     201           0 :                         tmp = talloc_asprintf_append(tmp, " \"%s\"", rec->data.txt.str[i]);
     202             :                 }
     203           0 :                 *data = tmp;
     204           0 :                 break;
     205             : 
     206           0 :         case DNS_TYPE_PTR:
     207           0 :                 *type = "ptr";
     208           0 :                 *data = b9_format_fqdn(mem_ctx, rec->data.ptr);
     209           0 :                 break;
     210             : 
     211          13 :         case DNS_TYPE_SRV:
     212          13 :                 *type = "srv";
     213          13 :                 fqdn = b9_format_fqdn(mem_ctx, rec->data.srv.nameTarget);
     214          13 :                 if (fqdn == NULL) {
     215           0 :                         return false;
     216             :                 }
     217          39 :                 *data = talloc_asprintf(mem_ctx, "%u %u %u %s",
     218          13 :                                         rec->data.srv.wPriority,
     219          13 :                                         rec->data.srv.wWeight,
     220          13 :                                         rec->data.srv.wPort,
     221             :                                         fqdn);
     222          13 :                 break;
     223             : 
     224           0 :         case DNS_TYPE_MX:
     225           0 :                 *type = "mx";
     226           0 :                 fqdn = b9_format_fqdn(mem_ctx, rec->data.mx.nameTarget);
     227           0 :                 if (fqdn == NULL) {
     228           0 :                         return false;
     229             :                 }
     230           0 :                 *data = talloc_asprintf(mem_ctx, "%u %s",
     231           0 :                                         rec->data.mx.wPriority, fqdn);
     232           0 :                 break;
     233             : 
     234           3 :         case DNS_TYPE_NS:
     235           3 :                 *type = "ns";
     236           3 :                 *data = b9_format_fqdn(mem_ctx, rec->data.ns);
     237           3 :                 break;
     238             : 
     239           2 :         case DNS_TYPE_SOA: {
     240             :                 const char *mname;
     241           2 :                 *type = "soa";
     242             : 
     243             :                 /* we need to fake the authoritative nameserver to
     244             :                  * point at ourselves. This is how AD DNS servers
     245             :                  * force clients to send updates to the right local DC
     246             :                  */
     247           2 :                 mname = talloc_asprintf(mem_ctx, "%s.%s.",
     248             :                                         lpcfg_netbios_name(state->lp),
     249             :                                         lpcfg_dnsdomain(state->lp));
     250           2 :                 if (mname == NULL) {
     251           0 :                         return false;
     252             :                 }
     253           2 :                 mname = strlower_talloc(mem_ctx, mname);
     254           2 :                 if (mname == NULL) {
     255           0 :                         return false;
     256             :                 }
     257             : 
     258           2 :                 fqdn = b9_format_fqdn(mem_ctx, rec->data.soa.rname);
     259           2 :                 if (fqdn == NULL) {
     260           0 :                         return false;
     261             :                 }
     262             : 
     263           2 :                 state->soa_serial = rec->data.soa.serial;
     264             : 
     265           2 :                 *data = talloc_asprintf(mem_ctx, "%s %s %u %u %u %u %u",
     266             :                                         mname, fqdn,
     267             :                                         rec->data.soa.serial,
     268             :                                         rec->data.soa.refresh,
     269             :                                         rec->data.soa.retry,
     270             :                                         rec->data.soa.expire,
     271             :                                         rec->data.soa.minimum);
     272           2 :                 break;
     273             :         }
     274             : 
     275           0 :         default:
     276           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz b9_format: unhandled record type %u",
     277           0 :                            rec->wType);
     278           0 :                 return false;
     279             :         }
     280             : 
     281          43 :         return true;
     282             : }
     283             : 
     284             : static const struct {
     285             :         enum dns_record_type dns_type;
     286             :         const char *typestr;
     287             :         bool single_valued;
     288             : } dns_typemap[] = {
     289             :         { DNS_TYPE_A,     "A"     , false},
     290             :         { DNS_TYPE_AAAA,  "AAAA"  , false},
     291             :         { DNS_TYPE_CNAME, "CNAME" , true},
     292             :         { DNS_TYPE_TXT,   "TXT"   , false},
     293             :         { DNS_TYPE_PTR,   "PTR"   , false},
     294             :         { DNS_TYPE_SRV,   "SRV"   , false},
     295             :         { DNS_TYPE_MX,    "MX"    , false},
     296             :         { DNS_TYPE_NS,    "NS"    , false},
     297             :         { DNS_TYPE_SOA,   "SOA"   , true},
     298             : };
     299             : 
     300             : 
     301             : /*
     302             :   see if a DNS type is single valued
     303             :  */
     304           7 : static bool b9_single_valued(enum dns_record_type dns_type)
     305             : {
     306             :         int i;
     307           7 :         for (i=0; i<ARRAY_SIZE(dns_typemap); i++) {
     308           7 :                 if (dns_typemap[i].dns_type == dns_type) {
     309           7 :                         return dns_typemap[i].single_valued;
     310             :                 }
     311             :         }
     312           0 :         return false;
     313             : }
     314             : 
     315             : /*
     316             :   get a DNS_TYPE_* value from the corresponding string
     317             :  */
     318           3 : static bool b9_dns_type(const char *type, enum dns_record_type *dtype)
     319             : {
     320             :         int i;
     321           6 :         for (i=0; i<ARRAY_SIZE(dns_typemap); i++) {
     322           6 :                 if (strcasecmp(dns_typemap[i].typestr, type) == 0) {
     323           3 :                         *dtype = dns_typemap[i].dns_type;
     324           3 :                         return true;
     325             :                 }
     326             :         }
     327           0 :         return false;
     328             : }
     329             : 
     330             : 
     331             : #define DNS_PARSE_STR(ret, str, sep, saveptr) do {      \
     332             :         (ret) = strtok_r(str, sep, &saveptr); \
     333             :         if ((ret) == NULL) return false; \
     334             :         } while (0)
     335             : 
     336             : #define DNS_PARSE_UINT(ret, str, sep, saveptr) do {  \
     337             :         char *istr = strtok_r(str, sep, &saveptr); \
     338             :         int error = 0;\
     339             :         if ((istr) == NULL) return false; \
     340             :         (ret) = smb_strtoul(istr, NULL, 10, &error, SMB_STR_STANDARD); \
     341             :         if (error != 0) {\
     342             :                 return false;\
     343             :         }\
     344             :         } while (0)
     345             : 
     346             : /*
     347             :   parse a record from bind9
     348             :  */
     349           9 : static bool b9_parse(struct dlz_bind9_data *state,
     350             :                      const char *rdatastr,
     351             :                      struct dnsp_DnssrvRpcRecord *rec)
     352             : {
     353             :         char *full_name, *dclass, *type;
     354           9 :         char *str, *tmp, *saveptr=NULL;
     355             :         int i;
     356             : 
     357           9 :         str = talloc_strdup(rec, rdatastr);
     358           9 :         if (str == NULL) {
     359           0 :                 return false;
     360             :         }
     361             : 
     362             :         /* parse the SDLZ string form */
     363           9 :         DNS_PARSE_STR(full_name, str, "\t", saveptr);
     364           9 :         DNS_PARSE_UINT(rec->dwTtlSeconds, NULL, "\t", saveptr);
     365           9 :         DNS_PARSE_STR(dclass, NULL, "\t", saveptr);
     366           9 :         DNS_PARSE_STR(type, NULL, "\t", saveptr);
     367             : 
     368             :         /* construct the record */
     369           9 :         for (i=0; i<ARRAY_SIZE(dns_typemap); i++) {
     370           9 :                 if (strcasecmp(type, dns_typemap[i].typestr) == 0) {
     371           9 :                         rec->wType = dns_typemap[i].dns_type;
     372           9 :                         break;
     373             :                 }
     374             :         }
     375           9 :         if (i == ARRAY_SIZE(dns_typemap)) {
     376           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: unsupported record type '%s' for '%s'",
     377             :                            type, full_name);
     378           0 :                 return false;
     379             :         }
     380             : 
     381           9 :         switch (rec->wType) {
     382           9 :         case DNS_TYPE_A:
     383           9 :                 DNS_PARSE_STR(rec->data.ipv4, NULL, " ", saveptr);
     384           9 :                 break;
     385             : 
     386           0 :         case DNS_TYPE_AAAA:
     387           0 :                 DNS_PARSE_STR(rec->data.ipv6, NULL, " ", saveptr);
     388           0 :                 break;
     389             : 
     390           0 :         case DNS_TYPE_CNAME:
     391           0 :                 DNS_PARSE_STR(rec->data.cname, NULL, " ", saveptr);
     392           0 :                 break;
     393             : 
     394           0 :         case DNS_TYPE_TXT:
     395           0 :                 rec->data.txt.count = 0;
     396           0 :                 rec->data.txt.str = talloc_array(rec, const char *, rec->data.txt.count);
     397           0 :                 tmp = strtok_r(NULL, "\t", &saveptr);
     398           0 :                 while (tmp) {
     399           0 :                         rec->data.txt.str = talloc_realloc(rec, rec->data.txt.str, const char *,
     400             :                                                         rec->data.txt.count+1);
     401           0 :                         if (tmp[0] == '"') {
     402             :                                 /* Strip quotes */
     403           0 :                                 rec->data.txt.str[rec->data.txt.count] = talloc_strndup(rec, &tmp[1], strlen(tmp)-2);
     404             :                         } else {
     405           0 :                                 rec->data.txt.str[rec->data.txt.count] = talloc_strdup(rec, tmp);
     406             :                         }
     407           0 :                         rec->data.txt.count++;
     408           0 :                         tmp = strtok_r(NULL, " ", &saveptr);
     409             :                 }
     410           0 :                 break;
     411             : 
     412           0 :         case DNS_TYPE_PTR:
     413           0 :                 DNS_PARSE_STR(rec->data.ptr, NULL, " ", saveptr);
     414           0 :                 break;
     415             : 
     416           0 :         case DNS_TYPE_SRV:
     417           0 :                 DNS_PARSE_UINT(rec->data.srv.wPriority, NULL, " ", saveptr);
     418           0 :                 DNS_PARSE_UINT(rec->data.srv.wWeight, NULL, " ", saveptr);
     419           0 :                 DNS_PARSE_UINT(rec->data.srv.wPort, NULL, " ", saveptr);
     420           0 :                 DNS_PARSE_STR(rec->data.srv.nameTarget, NULL, " ", saveptr);
     421           0 :                 break;
     422             : 
     423           0 :         case DNS_TYPE_MX:
     424           0 :                 DNS_PARSE_UINT(rec->data.mx.wPriority, NULL, " ", saveptr);
     425           0 :                 DNS_PARSE_STR(rec->data.mx.nameTarget, NULL, " ", saveptr);
     426           0 :                 break;
     427             : 
     428           0 :         case DNS_TYPE_NS:
     429           0 :                 DNS_PARSE_STR(rec->data.ns, NULL, " ", saveptr);
     430           0 :                 break;
     431             : 
     432           0 :         case DNS_TYPE_SOA:
     433           0 :                 DNS_PARSE_STR(rec->data.soa.mname, NULL, " ", saveptr);
     434           0 :                 DNS_PARSE_STR(rec->data.soa.rname, NULL, " ", saveptr);
     435           0 :                 DNS_PARSE_UINT(rec->data.soa.serial, NULL, " ", saveptr);
     436           0 :                 DNS_PARSE_UINT(rec->data.soa.refresh, NULL, " ", saveptr);
     437           0 :                 DNS_PARSE_UINT(rec->data.soa.retry, NULL, " ", saveptr);
     438           0 :                 DNS_PARSE_UINT(rec->data.soa.expire, NULL, " ", saveptr);
     439           0 :                 DNS_PARSE_UINT(rec->data.soa.minimum, NULL, " ", saveptr);
     440           0 :                 break;
     441             : 
     442           0 :         default:
     443           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz b9_parse: unhandled record type %u",
     444           0 :                            rec->wType);
     445           0 :                 return false;
     446             :         }
     447             : 
     448             :         /* we should be at the end of the buffer now */
     449           9 :         if (strtok_r(NULL, "\t ", &saveptr) != NULL) {
     450           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz b9_parse: unexpected data at end of string for '%s'",
     451             :                            rdatastr);
     452           0 :                 return false;
     453             :         }
     454             : 
     455           9 :         return true;
     456             : }
     457             : 
     458             : /*
     459             :   send a resource record to bind9
     460             :  */
     461          19 : static isc_result_t b9_putrr(struct dlz_bind9_data *state,
     462             :                              void *handle, struct dnsp_DnssrvRpcRecord *rec,
     463             :                              const char **types)
     464             : {
     465             :         isc_result_t result;
     466             :         const char *type, *data;
     467          19 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
     468             : 
     469          19 :         if (!b9_format(state, tmp_ctx, rec, &type, &data)) {
     470           0 :                 return ISC_R_FAILURE;
     471             :         }
     472             : 
     473          19 :         if (data == NULL) {
     474           0 :                 talloc_free(tmp_ctx);
     475           0 :                 return ISC_R_NOMEMORY;
     476             :         }
     477             : 
     478          19 :         if (types) {
     479             :                 int i;
     480           0 :                 for (i=0; types[i]; i++) {
     481           0 :                         if (strcmp(types[i], type) == 0) break;
     482             :                 }
     483           0 :                 if (types[i] == NULL) {
     484             :                         /* skip it */
     485           0 :                         return ISC_R_SUCCESS;
     486             :                 }
     487             :         }
     488             : 
     489          19 :         result = state->putrr(handle, type, rec->dwTtlSeconds, data);
     490          19 :         if (result != ISC_R_SUCCESS) {
     491           0 :                 state->log(ISC_LOG_ERROR, "Failed to put rr");
     492             :         }
     493          19 :         talloc_free(tmp_ctx);
     494          19 :         return result;
     495             : }
     496             : 
     497             : 
     498             : /*
     499             :   send a named resource record to bind9
     500             :  */
     501          24 : static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state,
     502             :                                   void *handle, const char *name,
     503             :                                   struct dnsp_DnssrvRpcRecord *rec)
     504             : {
     505             :         isc_result_t result;
     506             :         const char *type, *data;
     507          24 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
     508             : 
     509          24 :         if (!b9_format(state, tmp_ctx, rec, &type, &data)) {
     510           0 :                 return ISC_R_FAILURE;
     511             :         }
     512             : 
     513          24 :         if (data == NULL) {
     514           0 :                 talloc_free(tmp_ctx);
     515           0 :                 return ISC_R_NOMEMORY;
     516             :         }
     517             : 
     518          24 :         result = state->putnamedrr(handle, name, type, rec->dwTtlSeconds, data);
     519          24 :         if (result != ISC_R_SUCCESS) {
     520           0 :                 state->log(ISC_LOG_ERROR, "Failed to put named rr '%s'", name);
     521             :         }
     522          24 :         talloc_free(tmp_ctx);
     523          24 :         return result;
     524             : }
     525             : 
     526             : /*
     527             :    parse options
     528             :  */
     529          14 : static isc_result_t parse_options(struct dlz_bind9_data *state,
     530             :                                   unsigned int argc, const char **argv,
     531             :                                   struct b9_options *options)
     532             : {
     533             :         int opt;
     534             :         poptContext pc;
     535          42 :         struct poptOption long_options[] = {
     536          14 :                 { "url", 'H', POPT_ARG_STRING, &options->url, 0, "database URL", "URL" },
     537          14 :                 { "debug", 'd', POPT_ARG_STRING, &options->debug, 0, "debug level", "DEBUG" },
     538             :                 {0}
     539             :         };
     540             : 
     541          14 :         pc = poptGetContext("dlz_bind9", argc, argv, long_options,
     542             :                         POPT_CONTEXT_KEEP_FIRST);
     543          14 :         while ((opt = poptGetNextOpt(pc)) != -1) {
     544             :                 switch (opt) {
     545           0 :                 default:
     546           0 :                         state->log(ISC_LOG_ERROR, "dlz_bind9: Invalid option %s: %s",
     547             :                                    poptBadOption(pc, 0), poptStrerror(opt));
     548           0 :                         poptFreeContext(pc);
     549           0 :                         return ISC_R_FAILURE;
     550             :                 }
     551             :         }
     552             : 
     553          14 :         poptFreeContext(pc);
     554          14 :         return ISC_R_SUCCESS;
     555             : }
     556             : 
     557             : 
     558             : /*
     559             :  * Create session info from PAC
     560             :  * This is called as auth_context->generate_session_info_pac()
     561             :  */
     562           3 : static NTSTATUS b9_generate_session_info_pac(struct auth4_context *auth_context,
     563             :                                              TALLOC_CTX *mem_ctx,
     564             :                                              struct smb_krb5_context *smb_krb5_context,
     565             :                                              DATA_BLOB *pac_blob,
     566             :                                              const char *principal_name,
     567             :                                              const struct tsocket_address *remote_addr,
     568             :                                              uint32_t session_info_flags,
     569             :                                              struct auth_session_info **session_info)
     570             : {
     571             :         NTSTATUS status;
     572             :         struct auth_user_info_dc *user_info_dc;
     573             :         TALLOC_CTX *tmp_ctx;
     574             : 
     575           3 :         tmp_ctx = talloc_new(mem_ctx);
     576           3 :         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
     577             : 
     578           3 :         status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
     579             :                                                    *pac_blob,
     580             :                                                    smb_krb5_context->krb5_context,
     581             :                                                    &user_info_dc,
     582             :                                                    NULL,
     583             :                                                    NULL);
     584           3 :         if (!NT_STATUS_IS_OK(status)) {
     585           0 :                 talloc_free(tmp_ctx);
     586           0 :                 return status;
     587             :         }
     588             : 
     589           3 :         if (user_info_dc->info->authenticated) {
     590           3 :                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
     591             :         }
     592             : 
     593           3 :         session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
     594             : 
     595           3 :         status = auth_generate_session_info(mem_ctx, NULL, NULL, user_info_dc,
     596             :                                             session_info_flags, session_info);
     597           3 :         if (!NT_STATUS_IS_OK(status)) {
     598           0 :                 talloc_free(tmp_ctx);
     599           0 :                 return status;
     600             :         }
     601             : 
     602           3 :         talloc_free(tmp_ctx);
     603           3 :         return status;
     604             : }
     605             : 
     606             : /* Callback for the DEBUG() system, to catch the remaining messages */
     607           2 : static void b9_debug(void *private_ptr, int msg_level, const char *msg)
     608             : {
     609             :         static const int isc_log_map[] = {
     610             :                 ISC_LOG_CRITICAL, /* 0 */
     611             :                 ISC_LOG_ERROR,    /* 1 */
     612             :                 ISC_LOG_WARNING,   /* 2 */
     613             :                 ISC_LOG_NOTICE    /* 3 */
     614             :         };
     615           2 :         struct dlz_bind9_data *state = private_ptr;
     616             :         int     isc_log_level;
     617             :         
     618           2 :         if (msg_level >= ARRAY_SIZE(isc_log_map) || msg_level < 0) {
     619           0 :                 isc_log_level = ISC_LOG_INFO;
     620             :         } else {
     621           2 :                 isc_log_level = isc_log_map[msg_level];
     622             :         }
     623           2 :         state->log(isc_log_level, "samba_dlz: %s", msg);
     624           2 : }
     625             : 
     626          14 : static int dlz_state_debug_unregister(struct dlz_bind9_data *state)
     627             : {
     628             :         /* Stop logging (to the bind9 logs) */
     629          14 :         debug_set_callback(NULL, NULL);
     630          14 :         return 0;
     631             : }
     632             : 
     633             : /*
     634             :   called to initialise the driver
     635             :  */
     636          20 : _PUBLIC_ isc_result_t dlz_create(const char *dlzname,
     637             :                                  unsigned int argc, const char **argv,
     638             :                                  void **dbdata, ...)
     639             : {
     640             :         struct dlz_bind9_data *state;
     641             :         const char *helper_name;
     642             :         va_list ap;
     643             :         isc_result_t result;
     644             :         struct ldb_dn *dn;
     645             :         NTSTATUS nt_status;
     646             :         int ret;
     647          20 :         char *errstring = NULL;
     648             : 
     649          20 :         if (dlz_bind9_state != NULL) {
     650           6 :                 dlz_bind9_state->log(ISC_LOG_ERROR,
     651             :                                      "samba_dlz: dlz_create ignored, #refs=%d",
     652             :                                      dlz_bind9_state_ref_count);
     653           6 :                 *dbdata = dlz_bind9_state;
     654           6 :                 dlz_bind9_state_ref_count++;
     655           6 :                 return ISC_R_SUCCESS;
     656             :         }
     657             : 
     658          14 :         state = talloc_zero(NULL, struct dlz_bind9_data);
     659          14 :         if (state == NULL) {
     660           0 :                 return ISC_R_NOMEMORY;
     661             :         }
     662             : 
     663          14 :         talloc_set_destructor(state, dlz_state_debug_unregister);
     664             : 
     665             :         /* fill in the helper functions */
     666          14 :         va_start(ap, dbdata);
     667          63 :         while ((helper_name = va_arg(ap, const char *)) != NULL) {
     668          35 :                 b9_add_helper(state, helper_name, va_arg(ap, void*));
     669             :         }
     670          14 :         va_end(ap);
     671             : 
     672             :         /* Do not install samba signal handlers */
     673          14 :         fault_setup_disable();
     674             : 
     675             :         /* Start logging (to the bind9 logs) */
     676          14 :         debug_set_callback(state, b9_debug);
     677             : 
     678          14 :         state->ev_ctx = s4_event_context_init(state);
     679          14 :         if (state->ev_ctx == NULL) {
     680           0 :                 result = ISC_R_NOMEMORY;
     681           0 :                 goto failed;
     682             :         }
     683             : 
     684          14 :         result = parse_options(state, argc, argv, &state->options);
     685          14 :         if (result != ISC_R_SUCCESS) {
     686           0 :                 goto failed;
     687             :         }
     688             : 
     689          14 :         state->lp = loadparm_init_global(true);
     690          14 :         if (state->lp == NULL) {
     691           0 :                 result = ISC_R_NOMEMORY;
     692           0 :                 goto failed;
     693             :         }
     694             : 
     695          14 :         if (state->options.debug) {
     696           0 :                 lpcfg_do_global_parameter(state->lp, "log level", state->options.debug);
     697             :         } else {
     698          14 :                 lpcfg_do_global_parameter(state->lp, "log level", "0");
     699             :         }
     700             : 
     701          14 :         if (smb_krb5_init_context(state, state->lp, &state->smb_krb5_ctx) != 0) {
     702           0 :                 result = ISC_R_NOMEMORY;
     703           0 :                 goto failed;
     704             :         }
     705             : 
     706          14 :         nt_status = gensec_init();
     707          14 :         if (!NT_STATUS_IS_OK(nt_status)) {
     708           0 :                 result = ISC_R_NOMEMORY;
     709           0 :                 goto failed;
     710             :         }
     711             : 
     712          14 :         state->auth_context = talloc_zero(state, struct auth4_context);
     713          14 :         if (state->auth_context == NULL) {
     714           0 :                 result = ISC_R_NOMEMORY;
     715           0 :                 goto failed;
     716             :         }
     717             : 
     718          14 :         if (state->options.url == NULL) {
     719           0 :                 state->options.url = talloc_asprintf(state,
     720             :                                                      "%s/dns/sam.ldb",
     721             :                                                      lpcfg_binddns_dir(state->lp));
     722           0 :                 if (state->options.url == NULL) {
     723           0 :                         result = ISC_R_NOMEMORY;
     724           0 :                         goto failed;
     725             :                 }
     726             : 
     727           0 :                 if (!file_exist(state->options.url)) {
     728           0 :                         state->options.url = talloc_asprintf(state,
     729             :                                                              "%s/dns/sam.ldb",
     730             :                                                              lpcfg_private_dir(state->lp));
     731           0 :                         if (state->options.url == NULL) {
     732           0 :                                 result = ISC_R_NOMEMORY;
     733           0 :                                 goto failed;
     734             :                         }
     735             :                 }
     736             :         }
     737             : 
     738          14 :         ret = samdb_connect_url(state,
     739             :                                 state->ev_ctx,
     740             :                                 state->lp,
     741             :                                 system_session(state->lp),
     742             :                                 0,
     743             :                                 state->options.url,
     744             :                                 NULL,
     745             :                                 &state->samdb,
     746             :                                 &errstring);
     747          14 :         if (ret != LDB_SUCCESS) {
     748           0 :                 state->log(ISC_LOG_ERROR,
     749             :                            "samba_dlz: Failed to connect to %s: %s",
     750             :                            errstring, ldb_strerror(ret));
     751           0 :                 result = ISC_R_FAILURE;
     752           0 :                 goto failed;
     753             :         }
     754             : 
     755          14 :         dn = ldb_get_default_basedn(state->samdb);
     756          14 :         if (dn == NULL) {
     757           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: Unable to get basedn for %s - %s",
     758             :                            state->options.url, ldb_errstring(state->samdb));
     759           0 :                 result = ISC_R_FAILURE;
     760           0 :                 goto failed;
     761             :         }
     762             : 
     763          14 :         state->log(ISC_LOG_INFO, "samba_dlz: started for DN %s",
     764             :                    ldb_dn_get_linearized(dn));
     765             : 
     766          14 :         state->auth_context->event_ctx = state->ev_ctx;
     767          14 :         state->auth_context->lp_ctx = state->lp;
     768          14 :         state->auth_context->sam_ctx = state->samdb;
     769          14 :         state->auth_context->generate_session_info_pac = b9_generate_session_info_pac;
     770             : 
     771          14 :         *dbdata = state;
     772          14 :         dlz_bind9_state = state;
     773          14 :         dlz_bind9_state_ref_count++;
     774             : 
     775          14 :         return ISC_R_SUCCESS;
     776             : 
     777           0 : failed:
     778           0 :         state->log(ISC_LOG_INFO,
     779             :                    "samba_dlz: FAILED dlz_create call result=%d #refs=%d",
     780             :                    result,
     781             :                    dlz_bind9_state_ref_count);
     782           0 :         talloc_free(state);
     783           0 :         return result;
     784             : }
     785             : 
     786             : /*
     787             :   shutdown the backend
     788             :  */
     789          20 : _PUBLIC_ void dlz_destroy(void *dbdata)
     790             : {
     791          20 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
     792             : 
     793          20 :         dlz_bind9_state_ref_count--;
     794          20 :         if (dlz_bind9_state_ref_count == 0) {
     795          14 :                 state->log(ISC_LOG_INFO, "samba_dlz: shutting down");
     796          14 :                 talloc_unlink(state, state->samdb);
     797          14 :                 talloc_free(state);
     798          14 :                 dlz_bind9_state = NULL;
     799             :         } else {
     800           6 :                 state->log(ISC_LOG_INFO,
     801             :                            "samba_dlz: dlz_destroy called. %d refs remaining.",
     802             :                            dlz_bind9_state_ref_count);
     803             :         }
     804          20 : }
     805             : 
     806             : 
     807             : /*
     808             :   return the base DN for a zone
     809             :  */
     810          34 : static isc_result_t b9_find_zone_dn(struct dlz_bind9_data *state, const char *zone_name,
     811             :                                     TALLOC_CTX *mem_ctx, struct ldb_dn **zone_dn)
     812             : {
     813             :         int ret;
     814          34 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
     815          34 :         const char *attrs[] = { NULL };
     816             :         int i;
     817             : 
     818         146 :         for (i=0; zone_prefixes[i]; i++) {
     819             :                 const char *casefold;
     820             :                 struct ldb_dn *dn;
     821             :                 struct ldb_result *res;
     822          60 :                 struct ldb_val zone_name_val
     823           0 :                         = data_blob_string_const(zone_name);
     824             : 
     825          60 :                 dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
     826          60 :                 if (dn == NULL) {
     827           0 :                         talloc_free(tmp_ctx);
     828          21 :                         return ISC_R_NOMEMORY;
     829             :                 }
     830             : 
     831             :                 /*
     832             :                  * This dance ensures that it is not possible to put
     833             :                  * (eg) an extra DC=x, into the DNS name being
     834             :                  * queried
     835             :                  */
     836             : 
     837          60 :                 if (!ldb_dn_add_child_fmt(dn,
     838             :                                           "DC=X,%s",
     839             :                                           zone_prefixes[i])) {
     840           0 :                         talloc_free(tmp_ctx);
     841           0 :                         return ISC_R_NOMEMORY;
     842             :                 }
     843             : 
     844          60 :                 ret = ldb_dn_set_component(dn,
     845             :                                            0,
     846             :                                            "DC",
     847             :                                            zone_name_val);
     848          60 :                 if (ret != LDB_SUCCESS) {
     849           0 :                         talloc_free(tmp_ctx);
     850           0 :                         return ISC_R_NOMEMORY;
     851             :                 }
     852             : 
     853             :                 /*
     854             :                  * Check if this is a plausibly valid DN early
     855             :                  * (time spent here will be saved during the
     856             :                  * search due to an internal cache)
     857             :                  */
     858          60 :                 casefold = ldb_dn_get_casefold(dn);
     859             : 
     860          60 :                 if (casefold == NULL) {
     861           0 :                         talloc_free(tmp_ctx);
     862           0 :                         return ISC_R_NOTFOUND;
     863             :                 }
     864             : 
     865          60 :                 ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsZone");
     866          60 :                 if (ret == LDB_SUCCESS) {
     867          21 :                         if (zone_dn != NULL) {
     868          15 :                                 *zone_dn = talloc_steal(mem_ctx, dn);
     869             :                         }
     870          21 :                         talloc_free(tmp_ctx);
     871          21 :                         return ISC_R_SUCCESS;
     872             :                 }
     873          39 :                 talloc_free(dn);
     874             :         }
     875             : 
     876          13 :         talloc_free(tmp_ctx);
     877          13 :         return ISC_R_NOTFOUND;
     878             : }
     879             : 
     880             : 
     881             : /*
     882             :   return the DN for a name. The record does not need to exist, but the
     883             :   zone must exist
     884             :  */
     885          15 : static isc_result_t b9_find_name_dn(struct dlz_bind9_data *state, const char *name,
     886             :                                     TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
     887             : {
     888             :         const char *p;
     889             : 
     890             :         /* work through the name piece by piece, until we find a zone */
     891          43 :         for (p=name; p; ) {
     892             :                 isc_result_t result;
     893          28 :                 result = b9_find_zone_dn(state, p, mem_ctx, dn);
     894          28 :                 if (result == ISC_R_SUCCESS) {
     895             :                         const char *casefold;
     896             : 
     897             :                         /* we found a zone, now extend the DN to get
     898             :                          * the full DN
     899             :                          */
     900             :                         bool ret;
     901          15 :                         if (p == name) {
     902           2 :                                 ret = ldb_dn_add_child_fmt(*dn, "DC=@");
     903           2 :                                 if (ret == false) {
     904           0 :                                         talloc_free(*dn);
     905           0 :                                         return ISC_R_NOMEMORY;
     906             :                                 }
     907             :                         } else {
     908          13 :                                 struct ldb_val name_val
     909          13 :                                         = data_blob_const(name,
     910          13 :                                                           (int)(p-name)-1);
     911             : 
     912          13 :                                 if (!ldb_dn_add_child_val(*dn,
     913             :                                                           "DC",
     914             :                                                           name_val)) {
     915           0 :                                         talloc_free(*dn);
     916           0 :                                         return ISC_R_NOMEMORY;
     917             :                                 }
     918             :                         }
     919             : 
     920             :                         /*
     921             :                          * Check if this is a plausibly valid DN early
     922             :                          * (time spent here will be saved during the
     923             :                          * search due to an internal cache)
     924             :                          */
     925          15 :                         casefold = ldb_dn_get_casefold(*dn);
     926             : 
     927          15 :                         if (casefold == NULL) {
     928           0 :                                 return ISC_R_NOTFOUND;
     929             :                         }
     930             : 
     931          15 :                         return ISC_R_SUCCESS;
     932             :                 }
     933          13 :                 p = strchr(p, '.');
     934          13 :                 if (p == NULL) {
     935           0 :                         break;
     936             :                 }
     937          13 :                 p++;
     938             :         }
     939           0 :         return ISC_R_NOTFOUND;
     940             : }
     941             : 
     942             : 
     943             : /*
     944             :   see if we handle a given zone
     945             :  */
     946           0 : _PUBLIC_ isc_result_t dlz_findzonedb(void *dbdata, const char *name,
     947             :                                      dns_clientinfomethods_t *methods,
     948             :                                      dns_clientinfo_t *clientinfo)
     949             : {
     950           0 :         struct timeval start = timeval_current();
     951           0 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
     952           0 :         isc_result_t result = ISC_R_SUCCESS;
     953             : 
     954           0 :         result = b9_find_zone_dn(state, name, NULL, NULL);
     955           0 :          DNS_COMMON_LOG_OPERATION(
     956             :                 isc_result_str(result),
     957             :                 &start,
     958             :                 NULL,
     959             :                 name,
     960             :                 NULL);
     961           0 :         return result;
     962             : }
     963             : 
     964             : 
     965             : /*
     966             :   lookup one record
     967             :  */
     968          13 : static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state,
     969             :                                      const char *zone, const char *name,
     970             :                                      dns_sdlzlookup_t *lookup,
     971             :                                      const char **types)
     972             : {
     973          13 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
     974             :         struct ldb_dn *dn;
     975          13 :         WERROR werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
     976          13 :         struct dnsp_DnssrvRpcRecord *records = NULL;
     977          13 :         uint16_t num_records = 0, i;
     978          13 :         struct ldb_val zone_name_val
     979           0 :                 = data_blob_string_const(zone);
     980          13 :         struct ldb_val name_val
     981           0 :                 = data_blob_string_const(name);
     982             : 
     983          22 :         for (i=0; zone_prefixes[i]; i++) {
     984             :                 int ret;
     985             :                 const char *casefold;
     986          19 :                 dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
     987          19 :                 if (dn == NULL) {
     988           0 :                         talloc_free(tmp_ctx);
     989           0 :                         return ISC_R_NOMEMORY;
     990             :                 }
     991             : 
     992             :                 /*
     993             :                  * This dance ensures that it is not possible to put
     994             :                  * (eg) an extra DC=x, into the DNS name being
     995             :                  * queried
     996             :                  */
     997             : 
     998          19 :                 if (!ldb_dn_add_child_fmt(dn,
     999             :                                           "DC=X,DC=X,%s",
    1000             :                                           zone_prefixes[i])) {
    1001           0 :                         talloc_free(tmp_ctx);
    1002           0 :                         return ISC_R_NOMEMORY;
    1003             :                 }
    1004             : 
    1005          19 :                 ret = ldb_dn_set_component(dn,
    1006             :                                            1,
    1007             :                                            "DC",
    1008             :                                            zone_name_val);
    1009          19 :                 if (ret != LDB_SUCCESS) {
    1010           0 :                         talloc_free(tmp_ctx);
    1011           0 :                         return ISC_R_NOMEMORY;
    1012             :                 }
    1013             : 
    1014          19 :                 ret = ldb_dn_set_component(dn,
    1015             :                                            0,
    1016             :                                            "DC",
    1017             :                                            name_val);
    1018          19 :                 if (ret != LDB_SUCCESS) {
    1019           0 :                         talloc_free(tmp_ctx);
    1020           0 :                         return ISC_R_NOMEMORY;
    1021             :                 }
    1022             : 
    1023             :                 /*
    1024             :                  * Check if this is a plausibly valid DN early
    1025             :                  * (time spent here will be saved during the
    1026             :                  * search due to an internal cache)
    1027             :                  */
    1028          19 :                 casefold = ldb_dn_get_casefold(dn);
    1029             : 
    1030          19 :                 if (casefold == NULL) {
    1031           0 :                         talloc_free(tmp_ctx);
    1032           0 :                         return ISC_R_NOTFOUND;
    1033             :                 }
    1034             : 
    1035          19 :                 werr = dns_common_wildcard_lookup(state->samdb, tmp_ctx, dn,
    1036             :                                          &records, &num_records);
    1037          19 :                 if (W_ERROR_IS_OK(werr)) {
    1038          10 :                         break;
    1039             :                 }
    1040             :         }
    1041          13 :         if (!W_ERROR_IS_OK(werr)) {
    1042           3 :                 talloc_free(tmp_ctx);
    1043           3 :                 return ISC_R_NOTFOUND;
    1044             :         }
    1045             : 
    1046          29 :         for (i=0; i < num_records; i++) {
    1047             :                 isc_result_t result;
    1048             : 
    1049          19 :                 result = b9_putrr(state, lookup, &records[i], types);
    1050          19 :                 if (result != ISC_R_SUCCESS) {
    1051           0 :                         talloc_free(tmp_ctx);
    1052           0 :                         return result;
    1053             :                 }
    1054             :         }
    1055             : 
    1056          10 :         talloc_free(tmp_ctx);
    1057          10 :         return ISC_R_SUCCESS;
    1058             : }
    1059             : 
    1060             : /*
    1061             :   lookup one record
    1062             :  */
    1063          13 : _PUBLIC_ isc_result_t dlz_lookup(const char *zone, const char *name,
    1064             :                                  void *dbdata, dns_sdlzlookup_t *lookup,
    1065             :                                  dns_clientinfomethods_t *methods,
    1066             :                                  dns_clientinfo_t *clientinfo)
    1067             : {
    1068          13 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1069          13 :         isc_result_t result = ISC_R_SUCCESS;
    1070          13 :         struct timeval start = timeval_current();
    1071             : 
    1072          13 :         result = dlz_lookup_types(state, zone, name, lookup, NULL);
    1073          13 :         DNS_COMMON_LOG_OPERATION(
    1074             :                 isc_result_str(result),
    1075             :                 &start,
    1076             :                 zone,
    1077             :                 name,
    1078             :                 NULL);
    1079             : 
    1080          13 :         return result;
    1081             : }
    1082             : 
    1083             : 
    1084             : /*
    1085             :   see if a zone transfer is allowed
    1086             :  */
    1087           6 : _PUBLIC_ isc_result_t dlz_allowzonexfr(void *dbdata, const char *name, const char *client)
    1088             : {
    1089           6 :         struct dlz_bind9_data *state = talloc_get_type(
    1090             :                 dbdata, struct dlz_bind9_data);
    1091             :         isc_result_t ret;
    1092             :         const char **authorized_clients, **denied_clients;
    1093           6 :         const char *cname="";
    1094             : 
    1095             :         /* check that the zone is known */
    1096           6 :         ret = b9_find_zone_dn(state, name, NULL, NULL);
    1097           6 :         if (ret != ISC_R_SUCCESS) {
    1098           0 :                 return ret;
    1099             :         }
    1100             : 
    1101             :         /* default is to deny all transfers */
    1102             : 
    1103           6 :         authorized_clients = lpcfg_dns_zone_transfer_clients_allow(state->lp);
    1104           6 :         denied_clients = lpcfg_dns_zone_transfer_clients_deny(state->lp);
    1105             : 
    1106             :         /* The logic of allow_access() when both allow and deny lists are given
    1107             :          * does not match our expectation here: it would allow clients thar are
    1108             :          * neither allowed nor denied.
    1109             :          * Here, we want to deny clients by default.
    1110             :          * Using the allow_access() function is still useful as it takes care of
    1111             :          * parsing IP adresses and subnets in a consistent way with other options
    1112             :          * from smb.conf.
    1113             :          *
    1114             :          * We will then check the deny list first, then the allow list, so that
    1115             :          * we accept only clients that are explicitely allowed AND not explicitely
    1116             :          * denied.
    1117             :          */
    1118           6 :         if ((authorized_clients == NULL) && (denied_clients == NULL)) {
    1119             :                 /* No "allow" or "deny" lists given. Deny by default. */
    1120           1 :                 return ISC_R_NOPERM;
    1121             :         }
    1122             : 
    1123           5 :         if (denied_clients != NULL) {
    1124           5 :                 bool ok = allow_access(denied_clients, NULL, cname, client);
    1125           5 :                 if (!ok) {
    1126             :                         /* client on deny list. Deny. */
    1127           1 :                         return ISC_R_NOPERM;
    1128             :                 }
    1129             :         }
    1130             : 
    1131           4 :         if (authorized_clients != NULL) {
    1132           4 :                 bool ok = allow_access(NULL, authorized_clients, cname, client);
    1133           4 :                 if (ok) {
    1134             :                         /*
    1135             :                          * client is not on deny list and is on allow list.
    1136             :                          * This is the only place we should return "allow".
    1137             :                          */
    1138           3 :                         return ISC_R_SUCCESS;
    1139             :                 }
    1140             :         }
    1141             :         /* We shouldn't get here, but deny by default. */
    1142           1 :         return ISC_R_NOPERM;
    1143             : }
    1144             : 
    1145             : /*
    1146             :   perform a zone transfer
    1147             :  */
    1148           1 : _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata,
    1149             :                                    dns_sdlzallnodes_t *allnodes)
    1150             : {
    1151           1 :         struct timeval start = timeval_current();
    1152           1 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1153           1 :         const char *attrs[] = { "dnsRecord", NULL };
    1154           1 :         int ret = LDB_ERR_NO_SUCH_OBJECT;
    1155             :         size_t i, j;
    1156           1 :         struct ldb_dn *dn = NULL;
    1157             :         struct ldb_result *res;
    1158           1 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
    1159           1 :         struct ldb_val zone_name_val = data_blob_string_const(zone);
    1160           1 :         isc_result_t result = ISC_R_SUCCESS;
    1161             : 
    1162           1 :         for (i=0; zone_prefixes[i]; i++) {
    1163             :                 const char *casefold;
    1164             : 
    1165           1 :                 dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
    1166           1 :                 if (dn == NULL) {
    1167           0 :                         talloc_free(tmp_ctx);
    1168           0 :                         result = ISC_R_NOMEMORY;
    1169           0 :                         goto exit;
    1170             :                 }
    1171             : 
    1172             :                 /*
    1173             :                  * This dance ensures that it is not possible to put
    1174             :                  * (eg) an extra DC=x, into the DNS name being
    1175             :                  * queried
    1176             :                  */
    1177             : 
    1178           1 :                 if (!ldb_dn_add_child_fmt(dn,
    1179             :                                           "DC=X,%s",
    1180             :                                           zone_prefixes[i])) {
    1181           0 :                         talloc_free(tmp_ctx);
    1182           0 :                         result = ISC_R_NOMEMORY;
    1183           0 :                         goto exit;
    1184             :                 }
    1185             : 
    1186           1 :                 ret = ldb_dn_set_component(dn,
    1187             :                                            0,
    1188             :                                            "DC",
    1189             :                                            zone_name_val);
    1190           1 :                 if (ret != LDB_SUCCESS) {
    1191           0 :                         talloc_free(tmp_ctx);
    1192           0 :                         result = ISC_R_NOMEMORY;
    1193           0 :                         goto exit;
    1194             :                 }
    1195             : 
    1196             :                 /*
    1197             :                  * Check if this is a plausibly valid DN early
    1198             :                  * (time spent here will be saved during the
    1199             :                  * search due to an internal cache)
    1200             :                  */
    1201           1 :                 casefold = ldb_dn_get_casefold(dn);
    1202             : 
    1203           1 :                 if (casefold == NULL) {
    1204           0 :                         result = ISC_R_NOTFOUND;
    1205           0 :                         goto exit;
    1206             :                 }
    1207             : 
    1208           1 :                 ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
    1209             :                                  attrs, "objectClass=dnsNode");
    1210           1 :                 if (ret == LDB_SUCCESS) {
    1211           1 :                         break;
    1212             :                 }
    1213             :         }
    1214           1 :         if (ret != LDB_SUCCESS || dn == NULL) {
    1215           0 :                 talloc_free(tmp_ctx);
    1216           0 :                 result = ISC_R_NOTFOUND;
    1217           0 :                 goto exit;
    1218             :         }
    1219             : 
    1220          19 :         for (i=0; i<res->count; i++) {
    1221             :                 struct ldb_message_element *el;
    1222          18 :                 TALLOC_CTX *el_ctx = talloc_new(tmp_ctx);
    1223             :                 const char *rdn, *name;
    1224             :                 const struct ldb_val *v;
    1225             :                 WERROR werr;
    1226          18 :                 struct dnsp_DnssrvRpcRecord *recs = NULL;
    1227          18 :                 uint16_t num_recs = 0;
    1228             : 
    1229          18 :                 el = ldb_msg_find_element(res->msgs[i], "dnsRecord");
    1230          18 :                 if (el == NULL || el->num_values == 0) {
    1231           0 :                         state->log(ISC_LOG_INFO, "failed to find dnsRecord for %s",
    1232             :                                    ldb_dn_get_linearized(dn));
    1233           0 :                         talloc_free(el_ctx);
    1234           0 :                         continue;
    1235             :                 }
    1236             : 
    1237          18 :                 v = ldb_dn_get_rdn_val(res->msgs[i]->dn);
    1238          18 :                 if (v == NULL) {
    1239           0 :                         state->log(ISC_LOG_INFO, "failed to find RDN for %s",
    1240             :                                    ldb_dn_get_linearized(dn));
    1241           0 :                         talloc_free(el_ctx);
    1242           0 :                         continue;
    1243             :                 }
    1244             : 
    1245          18 :                 rdn = talloc_strndup(el_ctx, (char *)v->data, v->length);
    1246          18 :                 if (rdn == NULL) {
    1247           0 :                         talloc_free(tmp_ctx);
    1248           0 :                         result = ISC_R_NOMEMORY;
    1249           0 :                         goto exit;
    1250             :                 }
    1251             : 
    1252          18 :                 if (strcmp(rdn, "@") == 0) {
    1253           1 :                         name = zone;
    1254             :                 } else {
    1255          17 :                         name = talloc_asprintf(el_ctx, "%s.%s", rdn, zone);
    1256             :                 }
    1257          18 :                 name = b9_format_fqdn(el_ctx, name);
    1258          18 :                 if (name == NULL) {
    1259           0 :                         talloc_free(tmp_ctx);
    1260           0 :                         result = ISC_R_NOMEMORY;
    1261           0 :                         goto exit;
    1262             :                 }
    1263             : 
    1264          18 :                 werr = dns_common_extract(state->samdb, el, el_ctx, &recs, &num_recs);
    1265          18 :                 if (!W_ERROR_IS_OK(werr)) {
    1266           0 :                         state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s",
    1267             :                                    ldb_dn_get_linearized(dn), win_errstr(werr));
    1268           0 :                         talloc_free(el_ctx);
    1269           0 :                         continue;
    1270             :                 }
    1271             : 
    1272          42 :                 for (j=0; j < num_recs; j++) {
    1273             :                         isc_result_t rc;
    1274             : 
    1275          24 :                         rc = b9_putnamedrr(state, allnodes, name, &recs[j]);
    1276          24 :                         if (rc != ISC_R_SUCCESS) {
    1277           0 :                                 continue;
    1278             :                         }
    1279             :                 }
    1280             : 
    1281          18 :                 talloc_free(el_ctx);
    1282             :         }
    1283             : 
    1284           1 :         talloc_free(tmp_ctx);
    1285           1 : exit:
    1286           1 :         DNS_COMMON_LOG_OPERATION(
    1287             :                 isc_result_str(result),
    1288             :                 &start,
    1289             :                 zone,
    1290             :                 NULL,
    1291             :                 NULL);
    1292           1 :         return result;
    1293             : }
    1294             : 
    1295             : 
    1296             : /*
    1297             :   start a transaction
    1298             :  */
    1299          12 : _PUBLIC_ isc_result_t dlz_newversion(const char *zone, void *dbdata, void **versionp)
    1300             : {
    1301          12 :         struct timeval start = timeval_current();
    1302          12 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1303          12 :         isc_result_t result = ISC_R_SUCCESS;
    1304             : 
    1305          12 :         state->log(ISC_LOG_INFO, "samba_dlz: starting transaction on zone %s", zone);
    1306             : 
    1307          12 :         if (state->transaction_token != NULL) {
    1308           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: transaction already started for zone %s", zone);
    1309           0 :                 result = ISC_R_FAILURE;
    1310           0 :                 goto exit;
    1311             :         }
    1312             : 
    1313          12 :         state->transaction_token = talloc_zero(state, int);
    1314          12 :         if (state->transaction_token == NULL) {
    1315           0 :                 result = ISC_R_NOMEMORY;
    1316           0 :                 goto exit;
    1317             :         }
    1318             : 
    1319          12 :         if (ldb_transaction_start(state->samdb) != LDB_SUCCESS) {
    1320           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: failed to start a transaction for zone %s", zone);
    1321           0 :                 talloc_free(state->transaction_token);
    1322           0 :                 state->transaction_token = NULL;
    1323           0 :                 result = ISC_R_FAILURE;
    1324           0 :                 goto exit;
    1325             :         }
    1326             : 
    1327          12 :         *versionp = (void *)state->transaction_token;
    1328          12 : exit:
    1329          12 :         DNS_COMMON_LOG_OPERATION(
    1330             :                 isc_result_str(result),
    1331             :                 &start,
    1332             :                 zone,
    1333             :                 NULL,
    1334             :                 NULL);
    1335          12 :         return result;
    1336             : }
    1337             : 
    1338             : /*
    1339             :   end a transaction
    1340             :  */
    1341          12 : _PUBLIC_ void dlz_closeversion(const char *zone, isc_boolean_t commit,
    1342             :                                void *dbdata, void **versionp)
    1343             : {
    1344          12 :         struct timeval start = timeval_current();
    1345          12 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1346          12 :         const char *data = NULL;
    1347             : 
    1348          12 :         data = commit ? "commit" : "cancel";
    1349             : 
    1350          12 :         if (state->transaction_token != (int *)*versionp) {
    1351           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: transaction not started for zone %s", zone);
    1352           0 :                 goto exit;
    1353             :         }
    1354             : 
    1355          12 :         if (commit) {
    1356           9 :                 if (ldb_transaction_commit(state->samdb) != LDB_SUCCESS) {
    1357           0 :                         state->log(ISC_LOG_INFO, "samba_dlz: failed to commit a transaction for zone %s", zone);
    1358           0 :                         goto exit;
    1359             :                 }
    1360           9 :                 state->log(ISC_LOG_INFO, "samba_dlz: committed transaction on zone %s", zone);
    1361             :         } else {
    1362           3 :                 if (ldb_transaction_cancel(state->samdb) != LDB_SUCCESS) {
    1363           0 :                         state->log(ISC_LOG_INFO, "samba_dlz: failed to cancel a transaction for zone %s", zone);
    1364           0 :                         goto exit;
    1365             :                 }
    1366           3 :                 state->log(ISC_LOG_INFO, "samba_dlz: cancelling transaction on zone %s", zone);
    1367             :         }
    1368             : 
    1369          12 :         talloc_free(state->transaction_token);
    1370          12 :         state->transaction_token = NULL;
    1371          12 :         *versionp = NULL;
    1372             : 
    1373          12 : exit:
    1374          12 :         DNS_COMMON_LOG_OPERATION(
    1375             :                 isc_result_str(ISC_R_SUCCESS),
    1376             :                 &start,
    1377             :                 zone,
    1378             :                 NULL,
    1379             :                 data);
    1380          12 : }
    1381             : 
    1382             : 
    1383             : /*
    1384             :   see if there is a SOA record for a zone
    1385             :  */
    1386          38 : static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const char *zone)
    1387             : {
    1388          38 :         TALLOC_CTX *tmp_ctx = talloc_new(state);
    1389             :         WERROR werr;
    1390          38 :         struct dnsp_DnssrvRpcRecord *records = NULL;
    1391          38 :         uint16_t num_records = 0, i;
    1392          38 :         struct ldb_val zone_name_val
    1393           0 :                 = data_blob_string_const(zone);
    1394             : 
    1395             :         /*
    1396             :          * This dance ensures that it is not possible to put
    1397             :          * (eg) an extra DC=x, into the DNS name being
    1398             :          * queried
    1399             :          */
    1400             : 
    1401          38 :         if (!ldb_dn_add_child_val(dn,
    1402             :                                   "DC",
    1403             :                                   zone_name_val)) {
    1404           0 :                 talloc_free(tmp_ctx);
    1405           0 :                 return false;
    1406             :         }
    1407             : 
    1408             :         /*
    1409             :          * The SOA record is alwas stored under DC=@,DC=zonename
    1410             :          * This can probably be removed when dns_common_lookup makes a fallback
    1411             :          * lookup on @ pseudo record
    1412             :          */
    1413             : 
    1414          38 :         if (!ldb_dn_add_child_fmt(dn,"DC=@")) {
    1415           0 :                 talloc_free(tmp_ctx);
    1416           0 :                 return false;
    1417             :         }
    1418             : 
    1419          38 :         werr = dns_common_lookup(state->samdb, tmp_ctx, dn,
    1420             :                                  &records, &num_records, NULL);
    1421          38 :         if (!W_ERROR_IS_OK(werr)) {
    1422           0 :                 talloc_free(tmp_ctx);
    1423           0 :                 return false;
    1424             :         }
    1425             : 
    1426          38 :         for (i=0; i < num_records; i++) {
    1427          38 :                 if (records[i].wType == DNS_TYPE_SOA) {
    1428          38 :                         talloc_free(tmp_ctx);
    1429          38 :                         return true;
    1430             :                 }
    1431             :         }
    1432             : 
    1433           0 :         talloc_free(tmp_ctx);
    1434           0 :         return false;
    1435             : }
    1436             : 
    1437          26 : static bool b9_zone_add(struct dlz_bind9_data *state, const char *name)
    1438             : {
    1439             :         struct b9_zone *zone;
    1440             : 
    1441          26 :         zone = talloc_zero(state, struct b9_zone);
    1442          26 :         if (zone == NULL) {
    1443           0 :                 return false;
    1444             :         }
    1445             : 
    1446          26 :         zone->name = talloc_strdup(zone, name);
    1447          26 :         if (zone->name == NULL) {
    1448           0 :                 talloc_free(zone);
    1449           0 :                 return false;
    1450             :         }
    1451             : 
    1452          26 :         DLIST_ADD(state->zonelist, zone);
    1453          26 :         return true;
    1454             : }
    1455             : 
    1456          38 : static bool b9_zone_exists(struct dlz_bind9_data *state, const char *name)
    1457             : {
    1458          38 :         struct b9_zone *zone = state->zonelist;
    1459          38 :         bool found = false;
    1460             : 
    1461          95 :         while (zone != NULL) {
    1462          31 :                 if (strcasecmp(name, zone->name) == 0) {
    1463          12 :                         found = true;
    1464          12 :                         break;
    1465             :                 }
    1466          19 :                 zone = zone->next;
    1467             :         }
    1468             : 
    1469          38 :         return found;
    1470             : }
    1471             : 
    1472             : 
    1473             : /*
    1474             :   configure a writeable zone
    1475             :  */
    1476          19 : _PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb,
    1477             :                                     void *dbdata)
    1478             : {
    1479          19 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1480             :         TALLOC_CTX *tmp_ctx;
    1481             :         struct ldb_dn *dn;
    1482             :         int i;
    1483             : 
    1484          19 :         state->log(ISC_LOG_INFO, "samba_dlz: starting configure");
    1485          19 :         if (state->writeable_zone == NULL) {
    1486           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: no writeable_zone method available");
    1487           0 :                 return ISC_R_FAILURE;
    1488             :         }
    1489             : 
    1490          19 :         tmp_ctx = talloc_new(state);
    1491             : 
    1492          76 :         for (i=0; zone_prefixes[i]; i++) {
    1493          57 :                 const char *attrs[] = { "name", NULL };
    1494             :                 int j, ret;
    1495             :                 struct ldb_result *res;
    1496             : 
    1497          57 :                 dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
    1498          57 :                 if (dn == NULL) {
    1499           0 :                         talloc_free(tmp_ctx);
    1500           0 :                         return ISC_R_NOMEMORY;
    1501             :                 }
    1502             : 
    1503          57 :                 if (!ldb_dn_add_child_fmt(dn, "%s", zone_prefixes[i])) {
    1504           0 :                         talloc_free(tmp_ctx);
    1505           0 :                         return ISC_R_NOMEMORY;
    1506             :                 }
    1507             : 
    1508          57 :                 ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
    1509             :                                  attrs, "objectClass=dnsZone");
    1510          57 :                 if (ret != LDB_SUCCESS) {
    1511          19 :                         continue;
    1512             :                 }
    1513             : 
    1514          95 :                 for (j=0; j<res->count; j++) {
    1515             :                         isc_result_t result;
    1516          57 :                         const char *zone = ldb_msg_find_attr_as_string(res->msgs[j], "name", NULL);
    1517             :                         struct ldb_dn *zone_dn;
    1518             : 
    1519          57 :                         if (zone == NULL) {
    1520           0 :                                 continue;
    1521             :                         }
    1522             :                         /* Ignore zones that are not handled in BIND */
    1523          95 :                         if ((strcmp(zone, "RootDNSServers") == 0) ||
    1524          38 :                             (strcmp(zone, "..TrustAnchors") == 0)) {
    1525          19 :                                 continue;
    1526             :                         }
    1527          38 :                         zone_dn = ldb_dn_copy(tmp_ctx, dn);
    1528          38 :                         if (zone_dn == NULL) {
    1529           0 :                                 talloc_free(tmp_ctx);
    1530           0 :                                 return ISC_R_NOMEMORY;
    1531             :                         }
    1532             : 
    1533          38 :                         if (!b9_has_soa(state, zone_dn, zone)) {
    1534           0 :                                 continue;
    1535             :                         }
    1536             : 
    1537          38 :                         if (b9_zone_exists(state, zone)) {
    1538          12 :                                 state->log(ISC_LOG_WARNING, "samba_dlz: Ignoring duplicate zone '%s' from '%s'",
    1539             :                                            zone, ldb_dn_get_linearized(zone_dn));
    1540          12 :                                 continue;
    1541             :                         }
    1542             : 
    1543          26 :                         if (!b9_zone_add(state, zone)) {
    1544           0 :                                 talloc_free(tmp_ctx);
    1545           0 :                                 return ISC_R_NOMEMORY;
    1546             :                         }
    1547             : 
    1548          26 :                         result = state->writeable_zone(view, dlzdb, zone);
    1549          26 :                         if (result != ISC_R_SUCCESS) {
    1550           0 :                                 state->log(ISC_LOG_ERROR, "samba_dlz: Failed to configure zone '%s'",
    1551             :                                            zone);
    1552           0 :                                 talloc_free(tmp_ctx);
    1553           0 :                                 return result;
    1554             :                         }
    1555          26 :                         state->log(ISC_LOG_INFO, "samba_dlz: configured writeable zone '%s'", zone);
    1556             :                 }
    1557             :         }
    1558             : 
    1559          19 :         talloc_free(tmp_ctx);
    1560          19 :         return ISC_R_SUCCESS;
    1561             : }
    1562             : 
    1563             : /*
    1564             :   authorize a zone update
    1565             :  */
    1566           3 : _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
    1567             :                                     const char *type, const char *key, uint32_t keydatalen, uint8_t *keydata,
    1568             :                                     void *dbdata)
    1569             : {
    1570           3 :         struct timeval start = timeval_current();
    1571           3 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1572             :         TALLOC_CTX *tmp_ctx;
    1573             :         DATA_BLOB ap_req;
    1574             :         struct cli_credentials *server_credentials;
    1575             :         char *keytab_name;
    1576           3 :         char *keytab_file = NULL;
    1577             :         int ret;
    1578             :         int ldb_ret;
    1579             :         NTSTATUS nt_status;
    1580             :         struct gensec_security *gensec_ctx;
    1581             :         struct auth_session_info *session_info;
    1582             :         struct ldb_dn *dn;
    1583             :         isc_result_t rc;
    1584             :         struct ldb_result *res;
    1585           3 :         const char * attrs[] = { NULL };
    1586             :         uint32_t access_mask;
    1587           3 :         struct gensec_settings *settings = NULL;
    1588           3 :         const struct gensec_security_ops **backends = NULL;
    1589           3 :         size_t idx = 0;
    1590           3 :         isc_boolean_t result = ISC_FALSE;
    1591             :         NTSTATUS status;
    1592             :         bool ok;
    1593             : 
    1594             :         /* Remove cached credentials, if any */
    1595           3 :         if (state->session_info) {
    1596           0 :                 talloc_free(state->session_info);
    1597           0 :                 state->session_info = NULL;
    1598             :         }
    1599           3 :         if (state->update_name) {
    1600           0 :                 talloc_free(state->update_name);
    1601           0 :                 state->update_name = NULL;
    1602             :         }
    1603             : 
    1604           3 :         tmp_ctx = talloc_new(state);
    1605           3 :         if (tmp_ctx == NULL) {
    1606           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: no memory");
    1607           0 :                 result = ISC_FALSE;
    1608           0 :                 goto exit;
    1609             :         }
    1610             : 
    1611           3 :         ap_req = data_blob_const(keydata, keydatalen);
    1612           3 :         server_credentials = cli_credentials_init(tmp_ctx);
    1613           3 :         if (!server_credentials) {
    1614           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to init server credentials");
    1615           0 :                 talloc_free(tmp_ctx);
    1616           0 :                 result = ISC_FALSE;
    1617           0 :                 goto exit;
    1618             :         }
    1619             : 
    1620           3 :         status = cli_credentials_set_krb5_context(server_credentials,
    1621             :                                                   state->smb_krb5_ctx);
    1622           3 :         if (!NT_STATUS_IS_OK(status)) {
    1623           0 :                 state->log(ISC_LOG_ERROR,
    1624             :                            "samba_dlz: failed to set krb5 context");
    1625           0 :                 talloc_free(tmp_ctx);
    1626           0 :                 result = ISC_FALSE;
    1627           0 :                 goto exit;
    1628             :         }
    1629             : 
    1630           3 :         ok = cli_credentials_set_conf(server_credentials, state->lp);
    1631           3 :         if (!ok) {
    1632           0 :                 state->log(ISC_LOG_ERROR,
    1633             :                            "samba_dlz: failed to load smb.conf");
    1634           0 :                 talloc_free(tmp_ctx);
    1635           0 :                 result = ISC_FALSE;
    1636           0 :                 goto exit;
    1637             :         }
    1638             : 
    1639           3 :         keytab_file = talloc_asprintf(tmp_ctx,
    1640             :                                       "%s/dns.keytab",
    1641             :                                       lpcfg_binddns_dir(state->lp));
    1642           3 :         if (keytab_file == NULL) {
    1643           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: Out of memory!");
    1644           0 :                 talloc_free(tmp_ctx);
    1645           0 :                 result = ISC_FALSE;
    1646           0 :                 goto exit;
    1647             :         }
    1648             : 
    1649           3 :         if (!file_exist(keytab_file)) {
    1650           0 :                 keytab_file = talloc_asprintf(tmp_ctx,
    1651             :                                               "%s/dns.keytab",
    1652             :                                               lpcfg_private_dir(state->lp));
    1653           0 :                 if (keytab_file == NULL) {
    1654           0 :                         state->log(ISC_LOG_ERROR, "samba_dlz: Out of memory!");
    1655           0 :                         talloc_free(tmp_ctx);
    1656           0 :                         result = ISC_FALSE;
    1657           0 :                         goto exit;
    1658             :                 }
    1659             :         }
    1660             : 
    1661           3 :         keytab_name = talloc_asprintf(tmp_ctx, "FILE:%s", keytab_file);
    1662           3 :         if (keytab_name == NULL) {
    1663           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: Out of memory!");
    1664           0 :                 talloc_free(tmp_ctx);
    1665           0 :                 result = ISC_FALSE;
    1666           0 :                 goto exit;
    1667             :         }
    1668             : 
    1669           3 :         ret = cli_credentials_set_keytab_name(server_credentials, state->lp, keytab_name,
    1670             :                                                 CRED_SPECIFIED);
    1671           3 :         if (ret != 0) {
    1672           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to obtain server credentials from %s",
    1673             :                            keytab_name);
    1674           0 :                 talloc_free(tmp_ctx);
    1675           0 :                 result = ISC_FALSE;
    1676           0 :                 goto exit;
    1677             :         }
    1678           3 :         talloc_free(keytab_name);
    1679             : 
    1680           3 :         settings = lpcfg_gensec_settings(tmp_ctx, state->lp);
    1681           3 :         if (settings == NULL) {
    1682           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: lpcfg_gensec_settings failed");
    1683           0 :                 talloc_free(tmp_ctx);
    1684           0 :                 result = ISC_FALSE;
    1685           0 :                 goto exit;
    1686             :         }
    1687           3 :         backends = talloc_zero_array(settings,
    1688             :                                      const struct gensec_security_ops *, 3);
    1689           3 :         if (backends == NULL) {
    1690           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: talloc_zero_array gensec_security_ops failed");
    1691           0 :                 talloc_free(tmp_ctx);
    1692           0 :                 result = ISC_FALSE;
    1693           0 :                 goto exit;
    1694             :         }
    1695           3 :         settings->backends = backends;
    1696             : 
    1697           3 :         gensec_init();
    1698             : 
    1699           3 :         backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_KERBEROS5);
    1700           3 :         backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
    1701             : 
    1702           3 :         nt_status = gensec_server_start(tmp_ctx, settings,
    1703             :                                         state->auth_context, &gensec_ctx);
    1704           3 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1705           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to start gensec server");
    1706           0 :                 talloc_free(tmp_ctx);
    1707           0 :                 result = ISC_FALSE;
    1708           0 :                 goto exit;
    1709             :         }
    1710             : 
    1711           3 :         gensec_set_credentials(gensec_ctx, server_credentials);
    1712             : 
    1713           3 :         nt_status = gensec_start_mech_by_oid(gensec_ctx, GENSEC_OID_SPNEGO);
    1714           3 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1715           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to start spnego");
    1716           0 :                 talloc_free(tmp_ctx);
    1717           0 :                 result = ISC_FALSE;
    1718           0 :                 goto exit;
    1719             :         }
    1720             : 
    1721             :         /*
    1722             :          * We only allow SPNEGO/KRB5 and make sure the backend
    1723             :          * to is RPC/IPC free.
    1724             :          *
    1725             :          * See gensec_gssapi_update_internal() as
    1726             :          * GENSEC_SERVER.
    1727             :          *
    1728             :          * It allows gensec_update() not to block.
    1729             :          *
    1730             :          * If that changes in future we need to use
    1731             :          * gensec_update_send/recv here!
    1732             :          */
    1733           3 :         nt_status = gensec_update(gensec_ctx, tmp_ctx, ap_req, &ap_req);
    1734           3 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1735           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: spnego update failed");
    1736           0 :                 talloc_free(tmp_ctx);
    1737           0 :                 result = ISC_FALSE;
    1738           0 :                 goto exit;
    1739             :         }
    1740             : 
    1741           3 :         nt_status = gensec_session_info(gensec_ctx, tmp_ctx, &session_info);
    1742           3 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1743           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to create session info");
    1744           0 :                 talloc_free(tmp_ctx);
    1745           0 :                 result = ISC_FALSE;
    1746           0 :                 goto exit;
    1747             :         }
    1748             : 
    1749             :         /* Get the DN from name */
    1750           3 :         rc = b9_find_name_dn(state, name, tmp_ctx, &dn);
    1751           3 :         if (rc != ISC_R_SUCCESS) {
    1752           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to find name %s", name);
    1753           0 :                 talloc_free(tmp_ctx);
    1754           0 :                 result = ISC_FALSE;
    1755           0 :                 goto exit;
    1756             :         }
    1757             : 
    1758             :         /* make sure the dn exists, or find parent dn in case new object is being added */
    1759           3 :         ldb_ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
    1760             :                                 attrs, "objectClass=dnsNode");
    1761           3 :         if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT) {
    1762           1 :                 ldb_dn_remove_child_components(dn, 1);
    1763           1 :                 access_mask = SEC_ADS_CREATE_CHILD;
    1764           1 :                 talloc_free(res);
    1765           2 :         } else if (ldb_ret == LDB_SUCCESS) {
    1766           2 :                 access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE;
    1767           2 :                 talloc_free(res);
    1768             :         } else {
    1769           0 :                 talloc_free(tmp_ctx);
    1770           0 :                 result = ISC_FALSE;
    1771           0 :                 goto exit;
    1772             :         }
    1773             : 
    1774             :         /* Do ACL check */
    1775           3 :         ldb_ret = dsdb_check_access_on_dn(state->samdb, tmp_ctx, dn,
    1776           3 :                                                 session_info->security_token,
    1777             :                                                 access_mask, NULL);
    1778           3 :         if (ldb_ret != LDB_SUCCESS) {
    1779           0 :                 state->log(ISC_LOG_INFO,
    1780             :                         "samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s",
    1781             :                         signer, name, type, ldb_strerror(ldb_ret));
    1782           0 :                 talloc_free(tmp_ctx);
    1783           0 :                 result = ISC_FALSE;
    1784           0 :                 goto exit;
    1785             :         }
    1786             : 
    1787             :         /* Cache session_info, so it can be used in the actual add/delete operation */
    1788           3 :         state->update_name = talloc_strdup(state, name);
    1789           3 :         if (state->update_name == NULL) {
    1790           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: memory allocation error");
    1791           0 :                 talloc_free(tmp_ctx);
    1792           0 :                 result = ISC_FALSE;
    1793           0 :                 goto exit;
    1794             :         }
    1795           3 :         state->session_info = talloc_steal(state, session_info);
    1796             : 
    1797           3 :         state->log(ISC_LOG_INFO, "samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s",
    1798             :                    signer, name, tcpaddr, type, key);
    1799             : 
    1800           3 :         talloc_free(tmp_ctx);
    1801           3 :         result = ISC_TRUE;
    1802           3 : exit:
    1803           3 :         DNS_COMMON_LOG_OPERATION(
    1804             :                 isc_result_str(result),
    1805             :                 &start,
    1806             :                 NULL,
    1807             :                 name,
    1808             :                 NULL);
    1809           3 :         return result;
    1810             : }
    1811             : 
    1812             : 
    1813             : /*
    1814             :   see if two dns records match
    1815             :  */
    1816           7 : static bool b9_record_match(struct dnsp_DnssrvRpcRecord *rec1,
    1817             :                             struct dnsp_DnssrvRpcRecord *rec2)
    1818             : {
    1819           7 :         if (rec1->wType != rec2->wType) {
    1820           0 :                 return false;
    1821             :         }
    1822             :         /* see if this type is single valued */
    1823           7 :         if (b9_single_valued(rec1->wType)) {
    1824           0 :                 return true;
    1825             :         }
    1826             : 
    1827           7 :         return dns_record_match(rec1, rec2);
    1828             : }
    1829             : 
    1830             : /*
    1831             :  * Update session_info on samdb using the cached credentials
    1832             :  */
    1833           8 : static bool b9_set_session_info(struct dlz_bind9_data *state, const char *name)
    1834             : {
    1835             :         int ret;
    1836             : 
    1837           8 :         if (state->update_name == NULL || state->session_info == NULL) {
    1838           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: invalid credentials");
    1839           0 :                 return false;
    1840             :         }
    1841             : 
    1842             :         /* Do not use client credentials, if we're not updating the client specified name */
    1843           8 :         if (strcmp(state->update_name, name) != 0) {
    1844           0 :                 return true;
    1845             :         }
    1846             : 
    1847           8 :         ret = ldb_set_opaque(
    1848             :                 state->samdb,
    1849             :                 DSDB_SESSION_INFO,
    1850           8 :                 state->session_info);
    1851           8 :         if (ret != LDB_SUCCESS) {
    1852           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: unable to set session info");
    1853           0 :                 return false;
    1854             :         }
    1855             : 
    1856           8 :         return true;
    1857             : }
    1858             : 
    1859             : /*
    1860             :  * Reset session_info on samdb as system session
    1861             :  */
    1862           8 : static void b9_reset_session_info(struct dlz_bind9_data *state)
    1863             : {
    1864           8 :         ldb_set_opaque(
    1865             :                 state->samdb,
    1866             :                 DSDB_SESSION_INFO,
    1867           8 :                 system_session(state->lp));
    1868           8 : }
    1869             : 
    1870             : /*
    1871             :   add or modify a rdataset
    1872             :  */
    1873           5 : _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, void *dbdata, void *version)
    1874             : {
    1875           5 :         struct timeval start = timeval_current();
    1876           5 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    1877             :         struct dnsp_DnssrvRpcRecord *rec;
    1878             :         struct ldb_dn *dn;
    1879           5 :         isc_result_t result = ISC_R_SUCCESS;
    1880           5 :         bool tombstoned = false;
    1881           5 :         bool needs_add = false;
    1882           5 :         struct dnsp_DnssrvRpcRecord *recs = NULL;
    1883           5 :         uint16_t num_recs = 0;
    1884           5 :         uint16_t first = 0;
    1885             :         uint16_t i;
    1886             :         WERROR werr;
    1887             : 
    1888           5 :         if (state->transaction_token != (void*)version) {
    1889           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version");
    1890           0 :                 result = ISC_R_FAILURE;
    1891           0 :                 goto exit;
    1892             :         }
    1893             : 
    1894           5 :         rec = talloc_zero(state, struct dnsp_DnssrvRpcRecord);
    1895           5 :         if (rec == NULL) {
    1896           0 :                 result = ISC_R_NOMEMORY;
    1897           0 :                 goto exit;
    1898             :         }
    1899             : 
    1900           5 :         rec->rank        = DNS_RANK_ZONE;
    1901             : 
    1902           5 :         if (!b9_parse(state, rdatastr, rec)) {
    1903           0 :                 state->log(ISC_LOG_INFO, "samba_dlz: failed to parse rdataset '%s'", rdatastr);
    1904           0 :                 talloc_free(rec);
    1905           0 :                 result = ISC_R_FAILURE;
    1906           0 :                 goto exit;
    1907             :         }
    1908             : 
    1909             :         /* find the DN of the record */
    1910           5 :         result = b9_find_name_dn(state, name, rec, &dn);
    1911           5 :         if (result != ISC_R_SUCCESS) {
    1912           0 :                 talloc_free(rec);
    1913           0 :                 goto exit;
    1914             :         }
    1915             : 
    1916             :         /* get any existing records */
    1917           5 :         werr = dns_common_lookup(state->samdb, rec, dn,
    1918             :                                  &recs, &num_recs, &tombstoned);
    1919           5 :         if (W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
    1920           1 :                 needs_add = true;
    1921           1 :                 werr = WERR_OK;
    1922             :         }
    1923           5 :         if (!W_ERROR_IS_OK(werr)) {
    1924           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s",
    1925             :                            ldb_dn_get_linearized(dn), win_errstr(werr));
    1926           0 :                 talloc_free(rec);
    1927           0 :                 result = ISC_R_FAILURE;
    1928           0 :                 goto exit;
    1929             :         }
    1930             : 
    1931           5 :         if (tombstoned) {
    1932             :                 /*
    1933             :                  * we need to keep the existing tombstone record
    1934             :                  * and ignore it
    1935             :                  */
    1936           1 :                 first = num_recs;
    1937             :         }
    1938             : 
    1939             :         /* there may be existing records. We need to see if this will
    1940             :          * replace a record or add to it
    1941             :          */
    1942           7 :         for (i=first; i < num_recs; i++) {
    1943           3 :                 if (b9_record_match(rec, &recs[i])) {
    1944           1 :                         break;
    1945             :                 }
    1946             :         }
    1947           5 :         if (i == UINT16_MAX) {
    1948           0 :                 state->log(ISC_LOG_ERROR,
    1949             :                            "samba_dlz: failed to find record to modify, and "
    1950             :                            "there are already %u dnsRecord values for %s",
    1951             :                            i, ldb_dn_get_linearized(dn));
    1952           0 :                 talloc_free(rec);
    1953           0 :                 result = ISC_R_FAILURE;
    1954           0 :                 goto exit;
    1955             :         }
    1956             : 
    1957           5 :         if (i == num_recs) {
    1958             :                 /* adding a new value */
    1959           4 :                 recs = talloc_realloc(rec, recs,
    1960             :                                       struct dnsp_DnssrvRpcRecord,
    1961             :                                       num_recs + 1);
    1962           4 :                 if (recs == NULL) {
    1963           0 :                         talloc_free(rec);
    1964           0 :                         result = ISC_R_NOMEMORY;
    1965           0 :                         goto exit;
    1966             :                 }
    1967           4 :                 num_recs++;
    1968             : 
    1969           4 :                 if (dns_name_is_static(recs, num_recs)) {
    1970           0 :                         rec->dwTimeStamp = 0;
    1971             :                 } else {
    1972           4 :                         rec->dwTimeStamp = unix_to_dns_timestamp(time(NULL));
    1973             :                 }
    1974             :         }
    1975             : 
    1976           5 :         recs[i] = *rec;
    1977             : 
    1978           5 :         if (!b9_set_session_info(state, name)) {
    1979           0 :                 talloc_free(rec);
    1980           0 :                 result = ISC_R_FAILURE;
    1981           0 :                 goto exit;
    1982             :         }
    1983             : 
    1984             :         /* modify the record */
    1985           5 :         werr = dns_common_replace(state->samdb, rec, dn,
    1986             :                                   needs_add,
    1987             :                                   state->soa_serial,
    1988             :                                   recs, num_recs);
    1989           5 :         b9_reset_session_info(state);
    1990           5 :         if (!W_ERROR_IS_OK(werr)) {
    1991           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to %s %s - %s",
    1992             :                            needs_add ? "add" : "modify",
    1993             :                            ldb_dn_get_linearized(dn), win_errstr(werr));
    1994           0 :                 talloc_free(rec);
    1995           0 :                 result = ISC_R_FAILURE;
    1996           0 :                 goto exit;
    1997             :         }
    1998             : 
    1999           5 :         state->log(ISC_LOG_INFO, "samba_dlz: added rdataset %s '%s'", name, rdatastr);
    2000             : 
    2001           5 :         talloc_free(rec);
    2002           5 : exit:
    2003           5 :         DNS_COMMON_LOG_OPERATION(
    2004             :                 isc_result_str(result),
    2005             :                 &start,
    2006             :                 NULL,
    2007             :                 name,
    2008             :                 rdatastr);
    2009           5 :         return result;
    2010             : }
    2011             : 
    2012             : /*
    2013             :   remove a rdataset
    2014             :  */
    2015           4 : _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, void *dbdata, void *version)
    2016             : {
    2017           4 :         struct timeval start = timeval_current();
    2018           4 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    2019             :         struct dnsp_DnssrvRpcRecord *rec;
    2020             :         struct ldb_dn *dn;
    2021           4 :         isc_result_t result = ISC_R_SUCCESS;
    2022           4 :         struct dnsp_DnssrvRpcRecord *recs = NULL;
    2023           4 :         uint16_t num_recs = 0;
    2024             :         uint16_t i;
    2025             :         WERROR werr;
    2026             : 
    2027           4 :         if (state->transaction_token != (void*)version) {
    2028           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version");
    2029           0 :                 result = ISC_R_FAILURE;
    2030           0 :                 goto exit;
    2031             :         }
    2032             : 
    2033           4 :         rec = talloc_zero(state, struct dnsp_DnssrvRpcRecord);
    2034           4 :         if (rec == NULL) {
    2035           0 :                 result = ISC_R_NOMEMORY;
    2036           0 :                 goto exit;
    2037             :         }
    2038             : 
    2039           4 :         if (!b9_parse(state, rdatastr, rec)) {
    2040           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse rdataset '%s'", rdatastr);
    2041           0 :                 talloc_free(rec);
    2042           0 :                 result = ISC_R_FAILURE;
    2043           0 :                 goto exit;
    2044             :         }
    2045             : 
    2046             :         /* find the DN of the record */
    2047           4 :         result = b9_find_name_dn(state, name, rec, &dn);
    2048           4 :         if (result != ISC_R_SUCCESS) {
    2049           0 :                 talloc_free(rec);
    2050           0 :                 goto exit;
    2051             :         }
    2052             : 
    2053             :         /* get the existing records */
    2054           4 :         werr = dns_common_lookup(state->samdb, rec, dn,
    2055             :                                  &recs, &num_recs, NULL);
    2056           4 :         if (!W_ERROR_IS_OK(werr)) {
    2057           1 :                 talloc_free(rec);
    2058           1 :                 result = ISC_R_NOTFOUND;
    2059           1 :                 goto exit;
    2060             :         }
    2061             : 
    2062           5 :         for (i=0; i < num_recs; i++) {
    2063           4 :                 if (b9_record_match(rec, &recs[i])) {
    2064           2 :                         recs[i] = (struct dnsp_DnssrvRpcRecord) {
    2065             :                                 .wType = DNS_TYPE_TOMBSTONE,
    2066             :                         };
    2067           2 :                         break;
    2068             :                 }
    2069             :         }
    2070           3 :         if (i == num_recs) {
    2071           1 :                 talloc_free(rec);
    2072           1 :                 result = ISC_R_NOTFOUND;
    2073           1 :                 goto exit;
    2074             :         }
    2075             : 
    2076           2 :         if (!b9_set_session_info(state, name)) {
    2077           0 :                 talloc_free(rec);
    2078           0 :                 result = ISC_R_FAILURE;
    2079           0 :                 goto exit;
    2080             :         }
    2081             : 
    2082             :         /* modify the record */
    2083           2 :         werr = dns_common_replace(state->samdb, rec, dn,
    2084             :                                   false,/* needs_add */
    2085             :                                   state->soa_serial,
    2086             :                                   recs, num_recs);
    2087           2 :         b9_reset_session_info(state);
    2088           2 :         if (!W_ERROR_IS_OK(werr)) {
    2089           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s",
    2090             :                            ldb_dn_get_linearized(dn), win_errstr(werr));
    2091           0 :                 talloc_free(rec);
    2092           0 :                 result = ISC_R_FAILURE;
    2093           0 :                 goto exit;
    2094             :         }
    2095             : 
    2096           2 :         state->log(ISC_LOG_INFO, "samba_dlz: subtracted rdataset %s '%s'", name, rdatastr);
    2097             : 
    2098           2 :         talloc_free(rec);
    2099           4 : exit:
    2100           4 :         DNS_COMMON_LOG_OPERATION(
    2101             :                 isc_result_str(result),
    2102             :                 &start,
    2103             :                 NULL,
    2104             :                 name,
    2105             :                 rdatastr);
    2106           4 :         return result;
    2107             : }
    2108             : 
    2109             : 
    2110             : /*
    2111             :   delete all records of the given type
    2112             :  */
    2113           3 : _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void *dbdata, void *version)
    2114             : {
    2115           3 :         struct timeval start = timeval_current();
    2116           3 :         struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
    2117             :         TALLOC_CTX *tmp_ctx;
    2118             :         struct ldb_dn *dn;
    2119           3 :         isc_result_t result = ISC_R_SUCCESS;
    2120             :         enum dns_record_type dns_type;
    2121           3 :         bool found = false;
    2122           3 :         struct dnsp_DnssrvRpcRecord *recs = NULL;
    2123           3 :         uint16_t num_recs = 0;
    2124           3 :         uint16_t ri = 0;
    2125             :         WERROR werr;
    2126             : 
    2127           3 :         if (state->transaction_token != (void*)version) {
    2128           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version");
    2129           0 :                 result = ISC_R_FAILURE;
    2130           0 :                 goto exit;
    2131             :         }
    2132             : 
    2133           3 :         if (!b9_dns_type(type, &dns_type)) {
    2134           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: bad dns type %s in delete", type);
    2135           0 :                 result = ISC_R_FAILURE;
    2136           0 :                 goto exit;
    2137             :         }
    2138             : 
    2139           3 :         tmp_ctx = talloc_new(state);
    2140             : 
    2141             :         /* find the DN of the record */
    2142           3 :         result = b9_find_name_dn(state, name, tmp_ctx, &dn);
    2143           3 :         if (result != ISC_R_SUCCESS) {
    2144           0 :                 talloc_free(tmp_ctx);
    2145           0 :                 goto exit;
    2146             :         }
    2147             : 
    2148             :         /* get the existing records */
    2149           3 :         werr = dns_common_lookup(state->samdb, tmp_ctx, dn,
    2150             :                                  &recs, &num_recs, NULL);
    2151           3 :         if (!W_ERROR_IS_OK(werr)) {
    2152           1 :                 talloc_free(tmp_ctx);
    2153           1 :                 result = ISC_R_NOTFOUND;
    2154           1 :                 goto exit;
    2155             :         }
    2156             : 
    2157           6 :         for (ri=0; ri < num_recs; ri++) {
    2158           4 :                 if (dns_type != recs[ri].wType) {
    2159           2 :                         continue;
    2160             :                 }
    2161             : 
    2162           2 :                 found = true;
    2163           2 :                 recs[ri] = (struct dnsp_DnssrvRpcRecord) {
    2164             :                         .wType = DNS_TYPE_TOMBSTONE,
    2165             :                 };
    2166             :         }
    2167             : 
    2168           2 :         if (!found) {
    2169           1 :                 talloc_free(tmp_ctx);
    2170           1 :                 result = ISC_R_FAILURE;
    2171           1 :                 goto exit;
    2172             :         }
    2173             : 
    2174           1 :         if (!b9_set_session_info(state, name)) {
    2175           0 :                 talloc_free(tmp_ctx);
    2176           0 :                 result = ISC_R_FAILURE;
    2177           0 :                 goto exit;
    2178             :         }
    2179             : 
    2180             :         /* modify the record */
    2181           1 :         werr = dns_common_replace(state->samdb, tmp_ctx, dn,
    2182             :                                   false,/* needs_add */
    2183             :                                   state->soa_serial,
    2184             :                                   recs, num_recs);
    2185           1 :         b9_reset_session_info(state);
    2186           1 :         if (!W_ERROR_IS_OK(werr)) {
    2187           0 :                 state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s",
    2188             :                            ldb_dn_get_linearized(dn), win_errstr(werr));
    2189           0 :                 talloc_free(tmp_ctx);
    2190           0 :                 result = ISC_R_FAILURE;
    2191           0 :                 goto exit;
    2192             :         }
    2193             : 
    2194           1 :         state->log(ISC_LOG_INFO, "samba_dlz: deleted rdataset %s of type %s", name, type);
    2195             : 
    2196           1 :         talloc_free(tmp_ctx);
    2197           3 : exit:
    2198           3 :         DNS_COMMON_LOG_OPERATION(
    2199             :                 isc_result_str(result),
    2200             :                 &start,
    2201             :                 NULL,
    2202             :                 name,
    2203             :                 type);
    2204           3 :         return result;
    2205             : }

Generated by: LCOV version 1.13