LCOV - code coverage report
Current view: top level - source4/dns_server - dlz_bind9.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 629 1125 55.9 %
Date: 2024-05-31 13:13:24 Functions: 34 36 94.4 %

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

Generated by: LCOV version 1.14