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

Generated by: LCOV version 1.14