1 /*
2  * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #if defined(_WIN32)
18 #include <process.h>
19 #define usleep(X) Sleep(((X)+999)/1000)
20 #else
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/resource.h>
27 #endif
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 
32 #include "mDNSEmbeddedAPI.h"
33 #include "DNSCommon.h"
34 #include "uDNS.h"
35 #include "uds_daemon.h"
36 #include "dns_sd_internal.h"
37 
38 // Apple-specific functionality, not required for other platforms
39 #if APPLE_OSX_mDNSResponder
40 #include <os/log.h>
41 #include <sys/ucred.h>
42 #ifndef PID_FILE
43 #define NO_PID_FILE // We need to signal that this platform has no PID file, and not just that we are taking the default
44 #endif
45 #endif
46 
47 #ifdef LOCAL_PEEREPID
48 #include <sys/un.h>         // for LOCAL_PEEREPID
49 #include <sys/socket.h>     // for getsockopt
50 #include <sys/proc_info.h>  // for struct proc_bsdshortinfo
51 #include <libproc.h>        // for proc_pidinfo()
52 #endif //LOCAL_PEEREPID
53 
54 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
55 #include "D2D.h"
56 #endif
57 
58 #if APPLE_OSX_mDNSResponder
59 #include "BLE.h"
60 #endif
61 
62 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
63 #include "mDNSMacOSX.h"
64 #include <os/feature_private.h>
65 #endif
66 
67 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
68 #include <bsm/libbsm.h>
69 #endif
70 
71 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
72 #include "QuerierSupport.h"
73 #endif
74 
75 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
76 #include "mdns_tlv.h"
77 #endif
78 
79 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
80 #include "dnssec_v2.h"
81 #endif
82 
83 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
84 #include "dnssd_server.h"
85 #endif
86 
87 // User IDs 0-500 are system-wide processes, not actual users in the usual sense
88 // User IDs for real user accounts start at 501 and count up from there
89 #define SystemUID(X) ((X) <= 500)
90 
91 // ***************************************************************************
92 #if COMPILER_LIKES_PRAGMA_MARK
93 #pragma mark -
94 #pragma mark - Globals
95 #endif
96 
97 // globals
98 mDNSexport mDNS mDNSStorage;
99 mDNSexport const char ProgramName[] = "mDNSResponder";
100 
101 #if defined(USE_TCP_LOOPBACK)
102 static char* boundPath = NULL;
103 #else
104 static char* boundPath = MDNS_UDS_SERVERPATH;
105 #endif
106 #if DEBUG
107 #define MDNS_UDS_SERVERPATH_DEBUG "/var/tmp/mDNSResponder"
108 #endif
109 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
110 static request_state *all_requests = NULL;
111 #ifdef LOCAL_PEEREPID
112 struct proc_bsdshortinfo proc;
113 #endif //LOCAL_PEEREPID
114 mDNSlocal void set_peer_pid(request_state *request);
115 mDNSlocal void LogMcastClientInfo(request_state *req);
116 mDNSlocal void GetMcastClients(request_state *req);
117 static mDNSu32 mcount;     // tracks the current active mcast operations for McastLogging
118 static mDNSu32 i_mcount;   // sets mcount when McastLogging is enabled(PROF signal is sent)
119 static mDNSu32 n_mrecords; // tracks the current active mcast records for McastLogging
120 static mDNSu32 n_mquests;  // tracks the current active mcast questions for McastLogging
121 
122 
123 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
124 mDNSu32 curr_num_regservices = 0;
125 mDNSu32 max_num_regservices = 0;
126 #endif
127 
128 // Note asymmetry here between registration and browsing.
129 // For service registrations we only automatically register in domains that explicitly appear in local configuration data
130 // (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
131 // For service browsing we also learn automatic browsing domains from the network, so for that case we have:
132 // 1. SCPrefBrowseDomains (local configuration data)
133 // 2. LocalDomainEnumRecords (locally-generated local-only PTR records -- equivalent to slElem->AuthRecs in uDNS.c)
134 // 3. AutoBrowseDomains, which is populated by tracking add/rmv events in AutomaticBrowseDomainChange, the callback function for our mDNS_GetDomains call.
135 // By creating and removing our own LocalDomainEnumRecords, we trigger AutomaticBrowseDomainChange callbacks just like domains learned from the network would.
136 
137 mDNSexport DNameListElem *AutoRegistrationDomains;  // Domains where we automatically register for empty-string registrations
138 
139 static DNameListElem *SCPrefBrowseDomains;          // List of automatic browsing domains read from SCPreferences for "empty string" browsing
140 static ARListElem    *LocalDomainEnumRecords;       // List of locally-generated PTR records to augment those we learn from the network
141 mDNSexport DNameListElem *AutoBrowseDomains;        // List created from those local-only PTR records plus records we get from the network
142 
143 #define MSG_PAD_BYTES 5     // pad message buffer (read from client) with n zero'd bytes to guarantee
144                             // n get_string() calls w/o buffer overrun
145 // initialization, setup/teardown functions
146 
147 // If a platform specifies its own PID file name, we use that
148 #ifndef PID_FILE
149 #define PID_FILE "/var/run/mDNSResponder.pid"
150 #endif
151 
152 // ***************************************************************************
153 #if COMPILER_LIKES_PRAGMA_MARK
154 #pragma mark -
155 #pragma mark - General Utility Functions
156 #endif
157 
GetNewRequestID(void)158 mDNSlocal mDNSu32 GetNewRequestID(void)
159 {
160 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
161     return dnssd_server_get_new_request_id();
162 #else
163     static mDNSu32 s_last_id = 0;
164     return ++s_last_id;
165 #endif
166 }
167 
FatalError(char * errmsg)168 mDNSlocal void FatalError(char *errmsg)
169 {
170     LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
171     abort();
172 }
173 
dnssd_htonl(mDNSu32 l)174 mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
175 {
176     mDNSu32 ret;
177     char *data = (char*) &ret;
178     put_uint32(l, &data);
179     return ret;
180 }
181 
182 // hack to search-replace perror's to LogMsg's
my_perror(char * errmsg)183 mDNSlocal void my_perror(char *errmsg)
184 {
185     LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno));
186 }
187 
188 // Throttled version of my_perror: Logs once every 250 msgs
my_throttled_perror(char * err_msg)189 mDNSlocal void my_throttled_perror(char *err_msg)
190 {
191     static int uds_throttle_count = 0;
192     if ((uds_throttle_count++ % 250) == 0)
193         my_perror(err_msg);
194 }
195 
196 // LogMcastQuestion/LogMcastQ should be called after the DNSQuestion struct is initialized(especially for q->TargetQID)
197 // Hence all calls are made after mDNS_StartQuery()/mDNS_StopQuery()/mDNS_StopBrowse() is called.
LogMcastQuestion(const DNSQuestion * const q,request_state * req,q_state status)198 mDNSlocal void LogMcastQuestion(const DNSQuestion *const q, request_state *req, q_state status)
199 {
200     if (mDNSOpaque16IsZero(q->TargetQID)) // Check for Mcast Query
201     {
202         mDNSBool mflag = mDNSfalse;
203         if (status == q_start)
204         {
205             if (++mcount == 1)
206                 mflag = mDNStrue;
207         }
208         else
209         {
210             mcount--;
211         }
212         LogMcast("%s: %##s  (%s) (%s)  Client(%d)[%s]", status ? "+Question" : "-Question", q->qname.c, DNSTypeName(q->qtype),
213                  q->InterfaceID == mDNSInterface_LocalOnly ? "lo" :
214                  q->InterfaceID == mDNSInterface_P2P ? "p2p" :
215                  q->InterfaceID == mDNSInterface_BLE ? "BLE" :
216                  q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(&mDNSStorage, q->InterfaceID),
217                  req->process_id, req->pid_name);
218         LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
219     }
220     return;
221 }
222 
223 // LogMcastService/LogMcastS should be called after the AuthRecord struct is initialized
224 // Hence all calls are made after mDNS_Register()/ just before mDNS_Deregister()
LogMcastService(const AuthRecord * const ar,request_state * req,reg_state status)225 mDNSlocal void LogMcastService(const AuthRecord *const ar, request_state *req, reg_state status)
226 {
227     if (!AuthRecord_uDNS(ar)) // Check for Mcast Service
228     {
229         mDNSBool mflag = mDNSfalse;
230         if (status == reg_start)
231         {
232             if (++mcount == 1)
233                 mflag = mDNStrue;
234         }
235         else
236         {
237             mcount--;
238         }
239         LogMcast("%s: %##s  (%s)  (%s)  Client(%d)[%s]", status ? "+Service" : "-Service", ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype),
240                  ar->resrec.InterfaceID == mDNSInterface_LocalOnly ? "lo" :
241                  ar->resrec.InterfaceID == mDNSInterface_P2P ? "p2p" :
242                  ar->resrec.InterfaceID == mDNSInterface_BLE ? "BLE" :
243                  ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID),
244                  req->process_id, req->pid_name);
245         LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
246     }
247     return;
248 }
249 
250 // For complete Mcast State Log, pass mDNStrue to mstatelog in LogMcastStateInfo()
LogMcastStateInfo(mDNSBool mflag,mDNSBool start,mDNSBool mstatelog)251 mDNSexport void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog)
252 {
253     mDNS *const m = &mDNSStorage;
254     if (!mstatelog)
255     {
256         if (!all_requests)
257         {
258             LogMcastNoIdent("<None>");
259         }
260         else
261         {
262             request_state *req, *r;
263             for (req = all_requests; req; req=req->next)
264             {
265                 if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
266                 {
267                     for (r = all_requests; r && r != req; r=r->next)
268                         if (r == req->primary)
269                             goto foundpar;
270                 }
271                 // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
272                 GetMcastClients(req);
273     foundpar:;
274             }
275             LogMcastNoIdent("--- MCAST RECORDS COUNT[%d] MCAST QUESTIONS COUNT[%d] ---", n_mrecords, n_mquests);
276             n_mrecords = n_mquests = 0; // Reset the values
277         }
278     }
279     else
280     {
281         static mDNSu32 i_mpktnum;
282         i_mcount = 0;
283         if (start)
284             mcount = 0;
285         // mcount is initialized to 0 when the PROF signal is sent since mcount could have
286         // wrong value if MulticastLogging is disabled and then re-enabled
287         LogMcastNoIdent("--- START MCAST STATE LOG ---");
288         if (!all_requests)
289         {
290             mcount = 0;
291             LogMcastNoIdent("<None>");
292         }
293         else
294         {
295             request_state *req, *r;
296             for (req = all_requests; req; req=req->next)
297             {
298                 if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
299                 {
300                     for (r = all_requests; r && r != req; r=r->next)
301                         if (r == req->primary)
302                             goto foundparent;
303                     LogMcastNoIdent("%3d: Orphan operation; parent not found in request list", req->sd);
304                 }
305                 // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
306                 LogMcastClientInfo(req);
307     foundparent:;
308             }
309             if(!mcount) // To initially set mcount
310                 mcount = i_mcount;
311         }
312         if (mcount == 0)
313         {
314             i_mpktnum = m->MPktNum;
315             LogMcastNoIdent("--- MCOUNT[%d]: IMPKTNUM[%d] ---", mcount, i_mpktnum);
316         }
317         if (mflag)
318             LogMcastNoIdent("--- MCOUNT[%d]: CMPKTNUM[%d] - IMPKTNUM[%d] = [%d]PKTS ---", mcount, m->MPktNum, i_mpktnum, (m->MPktNum - i_mpktnum));
319         LogMcastNoIdent("--- END MCAST STATE LOG ---");
320     }
321 }
322 
abort_request(request_state * req)323 mDNSlocal void abort_request(request_state *req)
324 {
325     if (req->terminate == (req_termination_fn) ~0)
326     {
327         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
328                   "[R%d] abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req->request_id, req, req->terminate);
329         return;
330     }
331 
332     // First stop whatever mDNSCore operation we were doing
333     // If this is actually a shared connection operation, then its req->terminate function will scan
334     // the all_requests list and terminate any subbordinate operations sharing this file descriptor
335     if (req->terminate) req->terminate(req);
336 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
337     if (req->custom_service_id != 0)
338     {
339         Querier_DeregisterCustomDNSService(req->custom_service_id);
340         req->custom_service_id = 0;
341     }
342 #endif
343 
344     if (!dnssd_SocketValid(req->sd))
345     {
346         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
347                   "[R%d] abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req->request_id, req, req->sd);
348         return;
349     }
350 
351     // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
352     if (!req->primary)
353     {
354         if (req->errsd != req->sd)
355         {
356             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
357                       "[R%d] Removing FD %d and closing errsd %d", req->request_id, req->sd, req->errsd);
358         }
359         else
360         {
361             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
362                       "[R%d] Removing FD %d", req->request_id, req->sd);
363         }
364         udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data);       // Note: This also closes file descriptor req->sd for us
365         if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
366 
367         while (req->replies)    // free pending replies
368         {
369             reply_state *ptr = req->replies;
370             req->replies = req->replies->next;
371             freeL("reply_state (abort)", ptr);
372         }
373     }
374 
375     // Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
376 #if MDNS_MALLOC_DEBUGGING
377     // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MDNS_MALLOC_DEBUGGING uses
378     // for detecting when the memory for an object is inadvertently freed while the object is still on some list
379 #ifdef WIN32
380 #error This will not work on Windows, look at IsValidSocket in mDNSShared/CommonServices.h to see why
381 #endif
382     req->sd = req->errsd = -2;
383 #else
384     req->sd = req->errsd = dnssd_InvalidSocket;
385 #endif
386     // We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request
387     req->terminate = (req_termination_fn) ~0;
388 }
389 
390 #if DEBUG
SetDebugBoundPath(void)391 mDNSexport void SetDebugBoundPath(void)
392 {
393 #if !defined(USE_TCP_LOOPBACK)
394     boundPath = MDNS_UDS_SERVERPATH_DEBUG;
395 #endif
396 }
397 
IsDebugSocketInUse(void)398 mDNSexport int IsDebugSocketInUse(void)
399 {
400 #if !defined(USE_TCP_LOOPBACK)
401     return !strcmp(boundPath, MDNS_UDS_SERVERPATH_DEBUG);
402 #else
403     return mDNSfalse;
404 #endif
405 }
406 #endif
407 
AbortUnlinkAndFree(request_state * req)408 mDNSlocal void AbortUnlinkAndFree(request_state *req)
409 {
410     request_state **p = &all_requests;
411     abort_request(req);
412     while (*p && *p != req) p=&(*p)->next;
413     if (*p)
414     {
415         *p = req->next;
416 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
417         if (req->trust)
418         {
419             void * context = mdns_trust_get_context(req->trust);
420             mdns_trust_set_context(req->trust, NULL);
421             if (context) freeL("context/AbortUnlinkAndFree", context);
422             mdns_trust_forget(&req->trust);
423         }
424 #endif
425         freeL("request_state/AbortUnlinkAndFree", req);
426     }
427     else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
428 }
429 
create_reply(const reply_op_t op,const size_t datalen,request_state * const request)430 mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
431 {
432     reply_state *reply;
433 
434     if ((unsigned)datalen < sizeof(reply_hdr))
435     {
436         LogMsg("ERROR: create_reply - data length less than length of required fields");
437         return NULL;
438     }
439 
440     reply = (reply_state *) callocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
441     if (!reply) FatalError("ERROR: calloc");
442 
443     reply->next     = mDNSNULL;
444     reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
445     reply->nwriten  = 0;
446 
447     reply->mhdr->version        = VERSION;
448     reply->mhdr->datalen        = (mDNSu32)datalen;
449     reply->mhdr->ipc_flags      = 0;
450     reply->mhdr->op             = op;
451     reply->mhdr->client_context = request->hdr.client_context;
452     reply->mhdr->reg_index      = 0;
453 
454     return reply;
455 }
456 
457 // Append a reply to the list in a request object
458 // If our request is sharing a connection, then we append our reply_state onto the primary's list
459 // If the request does not want asynchronous replies, then the reply is freed instead of being appended to any list.
append_reply(request_state * req,reply_state * rep)460 mDNSlocal void append_reply(request_state *req, reply_state *rep)
461 {
462     request_state *r;
463     reply_state **ptr;
464 
465     if (req->no_reply)
466     {
467         freeL("reply_state/append_reply", rep);
468         return;
469     }
470 
471     r = req->primary ? req->primary : req;
472     ptr = &r->replies;
473     while (*ptr) ptr = &(*ptr)->next;
474     *ptr = rep;
475     rep->next = NULL;
476 }
477 
478 // Generates a response message giving name, type, domain, plus interface index,
479 // suitable for a browse result or service registration result.
480 // On successful completion rep is set to point to a malloc'd reply_state struct
GenerateNTDResponse(const domainname * const servicename,const mDNSInterfaceID id,request_state * const request,reply_state ** const rep,reply_op_t op,DNSServiceFlags flags,mStatus err)481 mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
482                                       request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
483 {
484     domainlabel name;
485     domainname type, dom;
486     *rep = NULL;
487     if (servicename && !DeconstructServiceName(servicename, &name, &type, &dom))
488         return kDNSServiceErr_Invalid;
489     else
490     {
491         char namestr[MAX_DOMAIN_LABEL+1];
492         char typestr[MAX_ESCAPED_DOMAIN_NAME];
493         char domstr [MAX_ESCAPED_DOMAIN_NAME];
494         int len;
495         char *data;
496 
497         if (servicename)
498         {
499             ConvertDomainLabelToCString_unescaped(&name, namestr);
500             ConvertDomainNameToCString(&type, typestr);
501             ConvertDomainNameToCString(&dom, domstr);
502         }
503         else
504         {
505             namestr[0] = 0;
506             typestr[0] = 0;
507             domstr[0] = 0;
508         }
509 
510         // Calculate reply data length
511         len = sizeof(DNSServiceFlags);
512         len += sizeof(mDNSu32);  // if index
513         len += sizeof(DNSServiceErrorType);
514         len += (int) (strlen(namestr) + 1);
515         len += (int) (strlen(typestr) + 1);
516         len += (int) (strlen(domstr) + 1);
517 
518         // Build reply header
519         *rep = create_reply(op, len, request);
520         (*rep)->rhdr->flags = dnssd_htonl(flags);
521         (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
522         (*rep)->rhdr->error = dnssd_htonl(err);
523 
524         // Build reply body
525         data = (char *)&(*rep)->rhdr[1];
526         put_string(namestr, &data);
527         put_string(typestr, &data);
528         put_string(domstr, &data);
529 
530         return mStatus_NoError;
531     }
532 }
533 
GenerateBrowseReply(const domainname * const servicename,const mDNSInterfaceID id,request_state * const request,reply_state ** const rep,reply_op_t op,DNSServiceFlags flags,mStatus err)534 mDNSlocal void GenerateBrowseReply(const domainname *const servicename, const mDNSInterfaceID id,
535                                               request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
536 {
537     char namestr[MAX_DOMAIN_LABEL+1];
538     char typestr[MAX_ESCAPED_DOMAIN_NAME];
539     static const char domstr[] = ".";
540     int len;
541     char *data;
542 
543     *rep = NULL;
544 
545     if (servicename)
546     {
547         // 1. Put first label in namestr
548         ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
549 
550         // 2. Put second label and "local" into typestr
551         mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
552     }
553     else
554     {
555         namestr[0] = 0;
556         typestr[0] = 0;
557     }
558 
559     // Calculate reply data length
560     len = sizeof(DNSServiceFlags);
561     len += sizeof(mDNSu32);  // if index
562     len += sizeof(DNSServiceErrorType);
563     len += (int) (strlen(namestr) + 1);
564     len += (int) (strlen(typestr) + 1);
565     len += (int) (strlen(domstr) + 1);
566 
567     // Build reply header
568     *rep = create_reply(op, len, request);
569     (*rep)->rhdr->flags = dnssd_htonl(flags);
570     (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
571     (*rep)->rhdr->error = dnssd_htonl(err);
572 
573     // Build reply body
574     data = (char *)&(*rep)->rhdr[1];
575     put_string(namestr, &data);
576     put_string(typestr, &data);
577     put_string(domstr, &data);
578 }
579 
580 // Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
581 // Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
582 // (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
read_rr_from_ipc_msg(request_state * request,int GetTTL,int validate_flags)583 mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
584 {
585     DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
586     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
587     char name[MAX_ESCAPED_DOMAIN_NAME];
588     int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
589     mDNSu16 type    = get_uint16(&request->msgptr, request->msgend);
590     mDNSu16     class   = get_uint16(&request->msgptr, request->msgend);
591     mDNSu16 rdlen   = get_uint16(&request->msgptr, request->msgend);
592     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata (&request->msgptr, request->msgend, rdlen);
593     mDNSu32 ttl   = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
594     size_t rdcapacity;
595     AuthRecord *rr;
596     mDNSInterfaceID InterfaceID;
597     AuthRecType artype;
598     mDNSu8 recordType;
599 
600     request->flags = flags;
601     request->interfaceIndex = interfaceIndex;
602 
603     if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
604 
605     if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
606 
607     if (validate_flags &&
608         !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
609         !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique) &&
610         !((flags & kDNSServiceFlagsKnownUnique) == kDNSServiceFlagsKnownUnique))
611     {
612         LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)");
613         return NULL;
614     }
615     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
616 
617     // The registration is scoped to a specific interface index, but the interface is not currently on our list.
618     if ((InterfaceID == mDNSInterface_Any) && (interfaceIndex != kDNSServiceInterfaceIndexAny))
619     {
620         // On Apple platforms, an interface's mDNSInterfaceID is equal to its index. Using an interface index that isn't
621         // currently valid will cause the registration to take place as soon as it becomes valid. On other platforms,
622         // mDNSInterfaceID is actually a pointer to a platform-specific interface object, but we don't know what the pointer
623         // for the interface index will be ahead of time. For now, just return NULL to indicate an error condition since the
624         // interface index is invalid. Otherwise, the registration would be performed on all interfaces.
625 #if APPLE_OSX_mDNSResponder
626         InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
627 #else
628         return NULL;
629 #endif
630     }
631     rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
632     rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(*rr) - sizeof(RDataBody) + rdcapacity);
633     if (!rr) FatalError("ERROR: calloc");
634 
635     if (InterfaceID == mDNSInterface_LocalOnly)
636         artype = AuthRecordLocalOnly;
637     else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
638         artype = AuthRecordP2P;
639     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P)
640             && (flags & kDNSServiceFlagsIncludeAWDL))
641         artype = AuthRecordAnyIncludeAWDLandP2P;
642     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P))
643         artype = AuthRecordAnyIncludeP2P;
644     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeAWDL))
645         artype = AuthRecordAnyIncludeAWDL;
646     else
647         artype = AuthRecordAny;
648 
649     if (flags & kDNSServiceFlagsShared)
650         recordType = (mDNSu8) kDNSRecordTypeShared;
651     else if (flags & kDNSServiceFlagsKnownUnique)
652         recordType = (mDNSu8) kDNSRecordTypeKnownUnique;
653     else
654         recordType = (mDNSu8) kDNSRecordTypeUnique;
655 
656     mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0, recordType, artype, mDNSNULL, mDNSNULL);
657 
658     if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
659     {
660         LogMsg("ERROR: bad name: %s", name);
661         freeL("AuthRecord/read_rr_from_ipc_msg", rr);
662         return NULL;
663     }
664 
665     if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
666     rr->resrec.rrclass = class;
667     rr->resrec.rdlength = rdlen;
668     rr->resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
669     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr->resrec, rdlen))
670     {
671         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
672             "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
673             request->request_id, DM_NAME_PARAM(rr->resrec.name), DNSTypeName(type));
674         freeL("AuthRecord/read_rr_from_ipc_msg", rr);
675         return NULL;
676     }
677     if (GetTTL) rr->resrec.rroriginalttl = ttl;
678     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
679     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
680     return rr;
681 }
682 
build_domainname_from_strings(domainname * srv,char * name,char * regtype,char * domain)683 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
684 {
685     domainlabel n;
686     domainname d, t;
687 
688     if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
689     if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
690     if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
691     if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
692     return 0;
693 }
694 
send_all(dnssd_sock_t s,const char * ptr,int len)695 mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
696 {
697     const ssize_t n = send(s, ptr, len, 0);
698     // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
699     // (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
700     // If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
701     if (n < len)
702     {
703         LogMsg("ERROR: send_all(%d) wrote %ld of %d errno %d (%s)",
704             s, (long)n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
705     }
706 }
707 
708 #if 0
709 mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms)
710 {
711     const DNameListElem   *delem = mDNSNULL;
712     int bestDelta   = -1;                           // the delta of the best match, lower is better
713     int dLabels     = 0;
714     mDNSBool allow       = mDNSfalse;
715 
716     if (SystemUID(request->uid)) return mDNStrue;
717 
718     dLabels = CountLabels(d);
719     for (delem = doms; delem; delem = delem->next)
720     {
721         if (delem->uid)
722         {
723             int delemLabels = CountLabels(&delem->name);
724             int delta       = dLabels - delemLabels;
725             if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta)))
726             {
727                 bestDelta = delta;
728                 allow = (allow || (delem->uid == request->uid));
729             }
730         }
731     }
732 
733     return bestDelta == -1 ? mDNStrue : allow;
734 }
735 #endif
736 
737 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
SetupAuditTokenForRequest(request_state * request)738 mDNSlocal void SetupAuditTokenForRequest(request_state *request)
739 {
740 
741     pid_t audit_pid = audit_token_to_pid(request->audit_token);
742     if (audit_pid == 0)
743     {
744 #if !defined(LOCAL_PEERTOKEN)
745 #define LOCAL_PEERTOKEN         0x006           /* retrieve peer audit token */
746 #endif
747         socklen_t len = sizeof(audit_token_t);
748         int ret = getsockopt(request->sd, SOL_LOCAL, LOCAL_PEERTOKEN, &request->audit_token, &len);
749         if (ret != 0)
750         {
751             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
752                       "SetupAuditTokenForRequest: No audit_token using LOCAL_PEERTOKEN (%s PID %d) for op %d ret(%d)",
753                       request->pid_name, request->process_id, request->hdr.op, ret);
754         }
755     }
756 }
757 #endif
758 
759 // ***************************************************************************
760 #if COMPILER_LIKES_PRAGMA_MARK
761 #pragma mark -
762 #pragma mark - external helpers
763 #endif
764 
765 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_start_advertising_helper(service_instance * const instance)766 mDNSlocal void external_start_advertising_helper(service_instance *const instance)
767 {
768     AuthRecord *st = instance->subtypes;
769     ExtraResourceRecord *e;
770     int i;
771     const pid_t requestPID = instance->request->process_id;
772 
773     if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
774     {
775         LogInfo("external_start_advertising_helper: Not registering service with port number zero");
776         return;
777     }
778 
779     if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
780 
781     for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
782         external_start_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
783 
784     external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
785     external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
786     external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
787 
788     for (e = instance->srs.Extras; e; e = e->next)
789         external_start_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
790 
791     instance->external_advertise = mDNStrue;
792 }
793 
external_stop_advertising_helper(service_instance * const instance)794 mDNSlocal void external_stop_advertising_helper(service_instance *const instance)
795 {
796     AuthRecord *st = instance->subtypes;
797     ExtraResourceRecord *e;
798     int i;
799 
800     if (!instance->external_advertise) return;
801 
802     LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
803 
804     if (instance->request)
805     {
806         const pid_t requestPID = instance->request->process_id;
807         for (i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
808         {
809             external_stop_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
810         }
811 
812         external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
813         external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
814         external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
815 
816         for (e = instance->srs.Extras; e; e = e->next)
817         {
818             external_stop_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
819         }
820     }
821 
822     instance->external_advertise = mDNSfalse;
823 }
824 #endif  // MDNSRESPONDER_SUPPORTS(APPLE, D2D)
825 
826 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
_get_trust_results_dispatch_queue(void)827 mDNSlocal dispatch_queue_t _get_trust_results_dispatch_queue(void)
828 {
829     static dispatch_once_t  once    = 0;
830     static dispatch_queue_t queue   = NULL;
831 
832     dispatch_once(&once, ^{
833         dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
834         queue = dispatch_queue_create("com.apple.mDNSResponder.trust_results-queue", attr);
835     });
836     return queue;
837 }
838 #endif
839 
840 // ***************************************************************************
841 #if COMPILER_LIKES_PRAGMA_MARK
842 #pragma mark -
843 #pragma mark - DNSServiceRegister
844 #endif
845 
FreeExtraRR(mDNS * const m,AuthRecord * const rr,mStatus result)846 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
847 {
848     ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
849     (void)m;  // Unused
850 
851     if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
852 
853     LogInfo("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
854 
855     if (rr->resrec.rdata != &rr->rdatastorage)
856         freeL("Extra RData", rr->resrec.rdata);
857     freeL("ExtraResourceRecord/FreeExtraRR", extra);
858 }
859 
unlink_and_free_service_instance(service_instance * srv)860 mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
861 {
862     ExtraResourceRecord *e = srv->srs.Extras, *tmp;
863 
864 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
865     external_stop_advertising_helper(srv);
866 #endif
867 
868     // clear pointers from parent struct
869     if (srv->request)
870     {
871         service_instance **p = &srv->request->u.servicereg.instances;
872         while (*p)
873         {
874             if (*p == srv) { *p = (*p)->next; break; }
875             p = &(*p)->next;
876         }
877     }
878 
879     while (e)
880     {
881         e->r.RecordContext = e;
882         tmp = e;
883         e = e->next;
884         FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
885     }
886 
887     if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
888         freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
889 
890     if (srv->subtypes)
891     {
892         freeL("ServiceSubTypes", srv->subtypes);
893         srv->subtypes = NULL;
894     }
895     freeL("service_instance", srv);
896 }
897 
898 // Count how many other service records we have locally with the same name, but different rdata.
899 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
900 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
CountPeerRegistrations(ServiceRecordSet * const srs)901 mDNSexport int CountPeerRegistrations(ServiceRecordSet *const srs)
902 {
903     int count = 0;
904     ResourceRecord *r = &srs->RR_SRV.resrec;
905     AuthRecord *rr;
906 
907     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
908         if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
909             count++;
910 
911     verbosedebugf("%d peer registrations for %##s", count, r->name->c);
912     return(count);
913 }
914 
CountExistingRegistrations(domainname * srv,mDNSIPPort port)915 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
916 {
917     int count = 0;
918     AuthRecord *rr;
919     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
920         if (rr->resrec.rrtype == kDNSType_SRV &&
921             mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
922             SameDomainName(rr->resrec.name, srv))
923             count++;
924     return(count);
925 }
926 
SendServiceRemovalNotification(ServiceRecordSet * const srs)927 mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
928 {
929     reply_state *rep;
930     service_instance *instance = srs->ServiceContext;
931     if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
932         LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
933     else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; }
934 }
935 
936 // service registration callback performs three duties - frees memory for deregistered services,
937 // handles name conflicts, and delivers completed registration information to the client
regservice_callback(mDNS * const m,ServiceRecordSet * const srs,mStatus result)938 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
939 {
940     mStatus err;
941     mDNSBool SuppressError = mDNSfalse;
942     service_instance *instance;
943     reply_state         *rep;
944     (void)m; // Unused
945 
946     if (!srs)
947     {
948         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs is NULL %d", result);
949         return;
950     }
951 
952     instance = srs->ServiceContext;
953     if (!instance)
954     {
955         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs->ServiceContext is NULL %d", result);
956         return;
957     }
958 
959     // don't send errors up to client for wide-area, empty-string registrations
960     if (instance->request &&
961         instance->request->u.servicereg.default_domain &&
962         !instance->default_local)
963         SuppressError = mDNStrue;
964 
965     if (mDNS_LoggingEnabled)
966     {
967         const char *result_description;
968         char description[32]; // 32-byte is enough for holding "suppressed error -2147483648\0"
969         mDNSu32 request_id = instance->request ? instance->request->request_id : 0;
970         switch (result) {
971             case mStatus_NoError:
972                 result_description = "REGISTERED";
973                 break;
974             case mStatus_MemFree:
975                 result_description = "DEREGISTERED";
976                 break;
977             case mStatus_NameConflict:
978                 result_description = "NAME CONFLICT";
979                 break;
980             default:
981                 mDNS_snprintf(description, sizeof(description), "%s %d", SuppressError ? "suppressed error" : "CALLBACK", result);
982                 result_description = description;
983                 break;
984         }
985         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegister(" PRI_DM_NAME ", %u) %s",
986                   request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name), mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result_description);
987     }
988 
989     if (!instance->request && result != mStatus_MemFree)
990     {
991         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: instance->request is NULL %d", result);
992         return;
993     }
994 
995     if (result == mStatus_NoError)
996     {
997         if (instance->request->u.servicereg.allowremotequery)
998         {
999             ExtraResourceRecord *e;
1000             srs->RR_ADV.AllowRemoteQuery = mDNStrue;
1001             srs->RR_PTR.AllowRemoteQuery = mDNStrue;
1002             srs->RR_SRV.AllowRemoteQuery = mDNStrue;
1003             srs->RR_TXT.AllowRemoteQuery = mDNStrue;
1004             for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
1005         }
1006 
1007         if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1008             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1009         else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1010 
1011 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1012         if (callExternalHelpers(instance->request->u.servicereg.InterfaceID, &instance->domain, instance->request->flags))
1013         {
1014             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] regservice_callback: calling external_start_advertising_helper()", instance->request->request_id);
1015             external_start_advertising_helper(instance);
1016         }
1017 #endif
1018         if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
1019             RecordUpdatedNiceLabel(0);   // Successfully got new name, tell user immediately
1020     }
1021     else if (result == mStatus_MemFree)
1022     {
1023 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
1024         curr_num_regservices--;
1025 #endif
1026         if (instance->request && instance->renameonmemfree)
1027         {
1028 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1029             external_stop_advertising_helper(instance);
1030 #endif
1031             instance->renameonmemfree = 0;
1032             err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
1033             if (err)
1034                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] ERROR: regservice_callback - RenameAndReregisterService returned %d", instance->request->request_id, err);
1035             // error should never happen - safest to log and continue
1036         }
1037         else
1038             unlink_and_free_service_instance(instance);
1039     }
1040     else if (result == mStatus_NameConflict)
1041     {
1042         if (instance->request->u.servicereg.autorename)
1043         {
1044 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1045             external_stop_advertising_helper(instance);
1046 #endif
1047             if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
1048             {
1049                 // On conflict for an autoname service, rename and reregister *all* autoname services
1050                 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
1051                 mDNS_ConfigChanged(m);  // Will call back into udsserver_handle_configchange()
1052             }
1053             else    // On conflict for a non-autoname service, rename and reregister just that one service
1054             {
1055                 if (instance->clientnotified) SendServiceRemovalNotification(srs);
1056                 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
1057             }
1058         }
1059         else
1060         {
1061             if (!SuppressError)
1062             {
1063                 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1064                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1065                 else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1066             }
1067             unlink_and_free_service_instance(instance);
1068         }
1069     }
1070     else        // Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
1071     {
1072         if (!SuppressError)
1073         {
1074             if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1075                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1076             else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1077         }
1078     }
1079 }
1080 
regrecord_callback(mDNS * const m,AuthRecord * rr,mStatus result)1081 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
1082 {
1083     (void)m; // Unused
1084     if (!rr->RecordContext)     // parent struct already freed by termination callback
1085     {
1086         if (result == mStatus_NoError)
1087             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Error: regrecord_callback: successful registration of orphaned record " PRI_S, ARDisplayString(m, rr));
1088         else
1089         {
1090             if (result != mStatus_MemFree)
1091                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regrecord_callback: error %d received after parent termination", result);
1092 
1093             // We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
1094             // If the record has been updated, we need to free the rdata. Every time we call mDNS_Update, it calls update_callback
1095             // with the old rdata (so that we can free it) and stores the new rdata in "rr->resrec.rdata". This means, we need
1096             // to free the latest rdata for which the update_callback was never called with.
1097             if (rr->resrec.rdata != &rr->rdatastorage) freeL("RData/regrecord_callback", rr->resrec.rdata);
1098             freeL("AuthRecord/regrecord_callback", rr);
1099         }
1100     }
1101     else
1102     {
1103         registered_record_entry *re = rr->RecordContext;
1104         request_state *request = re->request;
1105 
1106         if (mDNS_LoggingEnabled)
1107         {
1108             const char *result_description;
1109             char description[16]; // 16-byte is enough for holding -2147483648\0
1110             switch (result) {
1111                 case mStatus_NoError:
1112                     result_description = "REGISTERED";
1113                     break;
1114                 case mStatus_MemFree:
1115                     result_description = "DEREGISTERED";
1116                     break;
1117                 case mStatus_NameConflict:
1118                     result_description = "NAME CONFLICT";
1119                     break;
1120                 default:
1121                     mDNS_snprintf(description, sizeof(description), "%d", result);
1122                     result_description = description;
1123                     break;
1124             }
1125 
1126             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegisterRecord(%u " PRI_S ")" PUB_S,
1127                       request->request_id, re->key, RRDisplayString(m, &rr->resrec), result_description);
1128         }
1129 
1130         if (result != mStatus_MemFree)
1131         {
1132             int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
1133             reply_state *reply = create_reply(reg_record_reply_op, len, request);
1134             reply->mhdr->client_context = re->regrec_client_context;
1135             reply->rhdr->flags = dnssd_htonl(0);
1136             reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID, mDNSfalse));
1137             reply->rhdr->error = dnssd_htonl(result);
1138             append_reply(request, reply);
1139         }
1140 
1141         if (result)
1142         {
1143             // If this is a callback to a keepalive record, do not free it.
1144             if (result == mStatus_BadStateErr)
1145             {
1146                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1147                           "[R%u] regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.", request->request_id);
1148             }
1149             else
1150             {
1151                 // unlink from list, free memory
1152                 registered_record_entry **ptr = &request->u.reg_recs;
1153                 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
1154                 if (!*ptr)
1155                 {
1156                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1157                               "[R%u] regrecord_callback - record not in list!", request->request_id);
1158                     return;
1159                 }
1160                 *ptr = (*ptr)->next;
1161                 freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
1162                 freeL("registered_record_entry regrecord_callback", re);
1163              }
1164         }
1165         else
1166         {
1167             if (re->external_advertise)
1168             {
1169                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1170                           "[R%u] regrecord_callback: external_advertise already set!", request->request_id);
1171             }
1172 
1173 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1174             if (callExternalHelpers(re->origInterfaceID, &rr->namestorage, request->flags))
1175             {
1176                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1177                           "[R%u] regrecord_callback: calling external_start_advertising_service", request->request_id);
1178                 external_start_advertising_service(&rr->resrec, request->flags, request->process_id);
1179                 re->external_advertise = mDNStrue;
1180             }
1181 #endif
1182         }
1183     }
1184 }
1185 
1186 // set_peer_pid() is called after mem is allocated for each new request in NewRequest()
1187 // This accounts for 2 places (connect_callback, request_callback)
set_peer_pid(request_state * request)1188 mDNSlocal void set_peer_pid(request_state *request)
1189 {
1190     request->pid_name[0] = '\0';
1191     request->process_id  = -1;
1192 #ifdef LOCAL_PEEREPID
1193     pid_t           p    = (pid_t) -1;
1194     socklen_t       len  = sizeof(p);
1195     if (request->sd < 0)
1196         return;
1197     // to extract the effective pid value
1198     if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREPID, &p, &len) != 0)
1199         return;
1200     // to extract the process name from the pid value
1201     if (proc_pidinfo(p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0)
1202         return;
1203     mDNSPlatformStrLCopy(request->pid_name, proc.pbsi_comm, sizeof(request->pid_name));
1204     request->process_id = p;
1205     debugf("set_peer_pid: Client PEEREPID is %d %s", p, request->pid_name);
1206 #else   // !LOCAL_PEEREPID
1207     LogInfo("set_peer_pid: Not Supported on this version of OS");
1208     if (request->sd < 0)
1209         return;
1210 #endif  // LOCAL_PEEREPID
1211 }
1212 
connection_termination(request_state * request)1213 mDNSlocal void connection_termination(request_state *request)
1214 {
1215     // When terminating a shared connection, we need to scan the all_requests list
1216     // and terminate any subbordinate operations sharing this file descriptor
1217     request_state **req = &all_requests;
1218 
1219     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1220            "[R%d] DNSServiceCreateConnection STOP PID[%d](" PUB_S ")",
1221            request->request_id, request->process_id, request->pid_name);
1222 
1223     while (*req)
1224     {
1225         if ((*req)->primary == request)
1226         {
1227             // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
1228             request_state *tmp = *req;
1229             if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d",                  tmp, tmp->sd);
1230             if (tmp->replies) LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
1231             abort_request(tmp);
1232             *req = tmp->next;
1233 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1234             if (tmp->trust)
1235             {
1236                 void * context = mdns_trust_get_context(tmp->trust);
1237                 mdns_trust_set_context(tmp->trust, NULL);
1238                 if (context) freeL("context/connection_termination", context);
1239                 mdns_trust_forget(&tmp->trust);
1240             }
1241 #endif
1242             freeL("request_state/connection_termination", tmp);
1243         }
1244         else
1245             req = &(*req)->next;
1246     }
1247 
1248     while (request->u.reg_recs)
1249     {
1250         registered_record_entry *ptr = request->u.reg_recs;
1251         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1252                "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") STOP PID[%d](" PUB_S ")",
1253                request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id,
1254                request->pid_name);
1255         request->u.reg_recs = request->u.reg_recs->next;
1256         ptr->rr->RecordContext = NULL;
1257         if (ptr->external_advertise)
1258         {
1259             ptr->external_advertise = mDNSfalse;
1260 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1261             external_stop_advertising_service(&ptr->rr->resrec, request->flags, request->process_id);
1262 #endif
1263         }
1264         LogMcastS(ptr->rr, request, reg_stop);
1265         mDNS_Deregister(&mDNSStorage, ptr->rr);     // Will free ptr->rr for us
1266         freeL("registered_record_entry/connection_termination", ptr);
1267     }
1268 }
1269 
handle_cancel_request(request_state * request)1270 mDNSlocal void handle_cancel_request(request_state *request)
1271 {
1272     request_state **req = &all_requests;
1273     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "[R%d] Cancel %08X %08X",
1274            request->request_id, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
1275     while (*req)
1276     {
1277         if ((*req)->primary == request &&
1278             (*req)->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
1279             (*req)->hdr.client_context.u32[1] == request->hdr.client_context.u32[1])
1280         {
1281             // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
1282             request_state *tmp = *req;
1283             abort_request(tmp);
1284             *req = tmp->next;
1285 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1286             if (tmp->trust)
1287             {
1288                 void * context = mdns_trust_get_context(tmp->trust);
1289                 mdns_trust_set_context(tmp->trust, NULL);
1290                 if (context) freeL("context/handle_cancel_request", context);
1291                 mdns_trust_forget(&tmp->trust);
1292             }
1293 #endif
1294             freeL("request_state/handle_cancel_request", tmp);
1295         }
1296         else
1297             req = &(*req)->next;
1298     }
1299 }
1300 
_handle_regrecord_request_start(request_state * request,AuthRecord * rr)1301 mDNSlocal mStatus _handle_regrecord_request_start(request_state *request, AuthRecord * rr)
1302 {
1303     mStatus err;
1304     registered_record_entry *re;
1305     // Don't allow non-local domains to be regsitered as LocalOnly. Allowing this would permit
1306     // clients to register records such as www.bigbank.com A w.x.y.z to redirect Safari.
1307     if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly && !IsLocalDomain(rr->resrec.name) &&
1308         rr->resrec.rrclass == kDNSClass_IN && (rr->resrec.rrtype == kDNSType_A || rr->resrec.rrtype == kDNSType_AAAA ||
1309                                                rr->resrec.rrtype == kDNSType_CNAME))
1310     {
1311         freeL("AuthRecord/handle_regrecord_request", rr);
1312         return (mStatus_BadParamErr);
1313     }
1314     // allocate registration entry, link into list
1315     re = (registered_record_entry *) callocL("registered_record_entry", sizeof(*re));
1316     if (!re) FatalError("ERROR: calloc");
1317     re->key                   = request->hdr.reg_index;
1318     re->rr                    = rr;
1319     re->regrec_client_context = request->hdr.client_context;
1320     re->request               = request;
1321     re->external_advertise    = mDNSfalse;
1322     rr->RecordContext         = re;
1323     rr->RecordCallback        = regrecord_callback;
1324 
1325     re->origInterfaceID = rr->resrec.InterfaceID;
1326     if (rr->resrec.InterfaceID == mDNSInterface_P2P)
1327         rr->resrec.InterfaceID = mDNSInterface_Any;
1328 #if 0
1329     if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
1330 #endif
1331     if (rr->resrec.rroriginalttl == 0)
1332         rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
1333 
1334     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1335            "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") START PID[%d](" PUB_S ")",
1336            request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id,
1337            request->pid_name);
1338 
1339     err = mDNS_Register(&mDNSStorage, rr);
1340     if (err)
1341     {
1342         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1343                "[R%d] DNSServiceRegisterRecord(0x%X, %d," PRI_S ") ERROR (%d)",
1344                request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), err);
1345         freeL("registered_record_entry", re);
1346         freeL("registered_record_entry/AuthRecord", rr);
1347     }
1348     else
1349     {
1350         LogMcastS(rr, request, reg_start);
1351         re->next = request->u.reg_recs;
1352         request->u.reg_recs = re;
1353     }
1354     return err;
1355 }
1356 
1357 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1358 
_return_regrecord_request_error(request_state * request,mStatus error)1359 mDNSlocal void _return_regrecord_request_error(request_state *request, mStatus error)
1360 {
1361     reply_state *rep;
1362     if (GenerateNTDResponse(NULL, 0, request, &rep, reg_record_reply_op, 0, error) != mStatus_NoError)
1363     {
1364         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegisterRecord _return_regrecord_request_error: error(%d)", request->request_id, error);
1365     }
1366     else
1367     {
1368         append_reply(request, rep);
1369     }
1370 }
1371 
_handle_regrecord_request_with_trust(request_state * request,AuthRecord * rr)1372 mDNSlocal mStatus _handle_regrecord_request_with_trust(request_state *request, AuthRecord * rr)
1373 {
1374     mStatus err;
1375     if (audit_token_to_pid(request->audit_token) == 0)
1376     {
1377         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regrecord_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
1378         err = _handle_regrecord_request_start(request, rr);
1379     }
1380     else
1381     {
1382         const char *service_ptr = NULL;
1383         char type_str[MAX_ESCAPED_DOMAIN_NAME] = "";
1384         domainlabel name;
1385         domainname type, domain;
1386         bool good = DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
1387         if (good)
1388         {
1389             ConvertDomainNameToCString(&type, type_str);
1390             service_ptr = type_str;
1391         }
1392 
1393         mdns_trust_flags_t flags = mdns_trust_flags_none;
1394         mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, service_ptr, &flags);
1395         switch (status)
1396         {
1397             case mdns_trust_status_denied:
1398             case mdns_trust_status_pending:
1399             {
1400                 mdns_trust_t trust = mdns_trust_create(request->audit_token, service_ptr, flags);
1401                 if (!trust)
1402                 {
1403                     freeL("AuthRecord/_handle_regrecord_request_with_trust", rr);
1404                     err = mStatus_NoMemoryErr;
1405                     goto exit;
1406                 }
1407                 mdns_trust_set_context(trust, rr);
1408                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
1409                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
1410                 {
1411                     if (event == mdns_trust_event_result)
1412                     {
1413                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
1414                         KQueueLock();
1415                         AuthRecord * _rr =  mdns_trust_get_context(trust);
1416                         if (_rr)
1417                         {
1418                             if (!error)
1419                             {
1420                                 mdns_trust_set_context(trust, NULL); // _handle_regrecord_request_start handles free
1421                                 error = _handle_regrecord_request_start(request, _rr);
1422                                 // No context means the request was canceled before we got here
1423                             }
1424                             if (error) // (not else if) Always check for error result
1425                             {
1426                                 _return_regrecord_request_error(request, error);
1427                             }
1428                         }
1429                         KQueueUnlock("_handle_regrecord_request_with_trust");
1430                     }
1431                 });
1432                 request->trust = trust;
1433                 mdns_trust_activate(trust);
1434                 err = mStatus_NoError;
1435                 break;
1436             }
1437 
1438             case mdns_trust_status_no_entitlement:
1439                 err = mStatus_NoAuth;
1440                 break;
1441 
1442             case mdns_trust_status_granted:
1443                 err = _handle_regrecord_request_start(request, rr);
1444                 break;
1445 
1446             default:
1447                 err = mStatus_UnknownErr;
1448                 break;
1449         }
1450      }
1451 exit:
1452     return err;
1453 }
1454 #endif // TRUST_ENFORCEMENT
1455 
handle_regrecord_request(request_state * request)1456 mDNSlocal mStatus handle_regrecord_request(request_state *request)
1457 {
1458     mStatus err = mStatus_BadParamErr;
1459     AuthRecord *rr;
1460 
1461     if (request->terminate != connection_termination)
1462     { LogMsg("%3d: DNSServiceRegisterRecord(not a shared connection ref)", request->sd); return(err); }
1463 
1464     rr = read_rr_from_ipc_msg(request, 1, 1);
1465     if (rr)
1466     {
1467 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1468         if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
1469             IsLocalDomain(rr->resrec.name))
1470         {
1471             err = _handle_regrecord_request_with_trust(request, rr);
1472         }
1473         else
1474         {
1475             err = _handle_regrecord_request_start(request, rr);
1476         }
1477 #else
1478         err = _handle_regrecord_request_start(request, rr);
1479 #endif
1480     }
1481     return(err);
1482 }
1483 
1484 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
1485 
regservice_termination_callback(request_state * request)1486 mDNSlocal void regservice_termination_callback(request_state *request)
1487 {
1488     if (!request)
1489     {
1490         LogMsg("regservice_termination_callback context is NULL");
1491         return;
1492     }
1493     while (request->u.servicereg.instances)
1494     {
1495         service_instance *p = request->u.servicereg.instances;
1496         request->u.servicereg.instances = request->u.servicereg.instances->next;
1497         // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
1498         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRegister(" PRI_DM_NAME ", %u) STOP PID[%d](" PUB_S ")",
1499                request->request_id, DM_NAME_PARAM(p->srs.RR_SRV.resrec.name),
1500                mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
1501 
1502 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1503         external_stop_advertising_helper(p);
1504 #endif
1505 
1506         // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
1507         // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
1508         // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
1509         // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
1510         // because by then we might have already freed p
1511         p->request = NULL;
1512         LogMcastS(&p->srs.RR_SRV, request, reg_stop);
1513         if (mDNS_DeregisterService(&mDNSStorage, &p->srs))
1514         {
1515             unlink_and_free_service_instance(p);
1516             // Don't touch service_instance *p after this -- it's likely to have been freed already
1517         }
1518     }
1519     if (request->u.servicereg.txtdata)
1520     {
1521         freeL("service_info txtdata", request->u.servicereg.txtdata);
1522         request->u.servicereg.txtdata = NULL;
1523     }
1524     if (request->u.servicereg.autoname)
1525     {
1526         // Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations
1527         request->u.servicereg.autoname = mDNSfalse;
1528         UpdateDeviceInfoRecord(&mDNSStorage);
1529     }
1530 }
1531 
LocateSubordinateRequest(request_state * request)1532 mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
1533 {
1534     request_state *req;
1535     for (req = all_requests; req; req = req->next)
1536         if (req->primary == request &&
1537             req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
1538             req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req);
1539     return(request);
1540 }
1541 
add_record_to_service(request_state * request,service_instance * instance,mDNSu16 rrtype,mDNSu16 rdlen,const mDNSu8 * const rdata,mDNSu32 ttl)1542 mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen,
1543     const mDNSu8 *const rdata, mDNSu32 ttl)
1544 {
1545     ServiceRecordSet *srs = &instance->srs;
1546     mStatus result;
1547     const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
1548     ExtraResourceRecord *extra = (ExtraResourceRecord *)callocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + rdcapacity);
1549     if (!extra) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
1550 
1551     extra->r.resrec.rrtype = rrtype;
1552     extra->r.resrec.rdata = &extra->r.rdatastorage;
1553     extra->r.resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
1554     extra->r.resrec.rdlength = rdlen;
1555     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &extra->r.resrec, rdlen))
1556     {
1557         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
1558             "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
1559             request->request_id, DM_NAME_PARAM(request->u.servicereg.instances ?
1560             request->u.servicereg.instances->srs.RR_SRV.resrec.name : mDNSNULL), DNSTypeName(rrtype));
1561         freeL("ExtraResourceRecord/add_record_to_service", extra);
1562         return mStatus_BadParamErr;
1563     }
1564     SetNewRData(&extra->r.resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
1565     // use InterfaceID value from DNSServiceRegister() call that created the original service
1566     extra->r.resrec.InterfaceID = request->u.servicereg.InterfaceID;
1567 
1568     result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl, request->flags);
1569     if (result)
1570     {
1571         freeL("ExtraResourceRecord/add_record_to_service", extra);
1572         return result;
1573     }
1574     LogMcastS(&srs->RR_PTR, request, reg_start);
1575 
1576     extra->ClientID = request->hdr.reg_index;
1577 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1578     if (   instance->external_advertise
1579            && callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags))
1580     {
1581         LogInfo("add_record_to_service: calling external_start_advertising_service");
1582         external_start_advertising_service(&extra->r.resrec, request->flags, request->process_id);
1583     }
1584 #endif
1585     return result;
1586 }
1587 
handle_add_request(request_state * request)1588 mDNSlocal mStatus handle_add_request(request_state *request)
1589 {
1590     service_instance *i;
1591     mStatus result = mStatus_UnknownErr;
1592     DNSServiceFlags flags  = get_flags (&request->msgptr, request->msgend);
1593     mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend);
1594     mDNSu16 rdlen  = get_uint16(&request->msgptr, request->msgend);
1595     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
1596     mDNSu32 ttl    = get_uint32(&request->msgptr, request->msgend);
1597     if (!ttl) ttl = DefaultTTLforRRType(rrtype);
1598     (void)flags; // Unused
1599 
1600     if (!request->msgptr)
1601     {
1602         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1603                "[R%d] DNSServiceAddRecord(unreadable parameters)", request->request_id);
1604         return(mStatus_BadParamErr);
1605     }
1606 
1607     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1608     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1609 
1610     if (request->terminate != regservice_termination_callback)
1611     {
1612         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1613                "[R%d] DNSServiceAddRecord(not a registered service ref)", request->request_id);
1614         return(mStatus_BadParamErr);
1615     }
1616 
1617     // For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
1618     // in the application. See radar://9165807.
1619     if (mDNSIPPortIsZero(request->u.servicereg.port))
1620     {
1621         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1622                "[R%d] DNSServiceAddRecord: adding record to a service registered with zero port", request->request_id);
1623         return(mStatus_BadParamErr);
1624     }
1625     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1626            "[R%d] DNSServiceAddRecord(%X, " PRI_DM_NAME ", " PUB_S ", %d) PID[%d](" PUB_S ")",
1627            request->request_id, flags,
1628            DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
1629            DNSTypeName(rrtype), rdlen, request->process_id, request->pid_name);
1630 
1631     for (i = request->u.servicereg.instances; i; i = i->next)
1632     {
1633         result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
1634         if (result && i->default_local) break;
1635         else result = mStatus_NoError;  // suppress non-local default errors
1636     }
1637 
1638     return(result);
1639 }
1640 
update_callback(mDNS * const m,AuthRecord * const rr,RData * oldrd,mDNSu16 oldrdlen)1641 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd, mDNSu16 oldrdlen)
1642 {
1643     mDNSBool external_advertise = (rr->UpdateContext) ? *((mDNSBool *)rr->UpdateContext) : mDNSfalse;
1644     (void)m; // Unused
1645 
1646     // There are three cases.
1647     //
1648     // 1. We have updated the primary TXT record of the service
1649     // 2. We have updated the TXT record that was added to the service using DNSServiceAddRecord
1650     // 3. We have updated the TXT record that was registered using DNSServiceRegisterRecord
1651     //
1652     // external_advertise is set if we have advertised at least once during the initial addition
1653     // of the record in all of the three cases above. We should have checked for InterfaceID/LocalDomain
1654     // checks during the first time and hence we don't do any checks here
1655     if (external_advertise)
1656     {
1657         ResourceRecord ext = rr->resrec;
1658 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1659         DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType);
1660 #endif
1661 
1662         if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
1663         SetNewRData(&ext, oldrd, oldrdlen);
1664 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1665         external_stop_advertising_service(&ext, flags, 0);
1666         LogInfo("update_callback: calling external_start_advertising_service");
1667         external_start_advertising_service(&rr->resrec, flags, 0);
1668 #endif
1669     }
1670 exit:
1671     if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
1672 }
1673 
update_record(AuthRecord * ar,mDNSu16 rdlen,const mDNSu8 * const rdata,mDNSu32 ttl,const mDNSBool * const external_advertise,const mDNSu32 request_id)1674 mDNSlocal mStatus update_record(AuthRecord *ar, mDNSu16 rdlen, const mDNSu8 *const rdata, mDNSu32 ttl,
1675     const mDNSBool *const external_advertise, const mDNSu32 request_id)
1676 {
1677     ResourceRecord rr;
1678     mStatus result;
1679     const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
1680     RData *newrd = (RData *) callocL("RData/update_record", sizeof(*newrd) - sizeof(RDataBody) + rdcapacity);
1681     if (!newrd) FatalError("ERROR: calloc");
1682     mDNSPlatformMemZero(&rr, (mDNSu32)sizeof(rr));
1683     rr.name     = ar->resrec.name;
1684     rr.rrtype   = ar->resrec.rrtype;
1685     rr.rrclass  = ar->resrec.rrclass;
1686     rr.rdata    = newrd;
1687     rr.rdata->MaxRDLength = (mDNSu16)rdcapacity;
1688     rr.rdlength = rdlen;
1689     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr, rdlen))
1690     {
1691         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
1692             "[R%u] update_record: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
1693             request_id, DM_NAME_PARAM(rr.name), DNSTypeName(rr.rrtype));
1694         freeL("RData/update_record", newrd);
1695         return mStatus_BadParamErr;
1696     }
1697     rdlen = GetRDLength(&rr, mDNSfalse);
1698     // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1699     // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1700     // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1701     if (ar->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
1702 
1703     if (external_advertise) ar->UpdateContext = (void *)external_advertise;
1704 
1705     result = mDNS_Update(&mDNSStorage, ar, ttl, rdlen, newrd, update_callback);
1706     if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, ar)); freeL("RData/update_record", newrd); }
1707     return result;
1708 }
1709 
handle_update_request(request_state * request)1710 mDNSlocal mStatus handle_update_request(request_state *request)
1711 {
1712     const ipc_msg_hdr *const hdr = &request->hdr;
1713     mStatus result = mStatus_BadReferenceErr;
1714     service_instance *i;
1715     AuthRecord *rr = NULL;
1716 
1717     // get the message data
1718     DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);  // flags unused
1719     mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
1720     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
1721     mDNSu32 ttl   = get_uint32(&request->msgptr, request->msgend);
1722     (void)flags; // Unused
1723 
1724     if (!request->msgptr)
1725     {
1726         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1727                "[R%d] DNSServiceUpdateRecord(unreadable parameters)", request->request_id);
1728         return(mStatus_BadParamErr);
1729     }
1730 
1731     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1732     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1733 
1734     if (request->terminate == connection_termination)
1735     {
1736         // update an individually registered record
1737         registered_record_entry *reptr;
1738         for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
1739         {
1740             if (reptr->key == hdr->reg_index)
1741             {
1742                 result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise, request->request_id);
1743                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1744                        "[R%d] DNSServiceUpdateRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
1745                        request->request_id, DM_NAME_PARAM(reptr->rr->resrec.name),
1746                        reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
1747                        request->process_id, request->pid_name);
1748                 goto end;
1749             }
1750         }
1751         result = mStatus_BadReferenceErr;
1752         goto end;
1753     }
1754 
1755     if (request->terminate != regservice_termination_callback)
1756     {
1757         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1758                "[R%d] DNSServiceUpdateRecord(not a registered service ref)", request->request_id);
1759         return(mStatus_BadParamErr);
1760     }
1761 
1762     // For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
1763     if (mDNSIPPortIsZero(request->u.servicereg.port))
1764     {
1765         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1766                "[R%d] DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->request_id);
1767         return(mStatus_BadParamErr);
1768     }
1769 
1770     // update the saved off TXT data for the service
1771     if (hdr->reg_index == TXT_RECORD_INDEX)
1772     {
1773         if (request->u.servicereg.txtdata)
1774         { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
1775         if (rdlen > 0)
1776         {
1777             request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen);
1778             if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
1779             mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
1780         }
1781         request->u.servicereg.txtlen = rdlen;
1782     }
1783 
1784     // update a record from a service record set
1785     for (i = request->u.servicereg.instances; i; i = i->next)
1786     {
1787         if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
1788         else
1789         {
1790             ExtraResourceRecord *e;
1791             for (e = i->srs.Extras; e; e = e->next)
1792                 if (e->ClientID == hdr->reg_index) { rr = &e->r; break; }
1793         }
1794 
1795         if (!rr) { result = mStatus_BadReferenceErr; goto end; }
1796         result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise, request->request_id);
1797         if (result && i->default_local) goto end;
1798         else result = mStatus_NoError;  // suppress non-local default errors
1799     }
1800 
1801 end:
1802     if (request->terminate == regservice_termination_callback)
1803         LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)  PID[%d](%s)", request->sd,
1804                      (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
1805                      rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>",
1806                      request->process_id, request->pid_name);
1807 
1808     return(result);
1809 }
1810 
1811 // remove a resource record registered via DNSServiceRegisterRecord()
remove_record(request_state * request)1812 mDNSlocal mStatus remove_record(request_state *request)
1813 {
1814     mStatus err = mStatus_UnknownErr;
1815     registered_record_entry *e, **ptr = &request->u.reg_recs;
1816 
1817     while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
1818     if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
1819     e = *ptr;
1820     *ptr = e->next; // unlink
1821 
1822     LogOperation("%3d: DNSServiceRemoveRecord(%u %s)  PID[%d](%s)",
1823                 request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec), request->process_id, request->pid_name);
1824     e->rr->RecordContext = NULL;
1825     if (e->external_advertise)
1826     {
1827 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1828         external_stop_advertising_service(&e->rr->resrec, request->flags, request->process_id);
1829 #endif
1830         e->external_advertise = mDNSfalse;
1831     }
1832     LogMcastS(e->rr, request, reg_stop);
1833     err = mDNS_Deregister(&mDNSStorage, e->rr);     // Will free e->rr for us; we're responsible for freeing e
1834     if (err)
1835     {
1836         LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
1837         freeL("registered_record_entry AuthRecord remove_record", e->rr);
1838     }
1839     freeL("registered_record_entry remove_record", e);
1840     return err;
1841 }
1842 
remove_extra(const request_state * const request,service_instance * const serv,mDNSu16 * const rrtype)1843 mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
1844 {
1845     mStatus err = mStatus_BadReferenceErr;
1846     ExtraResourceRecord *ptr;
1847 
1848     for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
1849     {
1850         if (ptr->ClientID == request->hdr.reg_index) // found match
1851         {
1852             *rrtype = ptr->r.resrec.rrtype;
1853 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1854             if (serv->external_advertise)
1855             {
1856                 external_stop_advertising_service(&ptr->r.resrec, request->flags, request->process_id);
1857             }
1858 #endif
1859             err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
1860             break;
1861         }
1862     }
1863     return err;
1864 }
1865 
handle_removerecord_request(request_state * request)1866 mDNSlocal mStatus handle_removerecord_request(request_state *request)
1867 {
1868     mStatus err = mStatus_BadReferenceErr;
1869     get_flags(&request->msgptr, request->msgend);   // flags unused
1870 
1871     if (!request->msgptr)
1872     {
1873         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1874                "[R%d] DNSServiceRemoveRecord(unreadable parameters)", request->request_id);
1875         return(mStatus_BadParamErr);
1876     }
1877 
1878     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1879     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1880 
1881     if (request->terminate == connection_termination)
1882         err = remove_record(request);  // remove individually registered record
1883     else if (request->terminate != regservice_termination_callback)
1884     {
1885         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1886                "[R%d] DNSServiceRemoveRecord(not a registered service ref)", request->request_id);
1887         return(mStatus_BadParamErr);
1888     }
1889     else
1890     {
1891         service_instance *i;
1892         mDNSu16 rrtype = 0;
1893         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRemoveRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
1894                request->request_id,
1895                DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
1896                rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
1897         for (i = request->u.servicereg.instances; i; i = i->next)
1898         {
1899             err = remove_extra(request, i, &rrtype);
1900             if (err && i->default_local) break;
1901             else err = mStatus_NoError;  // suppress non-local default errors
1902         }
1903     }
1904 
1905     return(err);
1906 }
1907 
1908 // If there's a comma followed by another character,
1909 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1910 // Otherwise, it returns a pointer to the final nul at the end of the string
FindFirstSubType(char * p)1911 mDNSlocal char *FindFirstSubType(char *p)
1912 {
1913     while (*p)
1914     {
1915         if (p[0] == '\\' && p[1])
1916         {
1917              p += 2;
1918         }
1919         else if (p[0] == ',' && p[1])
1920         {
1921             *p++ = 0;
1922             return(p);
1923         }
1924         else
1925         {
1926             p++;
1927         }
1928     }
1929     return(p);
1930 }
1931 
1932 // If there's a comma followed by another character,
1933 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1934 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1935 // Otherwise, it returns a pointer to the final nul at the end of the string
FindNextSubType(char * p)1936 mDNSlocal char *FindNextSubType(char *p)
1937 {
1938     while (*p)
1939     {
1940         if (p[0] == '\\' && p[1])       // If escape character
1941             p += 2;                     // ignore following character
1942         else if (p[0] == ',')           // If we found a comma
1943         {
1944             if (p[1]) *p++ = 0;
1945             return(p);
1946         }
1947         else if (p[0] == '.')
1948             return(mDNSNULL);
1949         else p++;
1950     }
1951     return(p);
1952 }
1953 
1954 // Returns -1 if illegal subtype found
ChopSubTypes(char * regtype)1955 mDNSlocal mDNSs32 ChopSubTypes(char *regtype)
1956 {
1957     mDNSs32 NumSubTypes = 0;
1958     char *stp = FindFirstSubType(regtype);
1959     while (stp && *stp)                 // If we found a comma...
1960     {
1961         if (*stp == ',') return(-1);
1962         NumSubTypes++;
1963         stp = FindNextSubType(stp);
1964     }
1965     if (!stp) return(-1);
1966     return(NumSubTypes);
1967 }
1968 
AllocateSubTypes(mDNSs32 NumSubTypes,char * p)1969 mDNSlocal AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1970 {
1971     AuthRecord *st = mDNSNULL;
1972     if (NumSubTypes)
1973     {
1974         mDNSs32 i;
1975         st = (AuthRecord *) callocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1976         if (!st) return(mDNSNULL);
1977         for (i = 0; i < NumSubTypes; i++)
1978         {
1979             mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
1980             while (*p) p++;
1981             p++;
1982             if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
1983             {
1984                 freeL("ServiceSubTypes", st);
1985                 return(mDNSNULL);
1986             }
1987         }
1988     }
1989     return(st);
1990 }
1991 
register_service_instance(request_state * request,const domainname * domain)1992 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
1993 {
1994     service_instance **ptr, *instance;
1995     size_t extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0;
1996     const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
1997     mStatus result;
1998     mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
1999 
2000     // If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
2001     // registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
2002     // registrations scoped to a specific interface, so for the automatic domains we add we must *not* specify an interface.
2003     // (Specifying an interface with an apparently wide-area domain (i.e. something other than "local")
2004     // currently forces the registration to use mDNS multicast despite the apparently wide-area domain.)
2005     if (request->u.servicereg.default_domain && !DomainIsLocal) interfaceID = mDNSInterface_Any;
2006 
2007     for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
2008     {
2009         if (SameDomainName(&(*ptr)->domain, domain))
2010         {
2011             LogMsg("register_service_instance: domain %##s already registered for %#s.%##s",
2012                    domain->c, &request->u.servicereg.name, &request->u.servicereg.type);
2013             return mStatus_AlreadyRegistered;
2014         }
2015     }
2016 
2017     instance = (service_instance *) callocL("service_instance", sizeof(*instance) + extra_size);
2018     if (!instance) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
2019 
2020     instance->next                          = mDNSNULL;
2021     instance->request                       = request;
2022     instance->renameonmemfree               = 0;
2023     instance->clientnotified                = mDNSfalse;
2024     instance->default_local                 = (request->u.servicereg.default_domain && DomainIsLocal);
2025     instance->external_advertise            = mDNSfalse;
2026     AssignDomainName(&instance->domain, domain);
2027 
2028     instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
2029 
2030     if (request->u.servicereg.num_subtypes && !instance->subtypes)
2031     {
2032         unlink_and_free_service_instance(instance);
2033         instance = NULL;
2034         FatalError("ERROR: malloc");
2035     }
2036 
2037     result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
2038                                   &request->u.servicereg.name, &request->u.servicereg.type, domain,
2039                                   request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
2040                                   request->u.servicereg.port,
2041                                   mDNSNULL, request->u.servicereg.txtdata, request->u.servicereg.txtlen,
2042                                   instance->subtypes, request->u.servicereg.num_subtypes,
2043                                   interfaceID, regservice_callback, instance, request->flags);
2044 
2045     if (!result)
2046     {
2047         *ptr = instance;        // Append this to the end of our request->u.servicereg.instances list
2048         LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", instance->request->sd,
2049                      instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
2050         LogMcastS(&instance->srs.RR_SRV, request, reg_start);
2051     }
2052     else
2053     {
2054         LogMsg("register_service_instance %#s.%##s%##s error %d",
2055                &request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
2056         unlink_and_free_service_instance(instance);
2057     }
2058 
2059     return result;
2060 }
2061 
udsserver_default_reg_domain_changed(const DNameListElem * const d,const mDNSBool add)2062 mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
2063 {
2064     request_state *request;
2065 
2066     LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
2067     for (request = all_requests; request; request = request->next)
2068     {
2069         if (request->terminate != regservice_termination_callback) continue;
2070         if (!request->u.servicereg.default_domain) continue;
2071         if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
2072         {
2073             service_instance **ptr = &request->u.servicereg.instances;
2074             while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
2075             if (add)
2076             {
2077                 // If we don't already have this domain in our list for this registration, add it now
2078                 if (!*ptr) register_service_instance(request, &d->name);
2079                 else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
2080             }
2081             else
2082             {
2083                 // Normally we should not fail to find the specified instance
2084                 // One case where this can happen is if a uDNS update fails for some reason,
2085                 // and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
2086                 if (!*ptr)
2087                     LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
2088                            &d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
2089                 else
2090                 {
2091                     DNameListElem *p;
2092                     for (p = AutoRegistrationDomains; p; p=p->next)
2093                         if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
2094                             if (SameDomainName(&d->name, &p->name)) break;
2095                     if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
2096                     else
2097                     {
2098                         mStatus err;
2099                         service_instance *si = *ptr;
2100                         *ptr = si->next;
2101                         if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
2102                         // Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
2103                         // Otherwise what can happen is this: While our mDNS_DeregisterService is in the
2104                         // process of completing asynchronously, the client cancels the entire operation, so
2105                         // regservice_termination_callback then runs through the whole list deregistering each
2106                         // instance, clearing the backpointers, and then disposing the parent request_state object.
2107                         // However, because this service_instance isn't in the list any more, regservice_termination_callback
2108                         // has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
2109                         // completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
2110                         // a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
2111                         si->request = NULL;
2112                         err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
2113                         if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
2114                     }
2115                 }
2116             }
2117         }
2118     }
2119 }
2120 
2121 // Returns true if the interfaceIndex value matches one of the pre-defined
2122 // special values listed in the switch statement below.
PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)2123 mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
2124 {
2125     switch(interfaceIndex)
2126     {
2127         case kDNSServiceInterfaceIndexAny:
2128         case kDNSServiceInterfaceIndexLocalOnly:
2129         case kDNSServiceInterfaceIndexUnicast:
2130         case kDNSServiceInterfaceIndexP2P:
2131         case kDNSServiceInterfaceIndexBLE:
2132             return mDNStrue;
2133         default:
2134             return mDNSfalse;
2135     }
2136 }
2137 
_handle_regservice_request_start(request_state * request,const domainname * const d)2138 mDNSlocal mStatus _handle_regservice_request_start(request_state *request, const domainname * const d)
2139 {
2140     mStatus err;
2141 
2142     request->terminate = regservice_termination_callback;
2143     err = register_service_instance(request, d);
2144 
2145 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
2146     ++curr_num_regservices;
2147     if (curr_num_regservices > max_num_regservices)
2148         max_num_regservices = curr_num_regservices;
2149 #endif
2150 
2151 #if 0
2152     err = AuthorizedDomain(request, d, AutoRegistrationDomains) ? register_service_instance(request, d) : mStatus_NoError;
2153 #endif
2154     if (!err)
2155     {
2156         if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
2157 
2158         if (request->u.servicereg.default_domain)
2159         {
2160             DNameListElem *ptr;
2161             // Note that we don't report errors for non-local, non-explicit domains
2162             for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
2163                 if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
2164                     register_service_instance(request, &ptr->name);
2165         }
2166     }
2167     return err;
2168 }
2169 
2170 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
2171 
_return_regservice_request_error(request_state * request,mStatus error)2172 mDNSlocal void _return_regservice_request_error(request_state *request, mStatus error)
2173 {
2174     if (request->u.servicereg.txtdata)
2175     {
2176         freeL("service_info txtdata", request->u.servicereg.txtdata);
2177         request->u.servicereg.txtdata = NULL;
2178     }
2179 
2180     reply_state *rep;
2181     if (GenerateNTDResponse(NULL, 0, request, &rep, reg_service_reply_op, 0, error) != mStatus_NoError)
2182     {
2183         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegister _return_regservice_request_error: error(%d)", request->request_id, error);
2184     }
2185     else
2186     {
2187         append_reply(request, rep);
2188     }
2189 }
2190 
_handle_regservice_request_with_trust(request_state * request,const domainname * const d)2191 mDNSlocal mStatus _handle_regservice_request_with_trust(request_state *request, const domainname * const d)
2192 {
2193     mStatus err;
2194     if (audit_token_to_pid(request->audit_token) == 0)
2195     {
2196         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regservice_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
2197         err = _handle_regservice_request_start(request, d);
2198     }
2199     else
2200     {
2201         mdns_trust_flags_t flags = mdns_trust_flags_none;
2202         mdns_trust_status_t status = mdns_trust_check_register_service(request->audit_token, request->u.servicereg.type_as_string, &flags);
2203         switch (status) {
2204             case mdns_trust_status_denied:
2205             case mdns_trust_status_pending:
2206             {
2207                 mdns_trust_t trust = mdns_trust_create(request->audit_token, request->u.servicereg.type_as_string, flags);
2208                 if (!trust)
2209                 {
2210                     err = mStatus_NoMemoryErr;
2211                     goto exit;
2212                 }
2213                 void * context = mallocL("context/_handle_regservice_request_with_trust", sizeof(domainname));
2214                 if (!context)
2215                 {
2216                     my_perror("ERROR: mallocL context/_handle_regservice_request_with_trust");
2217                     mdns_release(trust);
2218                     err = mStatus_NoMemoryErr;
2219                     goto exit;
2220                 }
2221                 memcpy(context, d, sizeof(domainname));
2222                 mdns_trust_set_context(trust, context);
2223 
2224                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
2225                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
2226                 {
2227                     if (event == mdns_trust_event_result)
2228                     {
2229                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
2230                         KQueueLock();
2231                         const domainname * _d = mdns_trust_get_context(trust);
2232                         if (_d)
2233                         {
2234                             if (!error)
2235                             {
2236                                 error = _handle_regservice_request_start(request, _d);
2237                                 // No context means the request was canceled before we got here
2238                             }
2239                             if (error) // (not else if) Always check for error result
2240                             {
2241                                 _return_regservice_request_error(request, error);
2242                             }
2243                         }
2244                         KQueueUnlock("_register_service_instance_with_trust");
2245                     }
2246                 });
2247                 request->trust = trust;
2248                 mdns_trust_activate(trust);
2249                 err = mStatus_NoError;
2250                 break;
2251             }
2252 
2253             case mdns_trust_status_no_entitlement:
2254                 err = mStatus_NoAuth;
2255                 break;
2256 
2257             case mdns_trust_status_granted:
2258                 err = _handle_regservice_request_start(request, d);
2259                 break;
2260 
2261             default:
2262                 err = mStatus_UnknownErr;
2263                 break;
2264         }
2265     }
2266 exit:
2267     return err;
2268 }
2269 #endif // TRUST_ENFORCEMENT
2270 
handle_regservice_request(request_state * request)2271 mDNSlocal mStatus handle_regservice_request(request_state *request)
2272 {
2273     char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2274     char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2275     char type_as_string[MAX_ESCAPED_DOMAIN_NAME];  // Note that this service type may include a trailing list of subtypes
2276     domainname d, srv;
2277     mStatus err;
2278     const char *msgTXTData;
2279 
2280     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2281     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2282     mDNSInterfaceID InterfaceID;
2283 
2284     // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the
2285     // kDNSServiceFlagsIncludeP2P flag set.
2286     if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
2287     {
2288         LogOperation("handle_regservice_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
2289         flags |= kDNSServiceFlagsIncludeP2P;
2290         interfaceIndex = kDNSServiceInterfaceIndexAny;
2291     }
2292 
2293     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2294 
2295     // The registration is scoped to a specific interface index, but the
2296     // interface is not currently in our list.
2297     if (interfaceIndex && !InterfaceID)
2298     {
2299         // If it's one of the specially defined inteface index values, just return an error.
2300         if (PreDefinedInterfaceIndex(interfaceIndex))
2301         {
2302             LogInfo("handle_regservice_request: bad interfaceIndex %d", interfaceIndex);
2303             return(mStatus_BadParamErr);
2304         }
2305 
2306         // Otherwise, use the specified interface index value and the registration will
2307         // be applied to that interface when it comes up.
2308         InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
2309         LogInfo("handle_regservice_request: registration pending for interface index %d", interfaceIndex);
2310     }
2311 
2312     if (get_string(&request->msgptr, request->msgend, name,           sizeof(name          )) < 0 ||
2313         get_string(&request->msgptr, request->msgend, type_as_string, sizeof(type_as_string)) < 0 ||
2314         get_string(&request->msgptr, request->msgend, domain,         sizeof(domain        )) < 0 ||
2315         get_string(&request->msgptr, request->msgend, host,           sizeof(host          )) < 0)
2316     { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
2317 
2318     request->flags = flags;
2319     request->interfaceIndex = interfaceIndex;
2320     request->u.servicereg.InterfaceID = InterfaceID;
2321     request->u.servicereg.instances = NULL;
2322     request->u.servicereg.txtlen  = 0;
2323     request->u.servicereg.txtdata = NULL;
2324     mDNSPlatformStrLCopy(request->u.servicereg.type_as_string, type_as_string, sizeof(request->u.servicereg.type_as_string));
2325 
2326     if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
2327     else
2328     {
2329         request->u.servicereg.port.b[0] = *request->msgptr++;
2330         request->u.servicereg.port.b[1] = *request->msgptr++;
2331     }
2332 
2333     request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
2334     msgTXTData = get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen);
2335 
2336     if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2337 
2338     if (request->u.servicereg.txtlen)
2339     {
2340         request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
2341         if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
2342         mDNSPlatformMemCopy(request->u.servicereg.txtdata, msgTXTData, request->u.servicereg.txtlen);
2343     }
2344 
2345     // Check for sub-types after the service type
2346     request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string);    // Note: Modifies regtype string to remove trailing subtypes
2347     if (request->u.servicereg.num_subtypes < 0)
2348     {
2349         LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string);
2350         goto bad_param;
2351     }
2352 
2353     // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2354     if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
2355     { LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); goto bad_param; }
2356 
2357     if (!name[0])
2358     {
2359         request->u.servicereg.name = mDNSStorage.nicelabel;
2360         request->u.servicereg.autoname = mDNStrue;
2361     }
2362     else
2363     {
2364         // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2365         if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2366         {
2367             int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2368             name[newlen] = 0;
2369         }
2370         if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
2371         { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2372         request->u.servicereg.autoname = mDNSfalse;
2373     }
2374 
2375     if (*domain)
2376     {
2377         request->u.servicereg.default_domain = mDNSfalse;
2378         if (!MakeDomainNameFromDNSNameString(&d, domain))
2379         { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2380     }
2381     else
2382     {
2383         request->u.servicereg.default_domain = mDNStrue;
2384         MakeDomainNameFromDNSNameString(&d, "local.");
2385     }
2386 
2387     if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
2388     {
2389         LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
2390                request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); goto bad_param;
2391     }
2392 
2393     if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
2394     { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2395     request->u.servicereg.autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
2396     request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2397 
2398     // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2399     // a port number of zero. When two instances of the protected client are allowed to run on one
2400     // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2401     if (!mDNSIPPortIsZero(request->u.servicereg.port))
2402     {
2403         int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
2404         if (count)
2405             LogMsg("Client application[%d](%s) registered %d identical instances of service %##s port %u.", request->process_id,
2406                    request->pid_name, count+1, srv.c, mDNSVal16(request->u.servicereg.port));
2407     }
2408 
2409 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2410     // Determine if this request should be promoted to use BLE triggered feature.
2411     if (shouldUseBLE(InterfaceID, 0, &request->u.servicereg.type, &d))
2412     {
2413         request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
2414         LogInfo("handle_regservice_request: registration promoted to use kDNSServiceFlagsAutoTrigger");
2415     }
2416 #endif  // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2417 
2418     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
2419            "[R%d] DNSServiceRegister(%X, %d, \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", %u) START PID[%d](" PUB_S ")",
2420            request->request_id, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
2421            mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
2422 
2423     // We need to unconditionally set request->terminate, because even if we didn't successfully
2424     // start any registrations right now, subsequent configuration changes may cause successful
2425     // registrations to be added, and we'll need to cancel them before freeing this memory.
2426     // We also need to set request->terminate first, before adding additional service instances,
2427     // because the udsserver_validatelists uses the request->terminate function pointer to determine
2428     // what kind of request this is, and therefore what kind of list validation is required.
2429     request->terminate = NULL;
2430 
2431 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
2432     if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
2433         (request->u.servicereg.default_domain || IsLocalDomain(&d)))
2434     {
2435         err = _handle_regservice_request_with_trust(request, &d);
2436         if (err == mStatus_NoAuth && request->u.servicereg.txtdata)
2437         {
2438             freeL("service_info txtdata", request->u.servicereg.txtdata);
2439             request->u.servicereg.txtdata = NULL;
2440         }
2441     }
2442     else
2443     {
2444         err = _handle_regservice_request_start(request, &d);
2445     }
2446 #else
2447     err = _handle_regservice_request_start(request, &d);
2448 #endif
2449 
2450     return(err);
2451 
2452 bad_param:
2453     freeL("handle_regservice_request (txtdata)", request->u.servicereg.txtdata);
2454     request->u.servicereg.txtdata = NULL;
2455     return mStatus_BadParamErr;
2456 }
2457 
2458 // ***************************************************************************
2459 #if COMPILER_LIKES_PRAGMA_MARK
2460 #pragma mark -
2461 #pragma mark - DNSServiceBrowse
2462 #endif
2463 
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)2464 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2465 {
2466     DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
2467     request_state *req = question->