<rdar://problem/7022715> SHARED: Bonjour servers in Finder disappear and never return
[people/sha0/mDNSResponder.git] / mDNSShared / uds_daemon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  * 
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #if defined(_WIN32)
19 #include <process.h>
20 #define usleep(X) Sleep(((X)+999)/1000)
21 #else
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #include "mDNSEmbeddedAPI.h"
34 #include "DNSCommon.h"
35 #include "uDNS.h"
36 #include "uds_daemon.h"
37
38 // Apple-specific functionality, not required for other platforms
39 #if APPLE_OSX_mDNSResponder
40 #include <sys/ucred.h>
41 #ifndef PID_FILE
42 #define PID_FILE ""
43 #endif
44 #endif
45
46 // User IDs 0-500 are system-wide processes, not actual users in the usual sense
47 // User IDs for real user accounts start at 501 and count up from there
48 #define SystemUID(X) ((X) <= 500)
49
50 // ***************************************************************************
51 #if COMPILER_LIKES_PRAGMA_MARK
52 #pragma mark -
53 #pragma mark - Types and Data Structures
54 #endif
55
56 typedef enum
57         {
58         t_uninitialized,
59         t_morecoming,
60         t_complete,
61         t_error,
62         t_terminated
63         } transfer_state;
64
65 typedef struct request_state request_state;
66
67 typedef void (*req_termination_fn)(request_state *request);
68
69 typedef struct registered_record_entry
70         {
71         struct registered_record_entry *next;
72         mDNSu32 key;
73         AuthRecord *rr;                         // Pointer to variable-sized AuthRecord
74         client_context_t regrec_client_context;
75         request_state *request;
76         } registered_record_entry;
77
78 // A single registered service: ServiceRecordSet + bookkeeping
79 // Note that we duplicate some fields from parent service_info object
80 // to facilitate cleanup, when instances and parent may be deallocated at different times.
81 typedef struct service_instance
82         {
83         struct service_instance *next;
84         request_state *request;
85         AuthRecord *subtypes;
86         mDNSBool renameonmemfree;               // Set on config change when we deregister original name
87     mDNSBool clientnotified;            // Has client been notified of successful registration yet?
88         mDNSBool default_local;                 // is this the "local." from an empty-string registration?
89         domainname domain;
90         ServiceRecordSet srs;                   // note -- variable-sized object -- must be last field in struct
91         } service_instance;
92
93 // for multi-domain default browsing
94 typedef struct browser_t
95         {
96         struct browser_t *next;
97         domainname domain;
98         DNSQuestion q;
99         } browser_t;
100
101 struct request_state
102         {
103         request_state *next;
104         request_state *primary;                 // If this operation is on a shared socket, pointer to primary
105                                                                         // request_state for the original DNSServiceConnect() operation
106         dnssd_sock_t sd;
107         dnssd_sock_t errsd;
108         mDNSu32 uid;
109
110         // Note: On a shared connection these fields in the primary structure, including hdr, are re-used
111         // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
112         // operation is, we don't know if we're going to need to allocate a new request_state or not.
113         transfer_state ts;
114         mDNSu32        hdr_bytes;               // bytes of header already read
115         ipc_msg_hdr    hdr;
116         mDNSu32        data_bytes;              // bytes of message data already read
117         char          *msgbuf;                  // pointer to data storage to pass to free()
118         const char    *msgptr;                  // pointer to data to be read from (may be modified)
119         char          *msgend;                  // pointer to byte after last byte of message
120
121         // reply, termination, error, and client context info
122         int no_reply;                                   // don't send asynchronous replies to client
123         mDNSs32 time_blocked;                   // record time of a blocked client
124         int unresponsiveness_reports;
125         struct reply_state *replies;    // corresponding (active) reply list
126         req_termination_fn terminate;
127
128         union
129                 {
130                 registered_record_entry *reg_recs;  // list of registrations for a connection-oriented request
131                 struct
132                         {
133                         mDNSInterfaceID interface_id;
134                         mDNSBool default_domain;
135                         mDNSBool ForceMCast;
136                         domainname regtype;
137                         browser_t *browsers;
138                         } browser;
139                 struct
140                         {
141                         mDNSInterfaceID InterfaceID;
142                         mDNSu16 txtlen;
143                         void *txtdata;
144                         mDNSIPPort port;
145                         domainlabel name;
146                         char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
147                         domainname type;
148                         mDNSBool default_domain;
149                         domainname host;
150                         mDNSBool autoname;                              // Set if this name is tied to the Computer Name
151                         mDNSBool autorename;                    // Set if this client wants us to automatically rename on conflict
152                         mDNSBool allowremotequery;              // Respond to unicast queries from outside the local link?
153                         int num_subtypes;
154                         service_instance *instances;
155                         } servicereg;
156                 struct
157                         {
158                         mDNSInterfaceID      interface_id;
159                         mDNSu32              flags;
160                         mDNSu32              protocol;
161                         DNSQuestion          q4;
162                         DNSQuestion          q6;
163                         } addrinfo;
164                 struct
165                         {
166                         mDNSIPPort           ReqExt;    // External port we originally requested, for logging purposes
167                         NATTraversalInfo     NATinfo;
168                         } pm;
169                 struct
170                         {
171 #if 0
172                         DNSServiceFlags flags;
173 #endif
174                         DNSQuestion q_all;
175                         DNSQuestion q_default;
176                         } enumeration;
177                 struct
178                         {
179                         DNSQuestion q;
180                         DNSQuestion q2;
181                         } queryrecord;
182                 struct
183                         {
184                         DNSQuestion qtxt;
185                         DNSQuestion qsrv;
186                         const ResourceRecord *txt;
187                         const ResourceRecord *srv;
188                         mDNSs32 ReportTime;
189                         } resolve;
190                 } u;
191         };
192
193 // struct physically sits between ipc message header and call-specific fields in the message buffer
194 typedef struct
195         {
196         DNSServiceFlags flags;                  // Note: This field is in NETWORK byte order
197         mDNSu32 ifi;                                    // Note: This field is in NETWORK byte order
198         DNSServiceErrorType error;              // Note: This field is in NETWORK byte order
199         } reply_hdr;
200
201 typedef struct reply_state
202         {
203         struct reply_state *next;               // If there are multiple unsent replies
204         mDNSu32 totallen;
205         mDNSu32 nwriten;
206         ipc_msg_hdr mhdr[1];
207         reply_hdr rhdr[1];
208         } reply_state;
209
210 // ***************************************************************************
211 #if COMPILER_LIKES_PRAGMA_MARK
212 #pragma mark -
213 #pragma mark - Globals
214 #endif
215
216 // globals
217 mDNSexport mDNS mDNSStorage;
218 mDNSexport const char ProgramName[] = "mDNSResponder";
219
220 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
221 static request_state *all_requests = NULL;
222
223 static DNameListElem *SCPrefBrowseDomains;                      // List of automatic browsing domains read from SCPreferences for "empty string" browsing
224 static ARListElem    *LocalDomainEnumRecords;           // List of locally-generated PTR records to augment those we learn from the network
225 mDNSexport DNameListElem *AutoBrowseDomains;            // List created from those local-only PTR records plus records we get from the network
226
227 mDNSexport DNameListElem *AutoRegistrationDomains;      // Domains where we automatically register for empty-string registrations
228
229 #define MSG_PAD_BYTES 5         // pad message buffer (read from client) with n zero'd bytes to guarantee
230                                                         // n get_string() calls w/o buffer overrun
231 // initialization, setup/teardown functions
232
233 // If a platform specifies its own PID file name, we use that
234 #ifndef PID_FILE
235 #define PID_FILE "/var/run/mDNSResponder.pid"
236 #endif
237
238 // ***************************************************************************
239 #if COMPILER_LIKES_PRAGMA_MARK
240 #pragma mark -
241 #pragma mark - General Utility Functions
242 #endif
243
244 mDNSlocal void FatalError(char *errmsg)
245         {
246         LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
247         *(long*)0 = 0;  // On OS X abort() doesn't generate a crash log, but writing to zero does
248         abort();                // On platforms where writing to zero doesn't generate an exception, abort instead
249         }
250
251 mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
252         {
253         mDNSu32 ret;
254         char *data = (char*) &ret;
255         put_uint32(l, &data);
256         return ret;
257         }
258
259 // hack to search-replace perror's to LogMsg's
260 mDNSlocal void my_perror(char *errmsg)
261         {
262         LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno));
263         }
264
265 mDNSlocal void abort_request(request_state *req)
266         {
267         if (req->terminate == (req_termination_fn)~0)
268                 { LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
269         
270         // First stop whatever mDNSCore operation we were doing
271         if (req->terminate) req->terminate(req);
272
273         if (!dnssd_SocketValid(req->sd))
274                 { LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d",     req, req->sd);        return; }
275         
276         // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
277         if (!req->primary)
278                 {
279                 if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
280                 else                       LogOperation("%3d: Removing FD", req->sd);
281                 udsSupportRemoveFDFromEventLoop(req->sd);               // Note: This also closes file descriptor req->sd for us
282                 if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
283
284                 while (req->replies)    // free pending replies
285                         {
286                         reply_state *ptr = req->replies;
287                         req->replies = req->replies->next;
288                         freeL("reply_state (abort)", ptr);
289                         }
290                 }
291
292         // Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
293 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
294         // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
295         // for detecting when the memory for an object is inadvertently freed while the object is still on some list
296         req->sd = req->errsd = -2;
297 #else
298         req->sd = req->errsd = dnssd_InvalidSocket;
299 #endif
300         // We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request
301         req->terminate = (req_termination_fn)~0;
302         }
303
304 mDNSlocal void AbortUnlinkAndFree(request_state *req)
305         {
306         request_state **p = &all_requests;
307         abort_request(req);
308         while (*p && *p != req) p=&(*p)->next;
309         if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
310         else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
311         }
312
313 mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
314         {
315         reply_state *reply;
316
317         if ((unsigned)datalen < sizeof(reply_hdr))
318                 {
319                 LogMsg("ERROR: create_reply - data length less than length of required fields");
320                 return NULL;
321                 }
322
323         reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
324         if (!reply) FatalError("ERROR: malloc");
325         
326         reply->next     = mDNSNULL;
327         reply->totallen = datalen + sizeof(ipc_msg_hdr);
328         reply->nwriten  = 0;
329
330         reply->mhdr->version        = VERSION;
331         reply->mhdr->datalen        = datalen;
332         reply->mhdr->ipc_flags      = 0;
333         reply->mhdr->op             = op;
334         reply->mhdr->client_context = request->hdr.client_context;
335         reply->mhdr->reg_index      = 0;
336
337         return reply;
338         }
339
340 // Append a reply to the list in a request object
341 // If our request is sharing a connection, then we append our reply_state onto the primary's list
342 mDNSlocal void append_reply(request_state *req, reply_state *rep)
343         {
344         request_state *r = req->primary ? req->primary : req;
345         reply_state **ptr = &r->replies;
346         while (*ptr) ptr = &(*ptr)->next;
347         *ptr = rep;
348         rep->next = NULL;
349         }
350
351 // Generates a response message giving name, type, domain, plus interface index,
352 // suitable for a browse result or service registration result.
353 // On successful completion rep is set to point to a malloc'd reply_state struct
354 mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
355         request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
356         {
357         domainlabel name;
358         domainname type, dom;
359         *rep = NULL;
360         if (!DeconstructServiceName(servicename, &name, &type, &dom))
361                 return kDNSServiceErr_Invalid;
362         else
363                 {
364                 char namestr[MAX_DOMAIN_LABEL+1];
365                 char typestr[MAX_ESCAPED_DOMAIN_NAME];
366                 char domstr [MAX_ESCAPED_DOMAIN_NAME];
367                 int len;
368                 char *data;
369
370                 ConvertDomainLabelToCString_unescaped(&name, namestr);
371                 ConvertDomainNameToCString(&type, typestr);
372                 ConvertDomainNameToCString(&dom, domstr);
373
374                 // Calculate reply data length
375                 len = sizeof(DNSServiceFlags);
376                 len += sizeof(mDNSu32);  // if index
377                 len += sizeof(DNSServiceErrorType);
378                 len += (int) (strlen(namestr) + 1);
379                 len += (int) (strlen(typestr) + 1);
380                 len += (int) (strlen(domstr) + 1);
381
382                 // Build reply header
383                 *rep = create_reply(op, len, request);
384                 (*rep)->rhdr->flags = dnssd_htonl(flags);
385                 (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id));
386                 (*rep)->rhdr->error = dnssd_htonl(err);
387
388                 // Build reply body
389                 data = (char *)&(*rep)->rhdr[1];
390                 put_string(namestr, &data);
391                 put_string(typestr, &data);
392                 put_string(domstr, &data);
393
394                 return mStatus_NoError;
395                 }
396         }
397
398 // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
399 // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
400 mDNSlocal void GenerateBonjourBrowserResponse(const domainname *const servicename, const mDNSInterfaceID id,
401         request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
402         {
403         char namestr[MAX_DOMAIN_LABEL+1];
404         char typestr[MAX_ESCAPED_DOMAIN_NAME];
405         static const char domstr[] = ".";
406         int len;
407         char *data;
408
409         *rep = NULL;
410
411         // 1. Put first label in namestr
412         ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
413
414         // 2. Put second label and "local" into typestr
415         mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
416
417         // Calculate reply data length
418         len = sizeof(DNSServiceFlags);
419         len += sizeof(mDNSu32);  // if index
420         len += sizeof(DNSServiceErrorType);
421         len += (int) (strlen(namestr) + 1);
422         len += (int) (strlen(typestr) + 1);
423         len += (int) (strlen(domstr) + 1);
424
425         // Build reply header
426         *rep = create_reply(op, len, request);
427         (*rep)->rhdr->flags = dnssd_htonl(flags);
428         (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id));
429         (*rep)->rhdr->error = dnssd_htonl(err);
430
431         // Build reply body
432         data = (char *)&(*rep)->rhdr[1];
433         put_string(namestr, &data);
434         put_string(typestr, &data);
435         put_string(domstr, &data);
436         }
437
438 // Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
439 // Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
440 // (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
441 mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
442         {
443         DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
444         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
445         char name[256];
446         int         str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
447         mDNSu16     type    = get_uint16(&request->msgptr, request->msgend);
448         mDNSu16     class   = get_uint16(&request->msgptr, request->msgend);
449         mDNSu16     rdlen   = get_uint16(&request->msgptr, request->msgend);
450         const char *rdata   = get_rdata (&request->msgptr, request->msgend, rdlen);
451         mDNSu32 ttl   = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
452         int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
453         AuthRecord *rr;
454
455         if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
456
457         if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
458
459         if (validate_flags &&
460                 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
461                 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
462                 {
463                 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
464                 return NULL;
465                 }
466
467         rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
468         if (!rr) FatalError("ERROR: malloc");
469         mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex),
470                 type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
471
472         if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
473                 {
474                 LogMsg("ERROR: bad name: %s", name);
475                 freeL("AuthRecord/read_rr_from_ipc_msg", rr);
476                 return NULL;
477                 }
478
479         if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
480         rr->resrec.rrclass = class;
481         rr->resrec.rdlength = rdlen;
482         rr->resrec.rdata->MaxRDLength = rdlen;
483         mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlen);
484         if (GetTTL) rr->resrec.rroriginalttl = ttl;
485         rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
486         SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
487         return rr;
488         }
489
490 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
491         {
492         domainlabel n;
493         domainname d, t;
494
495         if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
496         if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
497         if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
498         if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
499         return 0;
500         }
501
502 mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
503         {
504         int n = send(s, ptr, len, 0);
505         // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
506         // (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
507         // If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
508         if (n < len)
509                 LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d (%s)",
510                         s, n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
511         }
512
513 #if 0
514 mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms)
515 {
516         const           DNameListElem   *delem = mDNSNULL;
517         int             bestDelta       = -1;                                   // the delta of the best match, lower is better
518         int             dLabels         = 0;
519         mDNSBool        allow           = mDNSfalse;
520         
521         if (SystemUID(request->uid)) return mDNStrue;
522         
523         dLabels = CountLabels(d);
524         for (delem = doms; delem; delem = delem->next)
525                 {
526                 if (delem->uid)
527                         {
528                         int     delemLabels = CountLabels(&delem->name);
529                         int delta               = dLabels - delemLabels;
530                         if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta)))
531                                 {
532                                 bestDelta = delta;
533                                 allow = (allow || (delem->uid == request->uid));
534                                 }
535                         }
536                 }
537         
538         return bestDelta == -1 ? mDNStrue : allow;
539 }
540 #endif
541
542 // ***************************************************************************
543 #if COMPILER_LIKES_PRAGMA_MARK
544 #pragma mark -
545 #pragma mark - DNSServiceRegister
546 #endif
547
548 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
549         {
550         ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
551         (void)m;  // Unused
552
553         if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
554
555         LogInfo("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
556
557         if (rr->resrec.rdata != &rr->rdatastorage)
558                 freeL("Extra RData", rr->resrec.rdata);
559         freeL("ExtraResourceRecord/FreeExtraRR", extra);
560         }
561
562 mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
563         {
564         ExtraResourceRecord *e = srv->srs.Extras, *tmp;
565
566         // clear pointers from parent struct
567         if (srv->request)
568                 {
569                 service_instance **p = &srv->request->u.servicereg.instances;
570                 while (*p)
571                         {
572                         if (*p == srv) { *p = (*p)->next; break; }
573                         p = &(*p)->next;
574                         }
575                 }
576
577         while (e)
578                 {
579                 e->r.RecordContext = e;
580                 tmp = e;
581                 e = e->next;
582                 FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
583                 }
584
585         if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
586                 freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
587
588         if (srv->subtypes) { freeL("ServiceSubTypes", srv->subtypes); srv->subtypes = NULL; }
589         freeL("service_instance", srv);
590         }
591
592 // Count how many other service records we have locally with the same name, but different rdata.
593 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
594 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
595 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
596         {
597         int count = 0;
598         ResourceRecord *r = &srs->RR_SRV.resrec;
599         AuthRecord *rr;
600         ServiceRecordSet *s;
601
602         for (rr = m->ResourceRecords; rr; rr=rr->next)
603                 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
604                         count++;
605
606         for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
607                 if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !IdenticalSameNameRecord(&s->RR_SRV.resrec, r))
608                         count++;
609
610         verbosedebugf("%d peer registrations for %##s", count, r->name->c);
611         return(count);
612         }
613
614 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
615         {
616         int count = 0;
617         AuthRecord *rr;
618         for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
619                 if (rr->resrec.rrtype == kDNSType_SRV &&
620                         mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
621                         SameDomainName(rr->resrec.name, srv))
622                         count++;
623         return(count);
624         }
625
626 mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
627         {
628         reply_state *rep;
629         service_instance *instance = srs->ServiceContext;
630         if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
631                 LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
632         else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; }
633         }
634
635 // service registration callback performs three duties - frees memory for deregistered services,
636 // handles name conflicts, and delivers completed registration information to the client
637 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
638         {
639         mStatus err;
640         mDNSBool SuppressError = mDNSfalse;
641         service_instance *instance = srs->ServiceContext;
642         reply_state         *rep;
643         char *fmt = "";
644         if (mDNS_LoggingEnabled)
645                 fmt = (result == mStatus_NoError)      ? "%3d: DNSServiceRegister(%##s, %u) REGISTERED"    :
646                           (result == mStatus_MemFree)      ? "%3d: DNSServiceRegister(%##s, %u) DEREGISTERED"  :
647                           (result == mStatus_NameConflict) ? "%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT" :
648                                                              "%3d: DNSServiceRegister(%##s, %u) %s %d";
649         (void)m; // Unused
650         if (!srs)      { LogMsg("regservice_callback: srs is NULL %d",                 result); return; }
651         if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
652
653         // don't send errors up to client for wide-area, empty-string registrations
654         if (instance->request &&
655                 instance->request->u.servicereg.default_domain &&
656                 !instance->default_local)
657                 SuppressError = mDNStrue;
658
659         LogOperation(fmt, instance->request ? instance->request->sd : -99,
660                 srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result);
661
662         if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
663
664         if (result == mStatus_NoError)
665                 {
666                 if (instance->request->u.servicereg.allowremotequery)
667                         {
668                         ExtraResourceRecord *e;
669                         srs->RR_ADV.AllowRemoteQuery = mDNStrue;
670                         srs->RR_PTR.AllowRemoteQuery = mDNStrue;
671                         srs->RR_SRV.AllowRemoteQuery = mDNStrue;
672                         srs->RR_TXT.AllowRemoteQuery = mDNStrue;
673                         for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
674                         }
675
676                 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
677                         LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
678                 else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
679
680                 if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
681                         RecordUpdatedNiceLabel(m, 0);   // Successfully got new name, tell user immediately
682                 }
683         else if (result == mStatus_MemFree)
684                 {
685                 if (instance->request && instance->renameonmemfree)
686                         {
687                         instance->renameonmemfree = 0;
688                         err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
689                         if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
690                         // error should never happen - safest to log and continue
691                         }
692                 else
693                         unlink_and_free_service_instance(instance);
694                 }
695         else if (result == mStatus_NameConflict)
696                 {
697                 if (instance->request->u.servicereg.autorename)
698                         {
699                         if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
700                                 {
701                                 // On conflict for an autoname service, rename and reregister *all* autoname services
702                                 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
703                                 mDNS_ConfigChanged(m);  // Will call back into udsserver_handle_configchange()
704                                 }
705                         else    // On conflict for a non-autoname service, rename and reregister just that one service
706                                 {
707                                 if (instance->clientnotified) SendServiceRemovalNotification(srs);
708                                 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
709                                 }
710                         }
711                 else
712                         {
713                         if (!SuppressError) 
714                                 {
715                                 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
716                                         LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
717                                 else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
718                                 }
719                         unlink_and_free_service_instance(instance);
720                         }
721                 }
722         else
723                 {
724                 if (!SuppressError) 
725                         {
726                         if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
727                                 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
728                         else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
729                         }
730                 }
731         }
732
733 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
734         {
735         (void)m; // Unused
736         if (!rr->RecordContext)         // parent struct already freed by termination callback
737                 {
738                 if (result == mStatus_NoError)
739                         LogMsg("Error: regrecord_callback: successful registration of orphaned record");
740                 else
741                         {
742                         if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
743                         freeL("AuthRecord/regrecord_callback", rr);
744                         }
745                 }
746         else
747                 {
748                 registered_record_entry *re = rr->RecordContext;
749                 request_state *request = re->request;
750                 int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
751                 reply_state *reply = create_reply(reg_record_reply_op, len, request);
752                 reply->mhdr->client_context = re->regrec_client_context;
753                 reply->rhdr->flags = dnssd_htonl(0);
754                 reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
755                 reply->rhdr->error = dnssd_htonl(result);
756
757                 LogOperation("%3d: DNSServiceRegisterRecord(%u) result %d", request->sd, request->hdr.reg_index, result);
758                 if (result)
759                         {
760                         // unlink from list, free memory
761                         registered_record_entry **ptr = &request->u.reg_recs;
762                         while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
763                         if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
764                         *ptr = (*ptr)->next;
765                         freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
766                         freeL("registered_record_entry regrecord_callback", re);
767                         }
768                 append_reply(request, reply);
769                 }
770         }
771
772 mDNSlocal void connection_termination(request_state *request)
773         {
774         request_state **req = &all_requests;
775         while (*req)
776                 {
777                 if ((*req)->primary == request)
778                         {
779                         // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
780                         request_state *tmp = *req;
781                         if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d",                  tmp, tmp->sd);
782                         if (tmp->replies)        LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
783                         abort_request(tmp);
784                         *req = tmp->next;
785                         freeL("request_state/connection_termination", tmp);
786                         }
787                 else
788                         req = &(*req)->next;
789                 }
790
791         while (request->u.reg_recs)
792                 {
793                 registered_record_entry *ptr = request->u.reg_recs;
794                 request->u.reg_recs = request->u.reg_recs->next;
795                 ptr->rr->RecordContext = NULL;
796                 mDNS_Deregister(&mDNSStorage, ptr->rr);         // Will free ptr->rr for us
797                 freeL("registered_record_entry/connection_termination", ptr);
798                 }
799         }
800
801 mDNSlocal void handle_cancel_request(request_state *request)
802         {
803         request_state **req = &all_requests;
804         LogOperation("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
805         while (*req)
806                 {
807                 if ((*req)->primary == request &&
808                         (*req)->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
809                         (*req)->hdr.client_context.u32[1] == request->hdr.client_context.u32[1])
810                         {
811                         // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
812                         request_state *tmp = *req;
813                         abort_request(tmp);
814                         *req = tmp->next;
815                         freeL("request_state/handle_cancel_request", tmp);
816                         }
817                 else
818                         req = &(*req)->next;
819                 }
820         }
821
822 mDNSlocal mStatus handle_regrecord_request(request_state *request)
823         {
824         mStatus err = mStatus_BadParamErr;
825         AuthRecord *rr = read_rr_from_ipc_msg(request, 1, 1);
826         if (rr)
827                 {
828                 // allocate registration entry, link into list
829                 registered_record_entry *re = mallocL("registered_record_entry", sizeof(registered_record_entry));
830                 if (!re) FatalError("ERROR: malloc");
831                 re->key = request->hdr.reg_index;
832                 re->rr = rr;
833                 re->request = request;
834                 re->regrec_client_context = request->hdr.client_context;
835                 rr->RecordContext = re;
836                 rr->RecordCallback = regrecord_callback;
837                 re->next = request->u.reg_recs;
838                 request->u.reg_recs = re;
839         
840 #if 0
841                 if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains))       return (mStatus_NoError);
842 #endif
843                 if (rr->resrec.rroriginalttl == 0)
844                         rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
845         
846                 LogOperation("%3d: DNSServiceRegisterRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &rr->resrec));
847                 err = mDNS_Register(&mDNSStorage, rr);
848                 }
849         return(err);
850         }
851
852 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
853
854 mDNSlocal void regservice_termination_callback(request_state *request)
855         {
856         if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; }
857         while (request->u.servicereg.instances)
858                 {
859                 service_instance *p = request->u.servicereg.instances;
860                 request->u.servicereg.instances = request->u.servicereg.instances->next;
861                 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
862                 LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP",
863                         request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
864
865                 // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
866                 // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
867                 // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
868                 // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
869                 // because by then we might have already freed p
870                 p->request = NULL;
871                 if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p);
872                 // Don't touch service_instance *p after this -- it's likely to have been freed already
873                 }
874         if (request->u.servicereg.txtdata)
875                 { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
876         if (request->u.servicereg.autoname)
877                 {
878                 // Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations
879                 request->u.servicereg.autoname = mDNSfalse;
880                 UpdateDeviceInfoRecord(&mDNSStorage);
881                 }
882         }
883
884 mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
885         {
886         request_state *req;
887         for (req = all_requests; req; req = req->next)
888                 if (req->primary == request &&
889                         req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
890                         req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req);
891         return(request);
892         }
893
894 mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
895         {
896         ServiceRecordSet *srs = &instance->srs;
897         mStatus result;
898         int size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
899         ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
900         if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
901
902         mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
903         extra->r.resrec.rrtype = rrtype;
904         extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
905         extra->r.resrec.rdlength = rdlen;
906         mDNSPlatformMemCopy(&extra->r.rdatastorage.u.data, rdata, rdlen);
907
908         result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl);
909         if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
910
911         extra->ClientID = request->hdr.reg_index;
912         return result;
913         }
914
915 mDNSlocal mStatus handle_add_request(request_state *request)
916         {
917         service_instance *i;
918         mStatus result = mStatus_UnknownErr;
919         DNSServiceFlags flags  = get_flags (&request->msgptr, request->msgend);
920         mDNSu16         rrtype = get_uint16(&request->msgptr, request->msgend);
921         mDNSu16         rdlen  = get_uint16(&request->msgptr, request->msgend);
922         const char     *rdata  = get_rdata (&request->msgptr, request->msgend, rdlen);
923         mDNSu32         ttl    = get_uint32(&request->msgptr, request->msgend);
924         if (!ttl) ttl = DefaultTTLforRRType(rrtype);
925         (void)flags; // Unused
926
927         if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
928
929         // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
930         if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
931
932         if (request->terminate != regservice_termination_callback)
933                 { LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
934
935         LogOperation("%3d: DNSServiceAddRecord(%##s, %s, %d)", request->sd,
936                 (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen);
937
938         for (i = request->u.servicereg.instances; i; i = i->next)
939                 {
940                 result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
941                 if (result && i->default_local) break;
942                 else result = mStatus_NoError;  // suppress non-local default errors
943                 }
944
945         return(result);
946         }
947
948 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
949         {
950         (void)m; // Unused
951         if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
952         }
953
954 mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
955         {
956         int rdsize;
957         RData *newrd;
958         mStatus result;
959
960         if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
961         else rdsize = sizeof(RDataBody);
962         newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
963         if (!newrd) FatalError("ERROR: malloc");
964         newrd->MaxRDLength = (mDNSu16) rdsize;
965         mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
966
967         // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
968         // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
969         // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
970         if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
971
972         result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
973         if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("RData/update_record", newrd); }
974         return result;
975         }
976
977 mDNSlocal mStatus handle_update_request(request_state *request)
978         {
979         const ipc_msg_hdr *const hdr = &request->hdr;
980         mStatus result = mStatus_BadReferenceErr;
981         service_instance *i;
982         AuthRecord *rr = NULL;
983
984         // get the message data
985         DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);  // flags unused
986         mDNSu16         rdlen = get_uint16(&request->msgptr, request->msgend);
987         const char     *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
988         mDNSu32         ttl   = get_uint32(&request->msgptr, request->msgend);
989         (void)flags; // Unused
990
991         if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
992
993         // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
994         if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
995
996         if (request->terminate == connection_termination)
997                 {
998                 // update an individually registered record
999                 registered_record_entry *reptr;
1000                 for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
1001                         {
1002                         if (reptr->key == hdr->reg_index)
1003                                 {
1004                                 result = update_record(reptr->rr, rdlen, rdata, ttl);
1005                                 goto end;
1006                                 }
1007                         }
1008                 result = mStatus_BadReferenceErr;
1009                 goto end;
1010                 }
1011
1012         if (request->terminate != regservice_termination_callback)
1013                 { LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
1014
1015         // update the saved off TXT data for the service
1016         if (hdr->reg_index == TXT_RECORD_INDEX)
1017                 {
1018                 if (request->u.servicereg.txtdata)
1019                         { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
1020                 if (rdlen > 0)
1021                         {
1022                         request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen);
1023                         if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
1024                         mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
1025                         }
1026                 else
1027                         request->u.servicereg.txtdata = NULL;
1028                 }
1029
1030         // update a record from a service record set
1031         for (i = request->u.servicereg.instances; i; i = i->next)
1032                 {
1033                 if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
1034                 else
1035                         {
1036                         ExtraResourceRecord *e;
1037                         for (e = i->srs.Extras; e; e = e->next)
1038                                 if (e->ClientID == hdr->reg_index) { rr = &e->r; break; }
1039                         }
1040
1041                 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
1042                 result = update_record(rr, rdlen, rdata, ttl);
1043                 if (result && i->default_local) goto end;
1044                 else result = mStatus_NoError;  // suppress non-local default errors
1045                 }
1046
1047 end:
1048         if (request->terminate == regservice_termination_callback)
1049                 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
1050                         (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
1051                         rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
1052
1053         return(result);
1054         }
1055
1056 // remove a resource record registered via DNSServiceRegisterRecord()
1057 mDNSlocal mStatus remove_record(request_state *request)
1058         {
1059         mStatus err = mStatus_UnknownErr;
1060         registered_record_entry *e, **ptr = &request->u.reg_recs;
1061
1062         while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
1063         if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
1064         e = *ptr;
1065         *ptr = e->next; // unlink
1066
1067         LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &e->rr->resrec));
1068         e->rr->RecordContext = NULL;
1069         err = mDNS_Deregister(&mDNSStorage, e->rr);
1070         if (err)
1071                 {
1072                 LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
1073                 freeL("registered_record_entry AuthRecord remove_record", e->rr);
1074                 }
1075         freeL("registered_record_entry remove_record", e);
1076         return err;
1077         }
1078
1079 mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
1080         {
1081         mStatus err = mStatus_BadReferenceErr;
1082         ExtraResourceRecord *ptr;
1083
1084         for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)              
1085                 {
1086                 if (ptr->ClientID == request->hdr.reg_index) // found match
1087                         {
1088                         *rrtype = ptr->r.resrec.rrtype;
1089                         return mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
1090                         }
1091                 }
1092         return err;
1093         }
1094
1095 mDNSlocal mStatus handle_removerecord_request(request_state *request)
1096         {
1097         mStatus err = mStatus_BadReferenceErr;
1098         get_flags(&request->msgptr, request->msgend);   // flags unused
1099
1100         if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
1101
1102         // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1103         if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1104
1105         if (request->terminate == connection_termination)
1106                 err = remove_record(request);  // remove individually registered record
1107         else if (request->terminate != regservice_termination_callback)
1108                 { LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
1109         else
1110                 {
1111                 service_instance *i;
1112                 mDNSu16 rrtype = 0;
1113                 LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", request->sd,
1114                         (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
1115                         rrtype ? DNSTypeName(rrtype) : "<NONE>");
1116                 for (i = request->u.servicereg.instances; i; i = i->next)
1117                         {
1118                         err = remove_extra(request, i, &rrtype);
1119                         if (err && i->default_local) break;
1120                         else err = mStatus_NoError;  // suppress non-local default errors
1121                         }
1122                 }
1123
1124         return(err);
1125         }
1126
1127 // If there's a comma followed by another character,
1128 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1129 // Otherwise, it returns a pointer to the final nul at the end of the string
1130 mDNSlocal char *FindFirstSubType(char *p)
1131         {
1132         while (*p)
1133                 {
1134                 if (p[0] == '\\' && p[1]) p += 2;
1135                 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1136                 else p++;
1137                 }
1138         return(p);
1139         }
1140
1141 // If there's a comma followed by another character,
1142 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1143 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1144 // Otherwise, it returns a pointer to the final nul at the end of the string
1145 mDNSlocal char *FindNextSubType(char *p)
1146         {
1147         while (*p)
1148                 {
1149                 if (p[0] == '\\' && p[1])               // If escape character
1150                         p += 2;                                         // ignore following character
1151                 else if (p[0] == ',')                   // If we found a comma
1152                         {
1153                         if (p[1]) *p++ = 0;
1154                         return(p);
1155                         }
1156                 else if (p[0] == '.')
1157                         return(mDNSNULL);
1158                 else p++;
1159                 }
1160         return(p);
1161         }
1162
1163 // Returns -1 if illegal subtype found
1164 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1165         {
1166         mDNSs32 NumSubTypes = 0;
1167         char *stp = FindFirstSubType(regtype);
1168         while (stp && *stp)                                     // If we found a comma...
1169                 {
1170                 if (*stp == ',') return(-1);
1171                 NumSubTypes++;
1172                 stp = FindNextSubType(stp);
1173                 }
1174         if (!stp) return(-1);
1175         return(NumSubTypes);
1176         }
1177
1178 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1179         {
1180         AuthRecord *st = mDNSNULL;
1181         if (NumSubTypes)
1182                 {
1183                 mDNSs32 i;
1184                 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1185                 if (!st) return(mDNSNULL);
1186                 for (i = 0; i < NumSubTypes; i++)
1187                         {
1188                         mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1189                         while (*p) p++;
1190                         p++;
1191                         if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
1192                                 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1193                         }
1194                 }
1195         return(st);
1196         }
1197
1198 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
1199         {
1200         service_instance **ptr, *instance;
1201         int instance_size;
1202         mStatus result;
1203
1204         for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
1205                 {
1206                 if (SameDomainName(&(*ptr)->domain, domain))
1207                         {
1208                         LogMsg("register_service_instance: domain %##s already registered for %#s.%##s",
1209                                 domain->c, &request->u.servicereg.name, &request->u.servicereg.type);
1210                         return mStatus_AlreadyRegistered;
1211                         }
1212                 }
1213
1214         // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel
1215         // services have to support IPv6, and our SMB server does not
1216         // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
1217         if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
1218                 {
1219                 DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
1220                 if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
1221                 }
1222
1223         instance_size = sizeof(*instance);
1224         if (request->u.servicereg.txtlen > sizeof(RDataBody)) instance_size += (request->u.servicereg.txtlen - sizeof(RDataBody));
1225         instance = mallocL("service_instance", instance_size);
1226         if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
1227
1228         instance->next            = mDNSNULL;
1229         instance->request         = request;
1230         instance->subtypes        = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
1231         instance->renameonmemfree = 0;
1232         instance->clientnotified  = mDNSfalse;
1233         instance->default_local   = (request->u.servicereg.default_domain && SameDomainName(domain, &localdomain));
1234         AssignDomainName(&instance->domain, domain);
1235
1236         if (request->u.servicereg.num_subtypes && !instance->subtypes)
1237                 { unlink_and_free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
1238
1239         result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
1240                 &request->u.servicereg.name, &request->u.servicereg.type, domain,
1241                 request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
1242                 request->u.servicereg.port,
1243                 request->u.servicereg.txtdata, request->u.servicereg.txtlen,
1244                 instance->subtypes, request->u.servicereg.num_subtypes,
1245                 request->u.servicereg.InterfaceID, regservice_callback, instance);
1246
1247         if (!result)
1248                 {
1249                 *ptr = instance;                // Append this to the end of our request->u.servicereg.instances list
1250                 LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED",
1251                         instance->request->sd, instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
1252                 }
1253         else
1254                 {
1255                 LogMsg("register_service_instance %#s.%##s%##s error %d",
1256                         &request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
1257                 unlink_and_free_service_instance(instance);
1258                 }
1259
1260         return result;
1261         }
1262
1263 mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
1264         {
1265         request_state *request;
1266
1267 #if APPLE_OSX_mDNSResponder
1268         machserver_automatic_registration_domain_changed(&d->name, add);
1269 #endif // APPLE_OSX_mDNSResponder
1270
1271         LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
1272         for (request = all_requests; request; request = request->next)
1273                 {
1274                 if (request->terminate != regservice_termination_callback) continue;
1275                 if (!request->u.servicereg.default_domain) continue;
1276                 if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
1277                         {
1278                         service_instance **ptr = &request->u.servicereg.instances;
1279                         while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
1280                         if (add)
1281                                 {
1282                                 // If we don't already have this domain in our list for this registration, add it now
1283                                 if (!*ptr) register_service_instance(request, &d->name);
1284                                 else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
1285                                 }
1286                         else
1287                                 {
1288                                 // Normally we should not fail to find the specified instance
1289                                 // One case where this can happen is if a uDNS update fails for some reason,
1290                                 // and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
1291                                 if (!*ptr)
1292                                         LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
1293                                                 &d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
1294                                 else
1295                                         {
1296                                         DNameListElem *p;
1297                                         for (p = AutoRegistrationDomains; p; p=p->next)
1298                                                 if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
1299                                                         if (SameDomainName(&d->name, &p->name)) break;
1300                                         if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
1301                                         else
1302                                                 {
1303                                                 mStatus err;
1304                                                 service_instance *si = *ptr;
1305                                                 *ptr = si->next;
1306                                                 if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
1307                                                 // Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
1308                                                 // Otherwise what can happen is this: While our mDNS_DeregisterService is in the
1309                                                 // process of completing asynchronously, the client cancels the entire operation, so
1310                                                 // regservice_termination_callback then runs through the whole list deregistering each
1311                                                 // instance, clearing the backpointers, and then disposing the parent request_state object.
1312                                                 // However, because this service_instance isn't in the list any more, regservice_termination_callback
1313                                                 // has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
1314                                                 // completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
1315                                                 // a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
1316                                                 si->request = NULL;
1317                                                 err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
1318                                                 if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
1319                                                 }
1320                                         }
1321                                 }
1322                         }
1323                 }
1324         }
1325
1326 mDNSlocal mStatus handle_regservice_request(request_state *request)
1327         {
1328         char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
1329         char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
1330         char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
1331         domainname d, srv;
1332         mStatus err;
1333
1334         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
1335         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
1336         mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
1337         if (interfaceIndex && !InterfaceID)
1338                 { LogMsg("ERROR: handle_regservice_request - Couldn't find interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
1339
1340         if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
1341                 get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1342                 get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1343                 get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
1344                 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
1345
1346         request->u.servicereg.InterfaceID = InterfaceID;
1347         request->u.servicereg.instances = NULL;
1348         request->u.servicereg.txtlen  = 0;
1349         request->u.servicereg.txtdata = NULL;
1350         mDNSPlatformStrCopy(request->u.servicereg.type_as_string, type_as_string);
1351
1352         if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
1353         else
1354                 {
1355                 request->u.servicereg.port.b[0] = *request->msgptr++;
1356                 request->u.servicereg.port.b[1] = *request->msgptr++;
1357                 }
1358
1359         request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
1360         if (request->u.servicereg.txtlen)
1361                 {
1362                 request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
1363                 if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
1364                 mDNSPlatformMemCopy(request->u.servicereg.txtdata, get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen), request->u.servicereg.txtlen);
1365                 }
1366         else request->u.servicereg.txtdata = NULL;
1367
1368         if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
1369
1370         // Check for sub-types after the service type
1371         request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string);        // Note: Modifies regtype string to remove trailing subtypes
1372         if (request->u.servicereg.num_subtypes < 0)
1373                 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
1374
1375         // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
1376         if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
1377                 { LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
1378
1379         if (!name[0])
1380                 {
1381                 request->u.servicereg.name = mDNSStorage.nicelabel;
1382                 request->u.servicereg.autoname = mDNStrue;
1383                 }
1384         else
1385                 {
1386                 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
1387                 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
1388                         {
1389                         int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
1390                         name[newlen] = 0;
1391                         }
1392                 if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
1393                         { LogMsg("ERROR: handle_regservice_request - name bad %s", name); return(mStatus_BadParamErr); }
1394                 request->u.servicereg.autoname = mDNSfalse;
1395                 }
1396
1397         if (*domain)
1398                 {
1399                 request->u.servicereg.default_domain = mDNSfalse;
1400                 if (!MakeDomainNameFromDNSNameString(&d, domain))
1401                         { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); return(mStatus_BadParamErr); }
1402                 }
1403         else
1404                 {
1405                 request->u.servicereg.default_domain = mDNStrue;
1406                 MakeDomainNameFromDNSNameString(&d, "local.");
1407                 }
1408
1409         if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
1410                 {
1411                 LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
1412                         request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); return(mStatus_BadParamErr);
1413                 }
1414
1415         if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
1416                 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); return(mStatus_BadParamErr); }
1417         request->u.servicereg.autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
1418         request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
1419
1420         // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1421         // a port number of zero. When two instances of the protected client are allowed to run on one
1422         // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1423         if (!mDNSIPPortIsZero(request->u.servicereg.port))
1424                 {
1425                 int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
1426                 if (count)
1427                         LogMsg("Client application registered %d identical instances of service %##s port %u.",
1428                                 count+1, srv.c, mDNSVal16(request->u.servicereg.port));
1429                 }
1430
1431         LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
1432                 request->sd, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port));
1433
1434         // We need to unconditionally set request->terminate, because even if we didn't successfully
1435         // start any registrations right now, subsequent configuration changes may cause successful
1436         // registrations to be added, and we'll need to cancel them before freeing this memory.
1437         // We also need to set request->terminate first, before adding additional service instances,
1438         // because the uds_validatelists uses the request->terminate function pointer to determine
1439         // what kind of request this is, and therefore what kind of list validation is required.
1440         request->terminate = regservice_termination_callback;
1441
1442         err = register_service_instance(request, &d);
1443
1444 #if 0
1445         err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError;
1446 #endif
1447         if (!err)
1448                 {
1449                 if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
1450
1451                 if (!*domain)
1452                         {
1453                         DNameListElem *ptr;
1454                         // Note that we don't report errors for non-local, non-explicit domains
1455                         for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
1456                                 if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
1457                                         register_service_instance(request, &ptr->name);
1458                         }
1459                 }
1460
1461         return(err);
1462         }
1463
1464 // ***************************************************************************
1465 #if COMPILER_LIKES_PRAGMA_MARK
1466 #pragma mark -
1467 #pragma mark - DNSServiceBrowse
1468 #endif
1469
1470 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
1471         {
1472         const DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
1473         request_state *req = question->QuestionContext;
1474         reply_state *rep;
1475         (void)m; // Unused
1476
1477         if (answer->rrtype != kDNSType_PTR)
1478                 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
1479
1480         if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
1481                 {
1482                 if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
1483                         {
1484                         // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
1485                         // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
1486                         GenerateBonjourBrowserResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError);
1487                         goto bonjourbrowserhack;
1488                         }
1489
1490                 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1491                         req->sd, answer->name->c, answer->rdata->u.name.c);
1492                 return;
1493                 }
1494
1495 bonjourbrowserhack:
1496
1497         LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s",
1498                 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv",
1499                 mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID), RRDisplayString(m, answer));
1500
1501         append_reply(req, rep);
1502         }
1503
1504 mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d)
1505         {
1506         browser_t *b, *p;
1507         mStatus err;
1508
1509         for (p = info->u.browser.browsers; p; p = p->next)
1510                 {
1511                 if (SameDomainName(&p->domain, d))
1512                         { debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
1513                 }
1514
1515         b = mallocL("browser_t", sizeof(*b));
1516         if (!b) return mStatus_NoMemoryErr;
1517         AssignDomainName(&b->domain, d);
1518         err = mDNS_StartBrowse(&mDNSStorage, &b->q,
1519                 &info->u.browser.regtype, d, info->u.browser.interface_id, info->u.browser.ForceMCast, FoundInstance, info);
1520         if (err)
1521                 {
1522                 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->u.browser.regtype.c, d->c);
1523                 freeL("browser_t/add_domain_to_browser", b);
1524                 }
1525         else
1526                 {
1527                 b->next = info->u.browser.browsers;
1528                 info->u.browser.browsers = b;
1529                 LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c);
1530                 }
1531         return err;
1532         }
1533
1534 mDNSlocal void browse_termination_callback(request_state *info)
1535         {
1536         while (info->u.browser.browsers)
1537                 {
1538                 browser_t *ptr = info->u.browser.browsers;
1539                 info->u.browser.browsers = ptr->next;
1540                 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
1541                 mDNS_StopBrowse(&mDNSStorage, &ptr->q);  // no need to error-check result
1542                 freeL("browser_t/browse_termination_callback", ptr);
1543                 }
1544         }
1545
1546 mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *const d, const mDNSBool add)
1547         {
1548         request_state *request;
1549         debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c);
1550
1551 #if APPLE_OSX_mDNSResponder
1552         machserver_automatic_browse_domain_changed(&d->name, add);
1553 #endif // APPLE_OSX_mDNSResponder
1554
1555         for (request = all_requests; request; request = request->next)
1556                 {
1557                 if (request->terminate != browse_termination_callback) continue;        // Not a browse operation
1558                 if (!request->u.browser.default_domain) continue;                                       // Not an auto-browse operation
1559                 if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
1560                         {
1561                         browser_t **ptr = &request->u.browser.browsers;
1562                         while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
1563                         if (add)
1564                                 {
1565                                 // If we don't already have this domain in our list for this browse operation, add it now
1566                                 if (!*ptr) add_domain_to_browser(request, &d->name);
1567                                 else debugf("udsserver_automatic_browse_domain_changed %##s already in list, not re-adding", &d->name);
1568                                 }
1569                         else
1570                                 {
1571                                 if (!*ptr) LogMsg("udsserver_automatic_browse_domain_changed ERROR %##s not found", &d->name);
1572                                 else
1573                                         {
1574                                         DNameListElem *p;
1575                                         for (p = AutoBrowseDomains; p; p=p->next)
1576                                                 if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
1577                                                         if (SameDomainName(&d->name, &p->name)) break;
1578                                         if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
1579                                         else
1580                                                 {
1581                                                 browser_t *rem = *ptr;
1582                                                 *ptr = (*ptr)->next;
1583                                                 mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
1584                                                 freeL("browser_t/udsserver_automatic_browse_domain_changed", rem);
1585                                                 }
1586                                         }
1587                                 }
1588                         }
1589                 }
1590         }
1591
1592 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
1593         {
1594         (void)m;  // unused
1595         if (result == mStatus_MemFree)
1596                 {
1597                 // On shutdown, mDNS_Close automatically deregisters all records
1598                 // Since in this case no one has called DeregisterLocalOnlyDomainEnumPTR to cut the record
1599                 // from the LocalDomainEnumRecords list, we do this here before we free the memory.
1600                 ARListElem **ptr = &LocalDomainEnumRecords;
1601                 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
1602                 if (*ptr) *ptr = (*ptr)->next;
1603                 mDNSPlatformMemFree(rr->RecordContext);
1604                 }
1605         }
1606
1607 mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
1608         {
1609         // allocate/register legacy and non-legacy _browse PTR record
1610         mStatus err;
1611         ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
1612
1613         debugf("Incrementing %s refcount for %##s",
1614                 (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
1615                 (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
1616                 (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
1617
1618         mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, ptr);
1619         MakeDomainNameFromDNSNameString(&ptr->ar.namestorage, mDNS_DomainTypeNames[type]);
1620         AppendDNSNameString            (&ptr->ar.namestorage, "local");
1621         AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
1622         err = mDNS_Register(m, &ptr->ar);
1623         if (err)
1624                 {
1625                 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
1626                 mDNSPlatformMemFree(ptr);
1627                 }
1628         else
1629                 {
1630                 ptr->next = LocalDomainEnumRecords;
1631                 LocalDomainEnumRecords = ptr;
1632                 }
1633         }
1634
1635 mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
1636         {
1637         ARListElem **ptr = &LocalDomainEnumRecords;
1638         domainname lhs; // left-hand side of PTR, for comparison
1639
1640         debugf("Decrementing %s refcount for %##s",
1641                 (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
1642                 (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
1643                 (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
1644
1645         MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
1646         AppendDNSNameString            (&lhs, "local");
1647
1648         while (*ptr)
1649                 {
1650                 if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
1651                         {
1652                         ARListElem *rem = *ptr;
1653                         *ptr = (*ptr)->next;
1654                         mDNS_Deregister(m, &rem->ar);
1655                         return;
1656                         }
1657                 else ptr = &(*ptr)->next;
1658                 }
1659         }
1660
1661 mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
1662         {
1663         DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
1664         if (!new) { LogMsg("ERROR: malloc"); return; }
1665         AssignDomainName(&new->name, name);
1666         new->uid = uid;
1667         new->next = AutoBrowseDomains;
1668         AutoBrowseDomains = new;
1669         udsserver_automatic_browse_domain_changed(new, mDNStrue);
1670         }
1671
1672 mDNSlocal void RmvAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
1673         {
1674         DNameListElem **p = &AutoBrowseDomains;
1675         while (*p && (!SameDomainName(&(*p)->name, name) || (*p)->uid != uid)) p = &(*p)->next;
1676         if (!*p) LogMsg("RmvAutoBrowseDomain: Got remove event for domain %##s not in list", name->c);
1677         else
1678                 {
1679                 DNameListElem *ptr = *p;
1680                 *p = ptr->next;
1681                 udsserver_automatic_browse_domain_changed(ptr, mDNSfalse);
1682                 mDNSPlatformMemFree(ptr);
1683                 }
1684         }
1685
1686 mDNSlocal void SetPrefsBrowseDomains(mDNS *m, DNameListElem *browseDomains, mDNSBool add)
1687         {
1688         DNameListElem *d;
1689         for (d = browseDomains; d; d = d->next)
1690                 {
1691                 if (add)
1692                         {
1693                         RegisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
1694                         AddAutoBrowseDomain(d->uid, &d->name);
1695                         }
1696                 else
1697                         {
1698                         DeregisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
1699                         RmvAutoBrowseDomain(d->uid, &d->name);
1700                         }
1701                 }
1702         }
1703
1704 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
1705         {
1706         int num_autoname = 0;
1707         request_state *req;
1708         for (req = all_requests; req; req = req->next)
1709                 if (req->terminate == regservice_termination_callback && req->u.servicereg.autoname)
1710                         num_autoname++;
1711
1712         // If DeviceInfo record is currently registered, see if we need to deregister it
1713         if (m->DeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered)
1714                 if (num_autoname == 0 || !SameDomainLabelCS(m->DeviceInfo.resrec.name->c, m->nicelabel.c))
1715                         {
1716                         LogOperation("UpdateDeviceInfoRecord Deregister %##s", m->DeviceInfo.resrec.name);
1717                         mDNS_Deregister(m, &m->DeviceInfo);
1718                         }
1719
1720         // If DeviceInfo record is not currently registered, see if we need to register it
1721         if (m->DeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
1722                 if (num_autoname > 0)
1723                         {
1724                         mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
1725                         mDNS_SetupResourceRecord(&m->DeviceInfo, mDNSNULL, mDNSNULL, kDNSType_TXT, kStandardTTL, kDNSRecordTypeAdvisory, mDNSNULL, mDNSNULL);
1726                         ConstructServiceName(&m->DeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &localdomain);
1727                         mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
1728                         mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
1729                         m->DeviceInfo.resrec.rdata->u.data[0] = 6 + len;        // "model=" plus the device string
1730                         m->DeviceInfo.resrec.rdlength         = 7 + len;        // One extra for the length byte at the start of the string
1731                         LogOperation("UpdateDeviceInfoRecord   Register %##s", m->DeviceInfo.resrec.name);
1732                         mDNS_Register(m, &m->DeviceInfo);
1733                         }
1734         }
1735
1736 mDNSexport void udsserver_handle_configchange(mDNS *const m)
1737         {
1738         request_state *req;
1739         service_instance *ptr;
1740         DNameListElem *RegDomains = NULL;
1741         DNameListElem *BrowseDomains = NULL;
1742         DNameListElem *p;
1743
1744         UpdateDeviceInfoRecord(m);
1745
1746         // For autoname services, see if the default service name has changed, necessitating an automatic update
1747         for (req = all_requests; req; req = req->next)
1748                 if (req->terminate == regservice_termination_callback)
1749                         if (req->u.servicereg.autoname && !SameDomainLabelCS(req->u.servicereg.name.c, m->nicelabel.c))
1750                                 {
1751                                 req->u.servicereg.name = m->nicelabel;
1752                                 for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
1753                                         {
1754                                         ptr->renameonmemfree = 1;
1755                                         if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
1756                                         if (mDNS_DeregisterService(m, &ptr->srs)) // If service was deregistered already
1757                                                 regservice_callback(m, &ptr->srs, mStatus_MemFree); // we can re-register immediately
1758                                         }
1759                                 }
1760
1761         // Let the platform layer get the current DNS information
1762         mDNS_Lock(m);
1763         mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains);
1764         mDNS_Unlock(m);
1765
1766         // Any automatic registration domains are also implicitly automatic browsing domains
1767         if (RegDomains) SetPrefsBrowseDomains(m, RegDomains, mDNStrue);                                                         // Add the new list first
1768         if (AutoRegistrationDomains) SetPrefsBrowseDomains(m, AutoRegistrationDomains, mDNSfalse);      // Then clear the old list
1769
1770         // Add any new domains not already in our AutoRegistrationDomains list
1771         for (p=RegDomains; p; p=p->next)
1772                 {
1773                 DNameListElem **pp = &AutoRegistrationDomains;
1774                 while (*pp && ((*pp)->uid != p->uid || !SameDomainName(&(*pp)->name, &p->name))) pp = &(*pp)->next;
1775                 if (!*pp)               // If not found in our existing list, this is a new default registration domain
1776                         {
1777                         RegisterLocalOnlyDomainEnumPTR(m, &p->name, mDNS_DomainTypeRegistration);
1778                         udsserver_default_reg_domain_changed(p, mDNStrue);
1779                         }
1780                 else                    // else found same domainname in both old and new lists, so no change, just delete old copy
1781                         {
1782                         DNameListElem *del = *pp;
1783                         *pp = (*pp)->next;
1784                         mDNSPlatformMemFree(del);
1785                         }
1786                 }
1787
1788         // Delete any domains in our old AutoRegistrationDomains list that are now gone
1789         while (AutoRegistrationDomains)
1790                 {
1791                 DNameListElem *del = AutoRegistrationDomains;
1792                 AutoRegistrationDomains = AutoRegistrationDomains->next;                // Cut record from list FIRST,
1793                 DeregisterLocalOnlyDomainEnumPTR(m, &del->name, mDNS_DomainTypeRegistration);
1794                 udsserver_default_reg_domain_changed(del, mDNSfalse);                   // before calling udsserver_default_reg_domain_changed()
1795                 mDNSPlatformMemFree(del);
1796                 }
1797
1798         // Now we have our new updated automatic registration domain list
1799         AutoRegistrationDomains = RegDomains;
1800
1801         // Add new browse domains to internal list
1802         if (BrowseDomains) SetPrefsBrowseDomains(m, BrowseDomains, mDNStrue);
1803
1804         // Remove old browse domains from internal list
1805         if (SCPrefBrowseDomains)
1806                 {
1807                 SetPrefsBrowseDomains(m, SCPrefBrowseDomains, mDNSfalse);
1808                 while (SCPrefBrowseDomains)
1809                         {
1810                         DNameListElem *fptr = SCPrefBrowseDomains;
1811                         SCPrefBrowseDomains = SCPrefBrowseDomains->next;
1812                         mDNSPlatformMemFree(fptr);
1813                         }
1814                 }
1815
1816         // Replace the old browse domains array with the new array
1817         SCPrefBrowseDomains = BrowseDomains;
1818         }
1819
1820 mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const ResourceRecord *const answer, QC_result AddRecord)
1821         {
1822         (void)m; // unused;
1823         (void)q; // unused
1824
1825         LogOperation("AutomaticBrowseDomainChange: %s automatic browse domain %##s",
1826                 AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
1827
1828         if (AddRecord) AddAutoBrowseDomain(0, &answer->rdata->u.name);
1829         else           RmvAutoBrowseDomain(0, &answer->rdata->u.name);
1830         }
1831
1832 mDNSlocal mStatus handle_browse_request(request_state *request)
1833         {
1834         char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1835         domainname typedn, d, temp;
1836         mDNSs32 NumSubTypes;
1837         mStatus err = mStatus_NoError;
1838
1839         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
1840         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
1841         mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
1842         if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
1843
1844         if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1845                 get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
1846
1847         if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
1848
1849         if (domain[0] == '\0') uDNS_RegisterSearchDomains(&mDNSStorage);
1850
1851         typedn.c[0] = 0;
1852         NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
1853         if (NumSubTypes < 0 || NumSubTypes > 1) return(mStatus_BadParamErr);
1854         if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1)) return(mStatus_BadParamErr);
1855
1856         if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) return(mStatus_BadParamErr);
1857
1858         if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr);
1859         // For over-long service types, we only allow domain "local"
1860         if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrCopy(domain, "local.");
1861
1862         // Set up browser info
1863         request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1864         request->u.browser.interface_id = InterfaceID;
1865         AssignDomainName(&request->u.browser.regtype, &typedn);
1866         request->u.browser.default_domain = !domain[0];
1867         request->u.browser.browsers = NULL;
1868
1869         LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, request->u.browser.regtype.c, domain);
1870
1871         // We need to unconditionally set request->terminate, because even if we didn't successfully
1872         // start any browses right now, subsequent configuration changes may cause successful
1873         // browses to be added, and we'll need to cancel them before freeing this memory.
1874         request->terminate = browse_termination_callback;
1875
1876         if (domain[0])
1877                 {
1878                 if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
1879                 err = add_domain_to_browser(request, &d);
1880 #if 0
1881                 err = AuthorizedDomain(request, &d, AutoBrowseDomains) ? add_domain_to_browser(request, &d) : mStatus_NoError;
1882 #endif
1883                 }
1884         else
1885                 {
1886                 DNameListElem *sdom;
1887                 for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
1888                         if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
1889                                 {
1890                                 err = add_domain_to_browser(request, &sdom->name);
1891                                 if (err)
1892                                         {
1893                                         if (SameDomainName(&sdom->name, &localdomain)) break;
1894                                         else err = mStatus_NoError;  // suppress errors for non-local "default" domains
1895                                         }
1896                                 }
1897                 }
1898
1899         return(err);
1900         }
1901
1902 // ***************************************************************************
1903 #if COMPILER_LIKES_PRAGMA_MARK
1904 #pragma mark -
1905 #pragma mark - DNSServiceResolve
1906 #endif
1907
1908 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
1909         {
1910         size_t len = 0;
1911         char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1912         char *data;
1913         reply_state *rep;
1914         request_state *req = question->QuestionContext;
1915         (void)m; // Unused
1916
1917         LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
1918
1919         if (!AddRecord)
1920                 {
1921                 if (req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
1922                 if (req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
1923                 return;
1924                 }
1925
1926         if (answer->rrtype == kDNSType_SRV) req->u.resolve.srv = answer;
1927         if (answer->rrtype == kDNSType_TXT) req->u.resolve.txt = answer;
1928
1929         if (!req->u.resolve.txt || !req->u.resolve.srv) return;         // only deliver result to client if we have both answers
1930
1931         ConvertDomainNameToCString(answer->name, fullname);
1932         ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target);
1933
1934         // calculate reply length
1935         len += sizeof(DNSServiceFlags);
1936         len += sizeof(mDNSu32);  // interface index
1937         len += sizeof(DNSServiceErrorType);
1938         len += strlen(fullname) + 1;
1939         len += strlen(target) + 1;
1940         len += 2 * sizeof(mDNSu16);  // port, txtLen
1941         len += req->u.resolve.txt->rdlength;
1942
1943         // allocate/init reply header
1944         rep = create_reply(resolve_reply_op, len, req);
1945         rep->rhdr->flags = dnssd_htonl(0);
1946         rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
1947         rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1948
1949         data = (char *)&rep->rhdr[1];
1950
1951         // write reply data to message
1952         put_string(fullname, &data);
1953         put_string(target, &data);
1954         *data++ =  req->u.resolve.srv->rdata->u.srv.port.b[0];
1955         *data++ =  req->u.resolve.srv->rdata->u.srv.port.b[1];
1956         put_uint16(req->u.resolve.txt->rdlength, &data);
1957         put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
1958
1959         LogOperation("%3d: DNSServiceResolve(%s) RESULT   %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
1960         append_reply(req, rep);
1961         }
1962
1963 mDNSlocal void resolve_termination_callback(request_state *request)
1964         {
1965         LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
1966         mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
1967         mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
1968         }
1969
1970 mDNSlocal mStatus handle_resolve_request(request_state *request)
1971         {
1972         char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1973         domainname fqdn;
1974         mStatus err;
1975
1976         // extract the data from the message
1977         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
1978         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
1979         mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
1980         if (interfaceIndex && !InterfaceID)
1981                 { LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
1982
1983         if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
1984                 get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1985                 get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1986                 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
1987
1988         if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
1989
1990         if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1991                 { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, regtype, domain); return(mStatus_BadParamErr); }
1992
1993         mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
1994
1995         // format questions
1996         request->u.resolve.qsrv.InterfaceID      = InterfaceID;
1997         request->u.resolve.qsrv.Target           = zeroAddr;
1998         AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
1999         request->u.resolve.qsrv.qtype            = kDNSType_SRV;
2000         request->u.resolve.qsrv.qclass           = kDNSClass_IN;
2001         request->u.resolve.qsrv.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
2002         request->u.resolve.qsrv.ExpectUnique     = mDNStrue;
2003         request->u.resolve.qsrv.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
2004         request->u.resolve.qsrv.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
2005         request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
2006         request->u.resolve.qsrv.QuestionContext  = request;
2007
2008         request->u.resolve.qtxt.InterfaceID      = InterfaceID;
2009         request->u.resolve.qtxt.Target           = zeroAddr;
2010         AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
2011         request->u.resolve.qtxt.qtype            = kDNSType_TXT;
2012         request->u.resolve.qtxt.qclass           = kDNSClass_IN;
2013         request->u.resolve.qtxt.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
2014         request->u.resolve.qtxt.ExpectUnique     = mDNStrue;
2015         request->u.resolve.qtxt.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
2016         request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
2017         request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
2018         request->u.resolve.qtxt.QuestionContext  = request;
2019
2020         request->u.resolve.ReportTime            = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
2021
2022 #if 0
2023         if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains))       return(mStatus_NoError);
2024 #endif
2025
2026         // ask the questions
2027         LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c);
2028         err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
2029         if (!err)
2030                 {
2031                 err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
2032                 if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
2033                 else request->terminate = resolve_termination_callback;
2034                 }
2035
2036         return(err);
2037         }
2038
2039 // ***************************************************************************
2040 #if COMPILER_LIKES_PRAGMA_MARK
2041 #pragma mark -
2042 #pragma mark - DNSServiceQueryRecord
2043 #endif
2044
2045 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
2046 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
2047 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
2048 // the mDNSCore operation if the client dies or closes its socket.
2049
2050 mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2051         {
2052         char name[MAX_ESCAPED_DOMAIN_NAME];
2053         request_state *req = question->QuestionContext;
2054         reply_state *rep;
2055         char *data;
2056         size_t len;
2057         DNSServiceErrorType error = kDNSServiceErr_NoError;
2058         (void)m; // Unused
2059
2060 #if APPLE_OSX_mDNSResponder
2061         if (question == &req->u.queryrecord.q2)
2062                 {
2063                 mDNS_StopQuery(&mDNSStorage, question);
2064                 // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
2065                 if (answer->RecordType == kDNSRecordTypePacketNegative ||
2066                         (question->qtype == req->u.queryrecord.q.qtype && SameDomainName(&question->qname, &req->u.queryrecord.q.qname)))
2067                         question->QuestionCallback = mDNSNULL;
2068                 else
2069                         {
2070                         *question              = req->u.queryrecord.q;
2071                         question->InterfaceID  = mDNSInterface_Unicast;
2072                         question->ExpectUnique = mDNStrue;
2073                         mStatus err = mDNS_StartQuery(&mDNSStorage, question);
2074                         if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype));
2075                         else LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
2076                         }
2077                 return;
2078                 }
2079 #endif // APPLE_OSX_mDNSResponder
2080
2081         if (answer->RecordType == kDNSRecordTypePacketNegative)
2082                 {
2083                 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
2084                 // Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative
2085                 // answers for just about every single multicast name we ever look up, since the Microsoft Active Directory
2086                 // server is going to assert that pretty much every single multicast name doesn't exist.
2087                 if (!answer->InterfaceID && IsLocalDomain(answer->name)) return;
2088                 error = kDNSServiceErr_NoSuchRecord;
2089                 AddRecord = mDNStrue;
2090                 }
2091
2092         ConvertDomainNameToCString(answer->name, name);
2093
2094         LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
2095                 req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
2096                 question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
2097
2098         len = sizeof(DNSServiceFlags);  // calculate reply data length
2099         len += sizeof(mDNSu32);         // interface index
2100         len += sizeof(DNSServiceErrorType);
2101         len += strlen(name) + 1;
2102         len += 3 * sizeof(mDNSu16);     // type, class, rdlen
2103         len += answer->rdlength;
2104         len += sizeof(mDNSu32);         // TTL
2105
2106         rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
2107
2108         rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
2109         rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
2110         rep->rhdr->error = dnssd_htonl(error);
2111
2112         data = (char *)&rep->rhdr[1];
2113
2114         put_string(name,             &data);
2115         put_uint16(answer->rrtype,   &data);
2116         put_uint16(answer->rrclass,  &data);
2117         put_uint16(answer->rdlength, &data);
2118         // We need to use putRData here instead of the crude put_rdata function, because the crude put_rdata
2119         // function just does a blind memory copy without regard to structures that may have holes in them.
2120         if (answer->rdlength)
2121                 if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer))
2122                         LogMsg("queryrecord_result_callback putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data);
2123         data += answer->rdlength;
2124         put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
2125
2126         append_reply(req, rep);
2127         }
2128
2129 mDNSlocal void queryrecord_termination_callback(request_state *request)
2130         {
2131         LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP",
2132                 request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype));
2133         mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q);  // no need to error check
2134         if (request->u.queryrecord.q2.QuestionCallback) mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q2);
2135         }
2136
2137 mDNSlocal mStatus handle_queryrecord_request(request_state *request)
2138         {
2139         DNSQuestion *const q = &request->u.queryrecord.q;
2140         char name[256];
2141         mDNSu16 rrtype, rrclass;
2142         mStatus err;
2143
2144         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2145         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2146         mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2147         if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
2148
2149         if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
2150         rrtype  = get_uint16(&request->msgptr, request->msgend);
2151         rrclass = get_uint16(&request->msgptr, request->msgend);
2152
2153         if (!request->msgptr)
2154                 { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2155
2156         mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
2157
2158         q->InterfaceID      = InterfaceID;
2159         q->Target           = zeroAddr;
2160         if (!MakeDomainNameFromDNSNameString(&q->qname, name))                  return(mStatus_BadParamErr);
2161 #if 0
2162         if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains))   return (mStatus_NoError);
2163 #endif
2164         q->qtype            = rrtype;
2165         q->qclass           = rrclass;
2166         q->LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
2167         q->ExpectUnique     = mDNSfalse;
2168         q->ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
2169         q->ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
2170         q->QuestionCallback = queryrecord_result_callback;
2171         q->QuestionContext  = request;
2172
2173         LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", request->sd, q->qname.c, DNSTypeName(q->qtype), flags);
2174         err = mDNS_StartQuery(&mDNSStorage, q);
2175         if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
2176         else request->terminate = queryrecord_termination_callback;
2177
2178 #if APPLE_OSX_mDNSResponder
2179         // Workaround for networks using Microsoft Active Directory using "local" as a private internal top-level domain
2180         extern domainname ActiveDirectoryPrimaryDomain;
2181         #define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
2182         #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
2183
2184         if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
2185                 if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
2186                         {
2187                         int labels = CountLabels(&q->qname);
2188                         DNSQuestion *const q2 = &request->u.queryrecord.q2;
2189                         *q2              = *q;
2190                         q2->InterfaceID  = mDNSInterface_Unicast;
2191                         q2->ExpectUnique = mDNStrue;
2192         
2193                         // For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
2194                         // For names of the form "<one-label>.local." it's less clear whether we should do a unicast query.
2195                         // If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP
2196                         // "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser)
2197                         // then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
2198                         // site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
2199                         // for names in the "local" domain will be safely answered privately before they hit the root name servers.
2200                         if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain))
2201                                 {
2202                                 AssignDomainName(&q2->qname, &localdomain);
2203                                 q2->qtype          = kDNSType_SOA;
2204                                 q2->LongLived      = mDNSfalse;
2205                                 q2->ForceMCast     = mDNSfalse;
2206                                 q2->ReturnIntermed = mDNStrue;
2207                                 }
2208                         err = mDNS_StartQuery(&mDNSStorage, q2);
2209                         if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
2210                         else LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
2211                         }
2212 #endif // APPLE_OSX_mDNSResponder
2213
2214         return(err);
2215         }
2216
2217 // ***************************************************************************
2218 #if COMPILER_LIKES_PRAGMA_MARK
2219 #pragma mark -
2220 #pragma mark - DNSServiceEnumerateDomains
2221 #endif
2222
2223 mDNSlocal reply_state *format_enumeration_reply(request_state *request,
2224         const char *domain, DNSServiceFlags flags, mDNSu32 ifi, DNSServiceErrorType err)
2225         {
2226         size_t len;
2227         reply_state *reply;
2228         char *data;
2229
2230         len = sizeof(DNSServiceFlags);
2231         len += sizeof(mDNSu32);
2232         len += sizeof(DNSServiceErrorType);
2233         len += strlen(domain) + 1;
2234
2235         reply = create_reply(enumeration_reply_op, len, request);
2236         reply->rhdr->flags = dnssd_htonl(flags);
2237         reply->rhdr->ifi   = dnssd_htonl(ifi);
2238         reply->rhdr->error = dnssd_htonl(err);
2239         data = (char *)&reply->rhdr[1];
2240         put_string(domain, &data);
2241         return reply;
2242         }
2243
2244 mDNSlocal void enum_termination_callback(request_state *request)
2245         {
2246         mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
2247         mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
2248         }
2249
2250 mDNSlocal void enum_result_callback(mDNS *const m,
2251         DNSQuestion *const question, const ResourceRecord *const answer, QC_result AddRecord)
2252         {
2253         char domain[MAX_ESCAPED_DOMAIN_NAME];
2254         request_state *request = question->QuestionContext;
2255         DNSServiceFlags flags = 0;
2256         reply_state *reply;
2257         (void)m; // Unused
2258
2259         if (answer->rrtype != kDNSType_PTR) return;
2260
2261 #if 0
2262         if (!AuthorizedDomain(request, &answer->rdata->u.name, request->u.enumeration.flags ? AutoRegistrationDomains : AutoBrowseDomains)) return;
2263 #endif
2264
2265         // We only return add/remove events for the browse and registration lists
2266         // For the default browse and registration answers, we only give an "ADD" event
2267         if (question == &request->u.enumeration.q_default && !AddRecord) return;
2268
2269         if (AddRecord)
2270                 {
2271                 flags |= kDNSServiceFlagsAdd;
2272                 if (question == &request->u.enumeration.q_default) flags |= kDNSServiceFlagsDefault;
2273                 }
2274
2275         ConvertDomainNameToCString(&answer->rdata->u.name, domain);
2276         // Note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
2277         // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
2278         // network, so we just pass kDNSServiceInterfaceIndexAny
2279         reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
2280         if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
2281
2282         LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "Add" : "Rmv", domain);
2283
2284         append_reply(request, reply);
2285         }
2286
2287 mDNSlocal mStatus handle_enum_request(request_state *request)
2288         {
2289         mStatus err;
2290         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2291         DNSServiceFlags reg = flags & kDNSServiceFlagsRegistrationDomains;
2292         mDNS_DomainType t_all     = reg ? mDNS_DomainTypeRegistration        : mDNS_DomainTypeBrowse;
2293         mDNS_DomainType t_default = reg ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
2294         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2295         mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2296         if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
2297
2298         if (!request->msgptr)
2299                 { LogMsg("%3d: DNSServiceEnumerateDomains(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2300
2301         // allocate context structures
2302         uDNS_RegisterSearchDomains(&mDNSStorage);
2303
2304 #if 0
2305         // mark which kind of enumeration we're doing so we can (de)authorize certain domains
2306         request->u.enumeration.flags = reg;
2307 #endif
2308
2309         // enumeration requires multiple questions, so we must link all the context pointers so that
2310         // necessary context can be reached from the callbacks
2311         request->u.enumeration.q_all    .QuestionContext = request;
2312         request->u.enumeration.q_default.QuestionContext = request;
2313         
2314         // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
2315         if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
2316
2317         // make the calls
2318         LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", request->sd, flags,
2319                 (flags & kDNSServiceFlagsBrowseDomains      ) ? "kDNSServiceFlagsBrowseDomains" :
2320                 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
2321         err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_all, t_all, NULL, InterfaceID, enum_result_callback, request);
2322         if (!err)
2323                 {
2324                 err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request);
2325                 if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
2326                 else request->terminate = enum_termination_callback;
2327                 }
2328
2329         return(err);
2330         }
2331
2332 // ***************************************************************************
2333 #if COMPILER_LIKES_PRAGMA_MARK
2334 #pragma mark -
2335 #pragma mark - DNSServiceReconfirmRecord & Misc
2336 #endif
2337
2338 mDNSlocal mStatus handle_reconfirm_request(request_state *request)
2339         {
2340         mStatus status = mStatus_BadParamErr;
2341         AuthRecord *rr = read_rr_from_ipc_msg(request, 0, 0);
2342         if (rr)
2343                 {
2344                 status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
2345                 LogOperation(
2346                         (status == mStatus_NoError) ?
2347                         "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
2348                         "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
2349                         request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
2350                         mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID), status);
2351                 freeL("AuthRecord/handle_reconfirm_request", rr);
2352                 }
2353         return(status);
2354         }
2355
2356 mDNSlocal mStatus handle_setdomain_request(request_state *request)
2357         {
2358         char domainstr[MAX_ESCAPED_DOMAIN_NAME];
2359         domainname domain;
2360         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2361         (void)flags; // Unused
2362         if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2363                 !MakeDomainNameFromDNSNameString(&domain, domainstr))
2364                 { LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2365
2366         LogOperation("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
2367         return(mStatus_NoError);
2368         }
2369
2370 typedef packedstruct
2371         {
2372         mStatus err;
2373         mDNSu32 len;
2374         mDNSu32 vers;
2375         } DaemonVersionReply;
2376
2377 mDNSlocal void handle_getproperty_request(request_state *request)
2378         {
2379         const mStatus BadParamErr = dnssd_htonl(mStatus_BadParamErr);
2380         char prop[256];
2381         if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
2382                 {
2383                 LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
2384                 if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
2385                         {
2386                         DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
2387                         send_all(request->sd, (const char *)&x, sizeof(x));
2388                         return;
2389                         }
2390                 }
2391
2392         // If we didn't recogize the requested property name, return BadParamErr
2393         send_all(request->sd, (const char *)&BadParamErr, sizeof(BadParamErr));
2394         }
2395
2396 // ***************************************************************************
2397 #if COMPILER_LIKES_PRAGMA_MARK
2398 #pragma mark -
2399 #pragma mark - DNSServiceNATPortMappingCreate
2400 #endif
2401
2402 #define DNSServiceProtocol(X) ((X) == NATOp_AddrRequest ? 0 : (X) == NATOp_MapUDP ? kDNSServiceProtocol_UDP : kDNSServiceProtocol_TCP)
2403
2404 mDNSlocal void port_mapping_termination_callback(request_state *request)
2405         {
2406         LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP", request->sd,
2407                 DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
2408                 mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
2409         mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
2410         }
2411
2412 // Called via function pointer when we get a NAT-PMP address request or port mapping response
2413 mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n)
2414         {
2415         request_state *request = (request_state *)n->clientContext;
2416         reply_state *rep;
2417         int replyLen;
2418         char *data;
2419
2420         if (!request) { LogMsg("port_mapping_create_request_callback called with unknown request_state object"); return; }
2421
2422         // calculate reply data length
2423         replyLen = sizeof(DNSServiceFlags);
2424         replyLen += 3 * sizeof(mDNSu32);  // if index + addr + ttl
2425         replyLen += sizeof(DNSServiceErrorType);
2426         replyLen += 2 * sizeof(mDNSu16);  // Internal Port + External Port
2427         replyLen += sizeof(mDNSu8);       // protocol
2428
2429         rep = create_reply(port_mapping_reply_op, replyLen, request);
2430
2431         rep->rhdr->flags = dnssd_htonl(0);
2432         rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID));
2433         rep->rhdr->error = dnssd_htonl(n->Result);
2434
2435         data = (char *)&rep->rhdr[1];
2436
2437         *data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
2438         *data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
2439         *data++ = request->u.pm.NATinfo.ExternalAddress.b[2];
2440         *data++ = request->u.pm.NATinfo.ExternalAddress.b[3];
2441         *data++ = DNSServiceProtocol(request->u.pm.NATinfo.Protocol);
2442         *data++ = request->u.pm.NATinfo.IntPort.b[0];
2443         *data++ = request->u.pm.NATinfo.IntPort.b[1];
2444         *data++ = request->u.pm.NATinfo.ExternalPort.b[0];
2445         *data++ = request->u.pm.NATinfo.ExternalPort.b[1];
2446         put_uint32(request->u.pm.NATinfo.Lifetime, &data);
2447
2448         LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
2449                 DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
2450                 mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
2451                 &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
2452
2453         append_reply(request, rep);
2454         }
2455
2456 mDNSlocal mStatus handle_port_mapping_request(request_state *request)
2457         {
2458         mDNSu32 ttl = 0;
2459         mStatus err = mStatus_NoError;
2460
2461         DNSServiceFlags flags          = get_flags(&request->msgptr, request->msgend);
2462         mDNSu32         interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2463         mDNSInterfaceID InterfaceID    = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2464         mDNSu8          protocol       = get_uint32(&request->msgptr, request->msgend);
2465         (void)flags; // Unused
2466         if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
2467         if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
2468         else
2469                 {
2470                 request->u.pm.NATinfo.IntPort.b[0] = *request->msgptr++;
2471                 request->u.pm.NATinfo.IntPort.b[1] = *request->msgptr++;
2472                 request->u.pm.ReqExt.b[0]          = *request->msgptr++;
2473                 request->u.pm.ReqExt.b[1]          = *request->msgptr++;
2474                 ttl = get_uint32(&request->msgptr, request->msgend);
2475                 }
2476
2477         if (!request->msgptr)
2478                 { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2479
2480         if (protocol == 0)      // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
2481                 {
2482                 if (!mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort) || !mDNSIPPortIsZero(request->u.pm.ReqExt) || ttl) return(mStatus_BadParamErr);
2483                 }
2484         else
2485                 {
2486                 if (mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort)) return(mStatus_BadParamErr);
2487                 if (!(protocol & (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP))) return(mStatus_BadParamErr);
2488                 }
2489
2490         request->u.pm.NATinfo.Protocol       = !protocol ? NATOp_AddrRequest : (protocol == kDNSServiceProtocol_UDP) ? NATOp_MapUDP : NATOp_MapTCP;
2491         //       u.pm.NATinfo.IntPort        = already set above
2492         request->u.pm.NATinfo.RequestedPort  = request->u.pm.ReqExt;
2493         request->u.pm.NATinfo.NATLease       = ttl;
2494         request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
2495         request->u.pm.NATinfo.clientContext  = request;
2496
2497         LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START", request->sd,
2498                 protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
2499         err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
2500         if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
2501         else request->terminate = port_mapping_termination_callback;
2502
2503         return(err);
2504         }
2505
2506 // ***************************************************************************
2507 #if COMPILER_LIKES_PRAGMA_MARK
2508 #pragma mark -
2509 #pragma mark - DNSServiceGetAddrInfo
2510 #endif
2511
2512 mDNSlocal void addrinfo_termination_callback(request_state *request)
2513         {
2514         if (request->u.addrinfo.q4.QuestionContext)
2515                 {
2516                 mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
2517                 request->u.addrinfo.q4.QuestionContext = mDNSNULL;
2518                 }
2519
2520         if (request->u.addrinfo.q6.QuestionContext)
2521                 {
2522                 mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
2523                 request->u.addrinfo.q6.QuestionContext = mDNSNULL;
2524                 }
2525         }
2526
2527 mDNSlocal mStatus handle_addrinfo_request(request_state *request)
2528         {
2529         char hostname[256];
2530         domainname d;
2531         mStatus err = 0;
2532
2533         DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2534         mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2535
2536         mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
2537         request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2538         request->u.addrinfo.flags        = flags;
2539         request->u.addrinfo.protocol     = get_uint32(&request->msgptr, request->msgend);
2540
2541         if (interfaceIndex && !request->u.addrinfo.interface_id) return(mStatus_BadParamErr);
2542         if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) return(mStatus_BadParamErr);
2543
2544         if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
2545
2546         if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2547
2548         if (!MakeDomainNameFromDNSNameString(&d, hostname))
2549                 { LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
2550
2551 #if 0
2552         if (!AuthorizedDomain(request, &d, AutoBrowseDomains))  return (mStatus_NoError);
2553 #endif
2554
2555         if (!request->u.addrinfo.protocol)
2556                 {
2557                 NetworkInterfaceInfo *i;
2558                 if (IsLocalDomain(&d))
2559                         {
2560                         for (i = mDNSStorage.HostInterfaces; i; i = i->next)
2561                                 {
2562                                 if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSIPv4AddressIsZero(i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
2563                                 else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSIPv6AddressIsZero(i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
2564                                 }
2565                         }
2566                 else
2567                         {
2568                         for (i = mDNSStorage.HostInterfaces; i; i = i->next)
2569                                 {
2570                                 if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
2571                                 else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
2572                                 }
2573                         }
2574                 }
2575
2576         if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
2577                 {
2578                 request->u.addrinfo.q4.InterfaceID      = request->u.addrinfo.interface_id;
2579                 request->u.addrinfo.q4.Target           = zeroAddr;
2580                 request->u.addrinfo.q4.qname            = d;
2581                 request->u.addrinfo.q4.qtype            = kDNSServiceType_A;
2582                 request->u.addrinfo.q4.qclass           = kDNSServiceClass_IN;
2583                 request->u.addrinfo.q4.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
2584                 request->u.addrinfo.q4.ExpectUnique     = mDNSfalse;
2585                 request->u.addrinfo.q4.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
2586                 request->u.addrinfo.q4.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
2587                 request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
2588                 request->u.addrinfo.q4.QuestionContext  = request;
2589
2590                 err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
2591                 if (err != mStatus_NoError)
2592                         {
2593                         LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
2594                         request->u.addrinfo.q4.QuestionContext = mDNSNULL;
2595                         }
2596                 }
2597
2598         if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
2599                 {
2600                 request->u.addrinfo.q6.InterfaceID      = request->u.addrinfo.interface_id;
2601                 request->u.addrinfo.q6.Target           = zeroAddr;
2602                 request->u.addrinfo.q6.qname            = d;
2603                 request->u.addrinfo.q6.qtype            = kDNSServiceType_AAAA;
2604                 request->u.addrinfo.q6.qclass           = kDNSServiceClass_IN;
2605                 request->u.addrinfo.q6.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
2606                 request->u.addrinfo.q6.ExpectUnique     = mDNSfalse;
2607                 request->u.addrinfo.q6.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
2608                 request->u.addrinfo.q6.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
2609                 request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
2610                 request->u.addrinfo.q6.QuestionContext  = request;
2611
2612                 err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
2613                 if (err != mStatus_NoError)
2614                         {
2615                         LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
2616                         request->u.addrinfo.q6.QuestionContext = mDNSNULL;
2617                         if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)    // If we started a query for IPv4,
2618                                 addrinfo_termination_callback(request);                                         // we need to cancel it
2619                         }
2620                 }
2621
2622         LogOperation("%3d: DNSServiceGetAddrInfo(%##s) START", request->sd, d.c);
2623
2624         if (!err) request->terminate = addrinfo_termination_callback;
2625
2626         return(err);
2627         }
2628
2629 // ***************************************************************************
2630 #if COMPILER_LIKES_PRAGMA_MARK
2631 #pragma mark -
2632 #pragma mark - Main Request Handler etc.
2633 #endif
2634
2635 mDNSlocal request_state *NewRequest(void)
2636         {
2637         request_state **p = &all_requests;
2638         while (*p) p=&(*p)->next;
2639         *p = mallocL("request_state", sizeof(request_state));
2640         if (!*p) FatalError("ERROR: malloc");
2641         mDNSPlatformMemZero(*p, sizeof(request_state));
2642         return(*p);
2643         }
2644
2645 // read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
2646 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
2647 mDNSlocal void read_msg(request_state *req)
2648         {
2649         if (req->ts == t_terminated || req->ts == t_error)
2650                 { LogMsg("%3d: ERROR: read_msg called with transfer state terminated or error", req->sd); req->ts = t_error; return; }
2651
2652         if (req->ts == t_complete)      // this must be death or something is wrong
2653                 {
2654                 char buf[4];    // dummy for death notification
2655                 int nread = recv(req->sd, buf, 4, 0);
2656                 if (!nread) { req->ts = t_terminated; return; }
2657                 if (nread < 0) goto rerror;
2658                 LogMsg("%3d: ERROR: read data from a completed request", req->sd);
2659                 req->ts = t_error;
2660                 return;
2661                 }
2662
2663         if (req->ts != t_morecoming)
2664                 { LogMsg("%3d: ERROR: read_msg called with invalid transfer state (%d)", req->sd, req->ts); req->ts = t_error; return; }
2665
2666         if (req->hdr_bytes < sizeof(ipc_msg_hdr))
2667                 {
2668                 mDNSu32 nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
2669                 int nread = recv(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0);
2670                 if (nread == 0) { req->ts = t_terminated; return; }
2671                 if (nread < 0) goto rerror;
2672                 req->hdr_bytes += nread;
2673                 if (req->hdr_bytes > sizeof(ipc_msg_hdr))
2674                         { LogMsg("%3d: ERROR: read_msg - read too many header bytes", req->sd); req->ts = t_error; return; }
2675
2676                 // only read data if header is complete
2677                 if (req->hdr_bytes == sizeof(ipc_msg_hdr))
2678                         {
2679                         ConvertHeaderBytes(&req->hdr);
2680                         if (req->hdr.version != VERSION)
2681                                 { LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
2682
2683                         // Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
2684                         // with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
2685                         // for other overhead, this means any message above 70kB is definitely bogus.
2686                         if (req->hdr.datalen > 70000)
2687                                 { LogMsg("%3d: ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
2688                         req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
2689                         if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
2690                         req->msgptr = req->msgbuf;
2691                         req->msgend = req->msgbuf + req->hdr.datalen;
2692                         mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
2693                         }
2694                 }
2695
2696         // If our header is complete, but we're still needing more body data, then try to read it now
2697         // Note: For cancel_request req->hdr.datalen == 0, but there's no error return socket for cancel_request
2698         // Any time we need to get the error return socket we know we'll have at least one data byte
2699         // (even if only the one-byte empty C string placeholder for the old ctrl_path parameter)
2700         if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
2701                 {
2702                 mDNSu32 nleft = req->hdr.datalen - req->data_bytes;
2703                 int nread;
2704 #if !defined(_WIN32)
2705                 struct iovec vec = { req->msgbuf + req->data_bytes, nleft };    // Tell recvmsg where we want the bytes put
2706                 struct msghdr msg;
2707                 struct cmsghdr *cmsg;
2708                 char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
2709                 msg.msg_name       = 0;
2710                 msg.msg_namelen    = 0;
2711                 msg.msg_iov        = &vec;
2712                 msg.msg_iovlen     = 1;
2713                 msg.msg_control    = cbuf;
2714                 msg.msg_controllen = sizeof(cbuf);
2715                 msg.msg_flags      = 0;
2716                 nread = recvmsg(req->sd, &msg, 0);
2717 #else
2718                 nread = recv(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0);
2719 #endif
2720                 if (nread == 0) { req->ts = t_terminated; return; }
2721                 if (nread < 0) goto rerror;
2722                 req->data_bytes += nread;
2723                 if (req->data_bytes > req->hdr.datalen)
2724                         { LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; }
2725 #if !defined(_WIN32)
2726                 cmsg = CMSG_FIRSTHDR(&msg);
2727 #if DEBUG_64BIT_SCM_RIGHTS
2728                 LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf),       sizeof(cbuf),   SOL_SOCKET,       SCM_RIGHTS);
2729                 LogMsg("%3d: Got       %d %d %d %d", req->sd, msg.msg_controllen, cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type);
2730 #endif // DEBUG_64BIT_SCM_RIGHTS
2731                 if (msg.msg_controllen == sizeof(cbuf) &&
2732                         cmsg->cmsg_len     == sizeof(cbuf) &&
2733                         cmsg->cmsg_level   == SOL_SOCKET   &&
2734                         cmsg->cmsg_type    == SCM_RIGHTS)
2735                         {
2736 #if APPLE_OSX_mDNSResponder
2737                         // Strictly speaking BPF_fd belongs solely in the platform support layer, but because
2738                         // of privilege separation on Mac OS X we need to get BPF_fd from mDNSResponderHelper,
2739                         // and it's convenient to repurpose the existing fd-passing code here for that task
2740                         if (req->hdr.op == send_bpf)
2741                                 {
2742                                 dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
2743                                 LogOperation("%3d: Got BPF %d", req->sd, x);
2744                                 mDNSPlatformReceiveBPF_fd(&mDNSStorage, x);
2745                                 }
2746                         else
2747 #endif // APPLE_OSX_mDNSResponder
2748                                 req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
2749 #if DEBUG_64BIT_SCM_RIGHTS
2750                         LogMsg("%3d: read req->errsd %d", req->sd, req->errsd);
2751 #endif // DEBUG_64BIT_SCM_RIGHTS
2752                         if (req->data_bytes < req->hdr.datalen)
2753                                 {
2754                                 LogMsg("%3d: Client sent error socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
2755                                         req->sd, req->errsd, req->data_bytes, req->hdr.datalen);
2756                                 req->ts = t_error;
2757                                 return;
2758                                 }
2759                         }
2760 #endif
2761                 }
2762
2763         // If our header and data are both complete, see if we need to make our separate error return socket
2764         if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes == req->hdr.datalen)
2765                 {
2766                 if (req->terminate && req->hdr.op != cancel_request)
2767                         {
2768                         dnssd_sockaddr_t cliaddr;
2769 #if defined(USE_TCP_LOOPBACK)
2770                         mDNSOpaque16 port;
2771                         int opt = 1;
2772                         port.b[0] = req->msgptr[0];
2773                         port.b[1] = req->msgptr[1];
2774                         req->msgptr += 2;
2775                         cliaddr.sin_family      = AF_INET;
2776                         cliaddr.sin_port        = port.NotAnInteger;
2777                         cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
2778 #else
2779                         char ctrl_path[MAX_CTLPATH];
2780                         get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH);  // path is first element in message buffer
2781                         mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr));
2782                         cliaddr.sun_family = AF_LOCAL;
2783                         mDNSPlatformStrCopy(cliaddr.sun_path, ctrl_path);
2784                         // If the error return path UDS name is empty string, that tells us
2785                         // that this is a new version of the library that's going to pass us
2786                         // the error return path socket via sendmsg/recvmsg
2787                         if (ctrl_path[0] == 0)
2788                                 {
2789                                 if (req->errsd == req->sd)
2790                                         { LogMsg("%3d: read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return; }
2791                                 goto got_errfd;
2792                                 }
2793 #endif
2794         
2795                         req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0);
2796                         if (!dnssd_SocketValid(req->errsd)) { my_perror("ERROR: socket"); req->ts = t_error; return; }
2797
2798                         if (connect(req->errsd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
2799                                 {
2800 #if !defined(USE_TCP_LOOPBACK)
2801                                 struct stat sb;
2802                                 LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)",
2803                                         req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
2804                                 if (stat(cliaddr.sun_path, &sb) < 0)
2805                                         LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
2806                                 else
2807                                         LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
2808 #endif
2809                                 req->ts = t_error;
2810                                 return;
2811                                 }
2812         
2813 got_errfd:
2814                         LogOperation("%3d: Error socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
2815 #if defined(_WIN32)
2816                         if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
2817 #else
2818                         if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
2819 #endif
2820                                 {
2821                                 LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)",
2822                                         req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
2823                                 req->ts = t_error;
2824                                 return;
2825                                 }
2826                         }
2827                 
2828                 req->ts = t_complete;
2829                 }
2830
2831         return;
2832
2833 rerror:
2834         if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
2835         LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
2836         req->ts = t_error;
2837         }
2838
2839 #define RecordOrientedOp(X) \
2840         ((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
2841
2842 // The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
2843 #define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
2844
2845 mDNSlocal void request_callback(int fd, short filter, void *info)
2846         {
2847         mStatus err = 0;
2848         request_state *req = info;
2849 #if defined(_WIN32)
2850         u_long opt = 1;
2851 #endif
2852         mDNSs32 min_size = sizeof(DNSServiceFlags);
2853         (void)fd; // Unused
2854         (void)filter; // Unused
2855
2856         read_msg(req);
2857         if (req->ts == t_morecoming) return;
2858         if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; }
2859         if (req->ts != t_complete) { LogMsg("req->ts %d != t_complete", req->ts); AbortUnlinkAndFree(req); return; }
2860
2861         if (req->hdr.version != VERSION)
2862                 {
2863                 LogMsg("ERROR: client version %d incompatible with daemon version %d", req->hdr.version, VERSION);
2864                 AbortUnlinkAndFree(req);
2865                 return;
2866                 }
2867
2868         switch(req->hdr.op)            //          Interface       + other data
2869                 {
2870                 case connection_request:       min_size = 0;                                                                           break;
2871                 case reg_service_request:      min_size += sizeof(mDNSu32) + 4 /* name, type, domain, host */ + 4 /* port, textlen */; break;
2872                 case add_record_request:       min_size +=                   4 /* type, rdlen */              + 4 /* ttl */;           break;
2873                 case update_record_request:    min_size +=                   2 /* rdlen */                    + 4 /* ttl */;           break;
2874                 case remove_record_request:                                                                                            break;
2875                 case browse_request:           min_size += sizeof(mDNSu32) + 2 /* type, domain */;                                     break;
2876                 case resolve_request:          min_size += sizeof(mDNSu32) + 3 /* type, type, domain */;                               break;
2877                 case query_request:            min_size += sizeof(mDNSu32) + 1 /* name */                     + 4 /* type, class*/;    break;
2878                 case enumeration_request:      min_size += sizeof(mDNSu32);                                                            break;
2879                 case reg_record_request:       min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */ + 4 /* ttl */;  break;
2880                 case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */;                break;
2881                 case setdomain_request:        min_size +=                   1 /* domain */;                                           break;
2882                 case getproperty_request:      min_size = 2;                                                                           break;
2883                 case port_mapping_request:     min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */    + 4 /* ttl */;  break;
2884                 case addrinfo_request:         min_size += sizeof(mDNSu32) + 4 /* v4/v6 */   + 1 /* hostname */;                       break;
2885                 case send_bpf:                 // Same as cancel_request below
2886                 case cancel_request:           min_size = 0;                                                                           break;
2887                 default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1;                     break;
2888                 }
2889
2890         if ((mDNSs32)req->data_bytes < min_size)
2891                 { LogMsg("Invalid message %d bytes; min for %d is %d", req->data_bytes, req->hdr.op, min_size); AbortUnlinkAndFree(req); return; }
2892
2893         if (LightweightOp(req->hdr.op) && !req->terminate)
2894                 { LogMsg("Reg/Add/Update/Remove %d require existing connection", req->hdr.op);                  AbortUnlinkAndFree(req); return; }
2895
2896         // check if client wants silent operation
2897         if (req->hdr.ipc_flags & IPC_FLAGS_NOREPLY) req->no_reply = 1;
2898
2899         // If req->terminate is already set, this means this operation is sharing an existing connection
2900         if (req->terminate && !LightweightOp(req->hdr.op))
2901                 {
2902                 request_state *newreq = NewRequest();
2903                 newreq->primary = req;
2904                 newreq->sd      = req->sd;
2905                 newreq->errsd   = req->errsd;
2906                 newreq->uid     = req->uid;
2907                 newreq->hdr     = req->hdr;
2908                 newreq->msgbuf  = req->msgbuf;
2909                 newreq->msgptr  = req->msgptr;
2910                 newreq->msgend  = req->msgend;
2911                 req = newreq;
2912                 }
2913
2914         // If we're shutting down, don't allow new client requests
2915         // We do allow "cancel" and "getproperty" during shutdown
2916         if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
2917                 {
2918                 err = mStatus_ServiceNotRunning;
2919                 }
2920         else switch(req->hdr.op)
2921                 {
2922                 // These are all operations that have their own first-class request_state object
2923                 case connection_request:           LogOperation("%3d: DNSServiceCreateConnection START", req->sd);
2924                                                        req->terminate = connection_termination; break;
2925                 case resolve_request:              err = handle_resolve_request     (req);  break;
2926                 case query_request:                err = handle_queryrecord_request (req);  break;
2927                 case browse_request:               err = handle_browse_request      (req);  break;
2928                 case reg_service_request:          err = handle_regservice_request  (req);  break;
2929                 case enumeration_request:          err = handle_enum_request        (req);  break;
2930                 case reconfirm_record_request:     err = handle_reconfirm_request   (req);  break;
2931                 case setdomain_request:            err = handle_setdomain_request   (req);  break;
2932                 case getproperty_request:                handle_getproperty_request (req);  break;
2933                 case port_mapping_request:         err = handle_port_mapping_request(req);  break;
2934                 case addrinfo_request:             err = handle_addrinfo_request    (req);  break;
2935                 case send_bpf:                     /* Do nothing for send_bpf */            break;
2936
2937                 // These are all operations that work with an existing request_state object
2938                 case reg_record_request:           err = handle_regrecord_request   (req);  break;
2939                 case add_record_request:           err = handle_add_request         (req);  break;
2940                 case update_record_request:        err = handle_update_request      (req);  break;
2941                 case remove_record_request:        err = handle_removerecord_request(req);  break;
2942                 case cancel_request:                     handle_cancel_request      (req);  break;
2943                 default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
2944                 }
2945
2946         // req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
2947         if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
2948
2949         // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
2950         // For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here
2951         if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request && req->hdr.op != send_bpf)
2952                 {
2953                 const mStatus err_netorder = dnssd_htonl(err);
2954                 send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
2955                 if (req->errsd != req->sd)
2956                         {
2957                         LogOperation("%3d: Error socket %d closed  %08X %08X (%d)",
2958                                 req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err);
2959                         dnssd_close(req->errsd);
2960                         req->errsd = req->sd;
2961                         // Also need to reset the parent's errsd, if this is a subordinate operation
2962                         if (req->primary) req->primary->errsd = req->primary->sd;
2963                         }
2964                 }
2965
2966         // Reset ready to accept the next req on this pipe
2967         if (req->primary) req = req->primary;
2968         req->ts         = t_morecoming;
2969         req->hdr_bytes  = 0;
2970         req->data_bytes = 0;
2971         req->msgbuf     = mDNSNULL;
2972         req->msgptr     = mDNSNULL;
2973         req->msgend     = 0;
2974         }
2975
2976 mDNSlocal void connect_callback(int fd, short filter, void *info)
2977         {
2978         dnssd_sockaddr_t cliaddr;
2979         dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
2980         dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
2981 #if defined(SO_NOSIGPIPE) || defined(_WIN32)
2982         const unsigned long optval = 1;
2983 #endif
2984
2985         (void)filter; // Unused
2986         (void)info; // Unused
2987
2988         if (!dnssd_SocketValid(sd))
2989                 {
2990                 if (dnssd_errno != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
2991                 return;
2992                 }
2993
2994 #ifdef SO_NOSIGPIPE
2995         // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
2996         if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
2997                 LogMsg("%3d: WARNING: setsockopt - SO_NOSIGPIPE %d (%s)", sd, dnssd_errno, dnssd_strerror(dnssd_errno));
2998 #endif
2999
3000 #if defined(_WIN32)
3001         if (ioctlsocket(sd, FIONBIO, &optval) != 0)
3002 #else
3003         if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK) != 0)
3004 #endif
3005                 {
3006                 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
3007                 dnssd_close(sd);
3008                 return;
3009                 }
3010         else
3011                 {
3012                 request_state *request = NewRequest();
3013                 request->ts    = t_morecoming;
3014                 request->sd    = sd;
3015                 request->errsd = sd;
3016 #if APPLE_OSX_mDNSResponder
3017                 struct xucred x;
3018                 socklen_t xucredlen = sizeof(x);
3019                 if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
3020                 else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
3021                 debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
3022 #endif // APPLE_OSX_mDNSResponder
3023                 LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
3024                 udsSupportAddFDToEventLoop(sd, request_callback, request);
3025                 }
3026         }
3027
3028 mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
3029         {
3030 #if defined(SO_NP_EXTENSIONS)
3031         struct          so_np_extensions sonpx;
3032         socklen_t       optlen = sizeof(struct so_np_extensions);
3033         sonpx.npx_flags = SONPX_SETOPTSHUT;
3034         sonpx.npx_mask  = SONPX_SETOPTSHUT;
3035         if (setsockopt(skt, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, optlen) < 0)
3036                 my_perror("WARNING: could not set sockopt - SO_NP_EXTENSIONS");
3037 #endif
3038 #if defined(_WIN32)
3039         // SEH: do we even need to do this on windows?
3040         // This socket will be given to WSAEventSelect which will automatically set it to non-blocking
3041         u_long opt = 1;
3042         if (ioctlsocket(skt, FIONBIO, &opt) != 0)
3043 #else
3044         if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) != 0)
3045 #endif
3046                 {
3047                 my_perror("ERROR: could not set listen socket to non-blocking mode");
3048                 return mDNSfalse;
3049                 }
3050
3051         if (listen(skt, LISTENQ) != 0)
3052                 {
3053                 my_perror("ERROR: could not listen on listen socket");
3054                 return mDNSfalse;
3055                 }
3056
3057         if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL))
3058                 {
3059                 my_perror("ERROR: could not add listen socket to event loop");
3060                 return mDNSfalse;
3061                 }
3062         else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt);
3063         
3064         return mDNStrue;
3065         }
3066
3067 mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
3068         {
3069         dnssd_sockaddr_t laddr;
3070         int ret;
3071         mDNSu32 i = 0;
3072 #if defined(_WIN32)
3073         u_long opt = 1;
3074 #endif
3075
3076         LogInfo("udsserver_init");
3077
3078         // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
3079         if (PID_FILE[0])
3080                 {
3081                 FILE *fp = fopen(PID_FILE, "w");
3082                 if (fp != NULL)
3083                         {
3084                         fprintf(fp, "%d\n", getpid());
3085                         fclose(fp);
3086                         }
3087                 }
3088
3089         if (skts)
3090                 {
3091                 for (i = 0; i < count; i++)
3092                         if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i]))
3093                                 goto error;
3094                 }
3095         else
3096                 {
3097                 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
3098                 if (!dnssd_SocketValid(listenfd))
3099                         {
3100                         my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
3101                         goto error;
3102                         }
3103
3104                 mDNSPlatformMemZero(&laddr, sizeof(laddr));
3105
3106                 #if defined(USE_TCP_LOOPBACK)
3107                         {
3108                         laddr.sin_family = AF_INET;
3109                         laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
3110                         laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
3111                         ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
3112                         if (ret < 0)
3113                                 {
3114                                 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
3115                                 goto error;
3116                                 }
3117                         }
3118                 #else
3119                         {
3120                         mode_t mask = umask(0);
3121                         unlink(MDNS_UDS_SERVERPATH);  // OK if this fails
3122                         laddr.sun_family = AF_LOCAL;
3123                         #ifndef NOT_HAVE_SA_LEN
3124                         // According to Stevens (section 3.2), there is no portable way to
3125                         // determine whether sa_len is defined on a particular platform.
3126                         laddr.sun_len = sizeof(struct sockaddr_un);
3127                         #endif
3128                         mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
3129                         ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
3130                         umask(mask);
3131                         if (ret < 0)
3132                          &nb