]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/uds_daemon.c
e393f69cfbb1eafdff77852b175164ebde15dbb2
[apple/mdnsresponder.git] / mDNSShared / uds_daemon.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: uds_daemon.c,v $
28 Revision 1.55.2.1 2004/06/13 22:32:24 ksekar
29 WWDC Branch
30
31 Revision 1.55 2004/06/05 00:04:27 cheshire
32 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
33
34 Revision 1.54 2004/06/01 22:22:52 ksekar
35 <rdar://problem/3668635>: wide-area default registrations should be in
36 .local too
37
38 Revision 1.53 2004/05/28 23:42:37 ksekar
39 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
40
41 Revision 1.52 2004/05/26 00:39:49 ksekar
42 <rdar://problem/3667105>: wide-area rendezvous servers don't appear in
43 Finder
44 Use local-only InterfaceID for GetDomains calls for sockets-API
45
46 Revision 1.51 2004/05/18 23:51:27 cheshire
47 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
48
49 Revision 1.50 2004/05/14 16:39:47 ksekar
50 Browse for iChat locally for now.
51
52 Revision 1.49 2004/05/13 21:33:52 ksekar
53 Clean up non-local registration control via config file. Force iChat
54 registrations to be local for now.
55
56 Revision 1.48 2004/05/13 04:13:19 ksekar
57 Updated SIGINFO handler for multi-domain browses
58
59 Revision 1.47 2004/05/12 22:04:01 ksekar
60 Implemented multi-domain browsing by default for uds_daemon.
61
62 Revision 1.46 2004/05/06 18:42:58 ksekar
63 General dns_sd.h API cleanup, including the following radars:
64 <rdar://problem/3592068>: Remove flags with zero value
65 <rdar://problem/3479569>: Passing in NULL causes a crash.
66
67 Revision 1.45 2004/03/12 08:49:28 cheshire
68 #include <sys/socket.h>
69
70 Revision 1.44 2004/02/25 01:25:27 ksekar
71 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
72
73 Revision 1.43 2004/02/24 01:46:40 cheshire
74 Manually reinstate lost checkin 1.36
75
76 Revision 1.42 2004/02/05 19:39:29 cheshire
77 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
78 so that all platforms get this functionality
79
80 Revision 1.41 2004/02/03 18:59:02 cheshire
81 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
82
83 Revision 1.40 2004/01/28 03:41:00 cheshire
84 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
85
86 Revision 1.39 2004/01/25 00:03:21 cheshire
87 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
88
89 Revision 1.38 2004/01/19 19:51:46 cheshire
90 Fix compiler error (mixed declarations and code) on some versions of Linux
91
92 Revision 1.37 2003/12/08 21:11:42 rpantos
93 Changes necessary to support mDNSResponder on Linux.
94
95 Revision 1.36 2003/12/04 23:40:57 cheshire
96 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
97 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
98
99 Revision 1.35 2003/12/03 19:10:22 ksekar
100 <rdar://problem/3498644>: malloc'd data not zero'd
101
102 Revision 1.34 2003/12/03 02:00:01 ksekar
103 <rdar://problem/3498644>: malloc'd data not zero'd
104
105 Revision 1.33 2003/11/22 01:18:46 ksekar
106 <rdar://problem/3486646>: config change handler not called for dns-sd services
107
108 Revision 1.32 2003/11/20 21:46:12 ksekar
109 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
110
111 Revision 1.31 2003/11/20 20:33:05 ksekar
112 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
113
114 Revision 1.30 2003/11/20 02:10:55 ksekar
115 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
116
117 Revision 1.29 2003/11/14 21:18:32 cheshire
118 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
119 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
120
121 Revision 1.28 2003/11/08 22:18:29 cheshire
122 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
123
124 Revision 1.27 2003/11/05 22:44:57 ksekar
125 <rdar://problem/3335230>: No bounds checking when reading data from client
126 Reviewed by: Stuart Cheshire
127
128 Revision 1.26 2003/10/23 17:51:04 ksekar
129 <rdar://problem/3335216>: handle blocked clients more efficiently
130 Changed gettimeofday() to mDNSPlatformTimeNow()
131
132 Revision 1.25 2003/10/22 23:37:49 ksekar
133 <rdar://problem/3459141>: crash/hang in abort_client
134
135 Revision 1.24 2003/10/21 20:59:40 ksekar
136 <rdar://problem/3335216>: handle blocked clients moreefficiently
137
138 Revision 1.23 2003/09/23 02:12:43 cheshire
139 Also include port number in list of services registered via new UDS API
140
141 Revision 1.22 2003/08/19 16:03:55 ksekar
142 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
143 Check termination_context for NULL before dereferencing.
144
145 Revision 1.21 2003/08/19 05:39:43 cheshire
146 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
147
148 Revision 1.20 2003/08/16 03:39:01 cheshire
149 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
150
151 Revision 1.19 2003/08/15 20:16:03 cheshire
152 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
153 We want to avoid touching the rdata pages, so we don't page them in.
154 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
155 Moved this from the RData to the ResourceRecord object.
156 2. To avoid unnecessarily touching the rdata just to compare it,
157 compute a hash of the rdata and store the hash in the ResourceRecord object.
158
159 Revision 1.18 2003/08/15 00:38:00 ksekar
160 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
161
162 Revision 1.17 2003/08/14 02:18:21 cheshire
163 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
164
165 Revision 1.16 2003/08/13 23:58:52 ksekar
166 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
167 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
168
169 Revision 1.15 2003/08/13 17:30:33 ksekar
170 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
171 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
172
173 Revision 1.14 2003/08/12 19:56:25 cheshire
174 Update to APSL 2.0
175
176 */
177
178 #include <fcntl.h>
179 #include <errno.h>
180 #include <sys/ioctl.h>
181 #include <sys/types.h>
182 #include <sys/time.h>
183 #include <sys/resource.h>
184 #include <sys/socket.h>
185
186 #include "mDNSClientAPI.h"
187 #include "uds_daemon.h"
188 #include "dns_sd.h"
189 #include "dnssd_ipc.h"
190
191 // convenience definition
192 #define _UNUSED __attribute__ ((unused))
193 // Types and Data Structures
194 // ----------------------------------------------------------------------
195
196 typedef enum
197 {
198 t_uninitialized,
199 t_morecoming,
200 t_complete,
201 t_error,
202 t_terminated
203 } transfer_state;
204
205 typedef void (*req_termination_fn)(void *);
206
207
208 typedef struct registered_record_entry
209 {
210 int key;
211 AuthRecord *rr;
212 struct registered_record_entry *next;
213 } registered_record_entry;
214
215 typedef struct extra_record_entry
216 {
217 int key;
218 struct extra_record_entry *next;
219 ExtraResourceRecord e;
220 } extra_record_entry;
221
222 typedef struct registered_service
223 {
224 int autoname;
225 int renameonconflict;
226 int rename_on_memfree; // set flag on config change when we deregister original name
227 domainlabel name;
228 ServiceRecordSet *srs;
229 struct request_state *request;
230 AuthRecord *subtypes;
231 extra_record_entry *extras;
232 } registered_service;
233
234 typedef struct
235 {
236 registered_service *local;
237 registered_service *global;
238 } servicepair_t;
239
240 typedef struct
241 {
242 mStatus err;
243 int nwritten;
244 int sd;
245 } undelivered_error_t;
246
247 typedef struct request_state
248 {
249 // connection structures
250 int sd;
251 int errfd;
252
253 // state of read (in case message is read over several recv() calls)
254 transfer_state ts;
255 uint32_t hdr_bytes; // bytes of header already read
256 ipc_msg_hdr hdr;
257 uint32_t data_bytes; // bytes of message data already read
258 char *msgbuf; // pointer to data storage to pass to free()
259 char *msgdata; // pointer to data to be read from (may be modified)
260 int bufsize; // size of data storage
261
262 // reply, termination, error, and client context info
263 int no_reply; // don't send asynchronous replies to client
264 int time_blocked; // record time of a blocked client
265 void *client_context; // don't touch this - pointer only valid in client's addr space
266 struct reply_state *replies; // corresponding (active) reply list
267 undelivered_error_t *u_err;
268 void *termination_context;
269 req_termination_fn terminate;
270
271 //!!!KRS toss these pointers in a union
272 // registration context associated with this request (null if not applicable)
273 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
274 servicepair_t servicepair;
275 struct resolve_result_t *resolve_results;
276
277 struct request_state *next;
278 } request_state;
279
280 // struct physically sits between ipc message header and call-specific fields in the message buffer
281 typedef struct
282 {
283 DNSServiceFlags flags;
284 uint32_t ifi;
285 DNSServiceErrorType error;
286 } reply_hdr;
287
288
289 typedef struct reply_state
290 {
291 // state of the transmission
292 int sd;
293 transfer_state ts;
294 uint32_t nwriten;
295 uint32_t len;
296 // context of the reply
297 struct request_state *request; // the request that this answers
298 struct reply_state *next; // if there are multiple unsent replies
299 // pointer into message buffer - allows fields to be changed after message is formatted
300 ipc_msg_hdr *mhdr;
301 reply_hdr *rhdr;
302 char *sdata; // pointer to start of call-specific data
303 // pointer to malloc'd buffer
304 char *msgbuf;
305 } reply_state;
306
307
308 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
309 // structures to handle callbacks
310 typedef struct
311 {
312 DNSQuestion question;
313 mDNS_DomainType type;
314 request_state *rstate;
315 } domain_enum_t;
316
317 typedef struct
318 {
319 domain_enum_t *all;
320 domain_enum_t *def;
321 request_state *rstate;
322 } enum_termination_t;
323
324 typedef struct
325 {
326 DNSQuestion question;
327 uint16_t qtype;
328 request_state *rstate;
329 } resolve_t;
330
331 typedef struct
332 {
333 resolve_t *txt;
334 resolve_t *srv;
335 request_state *rstate;
336 } resolve_termination_t;
337
338 typedef struct resolve_result_t
339 {
340 const ResourceRecord *txt;
341 const ResourceRecord *srv;
342 } resolve_result_t;
343
344 typedef struct
345 {
346 request_state *rstate;
347 client_context_t client_context;
348 } regrecord_callback_context;
349
350 // for multi-domain browsing
351 typedef struct qlist_t
352 {
353 DNSQuestion q;
354 struct qlist_t *next;
355 } qlist_t;
356
357 typedef struct
358 {
359 qlist_t *qlist;
360 request_state *rstate;
361 } browse_termination_context;
362
363
364 // globals
365 static mDNS *gmDNS = NULL;
366 static int listenfd = -1;
367 static request_state *all_requests = NULL;
368 //!!!KRS we should keep a separate list containing only the requests that need to be examined
369 //in the idle() routine.
370
371
372 #define MAX_OPENFILES 1024
373 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
374 // terminating connection
375 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
376 // n get_string() calls w/o buffer overrun
377 // private function prototypes
378 static void connect_callback(void *info);
379 static int read_msg(request_state *rs);
380 static int send_msg(reply_state *rs);
381 static void abort_request(request_state *rs);
382 static void request_callback(void *info);
383 static void handle_resolve_request(request_state *rstate);
384 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
385 static void question_termination_callback(void *context);
386 static void handle_browse_request(request_state *request);
387 static void browse_termination_callback(void *context);
388 static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
389 static void handle_regservice_request(request_state *request);
390 static void regservice_termination_callback(void *context);
391 static void process_service_registration(ServiceRecordSet *const srs);
392 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
393 static void handle_add_request(request_state *rstate);
394 static void handle_update_request(request_state *rstate);
395 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
396 static void append_reply(request_state *req, reply_state *rep);
397 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
398 static void enum_termination_callback(void *context);
399 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
400 static void handle_query_request(request_state *rstate);
401 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
402 static void handle_enum_request(request_state *rstate);
403 static void handle_regrecord_request(request_state *rstate);
404 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
405 static void connected_registration_termination(void *context);
406 static void handle_reconfirm_request(request_state *rstate);
407 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
408 static void handle_removerecord_request(request_state *rstate);
409 static void reset_connected_rstate(request_state *rstate);
410 static int deliver_error(request_state *rstate, mStatus err);
411 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
412 static transfer_state send_undelivered_error(request_state *rs);
413 static reply_state *create_reply(reply_op_t op, int datalen, request_state *request);
414 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
415 static void my_perror(char *errmsg);
416 static void unlink_request(request_state *rs);
417 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
418 static void resolve_termination_callback(void *context);
419 static int validate_message(request_state *rstate);
420 static mStatus remove_extra_rr_from_service(request_state *rstate);
421 static mStatus remove_record(request_state *rstate);
422 static void free_service_registration(registered_service *srv);
423
424 // initialization, setup/teardown functions
425
426 // If a platform specifies its own PID file name, we use that
427 #ifndef PID_FILE
428 #define PID_FILE "/var/run/mDNSResponder.pid"
429 #endif
430
431 int udsserver_init( mDNS *globalInstance)
432 {
433 mode_t mask;
434 struct sockaddr_un laddr;
435 struct rlimit maxfds;
436
437 if ( !globalInstance)
438 goto error;
439 gmDNS = globalInstance;
440
441 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
442 if (PID_FILE[0])
443 {
444 FILE *fp = fopen(PID_FILE, "w");
445 if (fp != NULL)
446 {
447 fprintf(fp, "%d\n", getpid());
448 fclose(fp);
449 }
450 }
451
452 if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
453 goto error;
454 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
455 bzero(&laddr, sizeof(laddr));
456 laddr.sun_family = AF_LOCAL;
457 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
458 // determine whether sa_len is defined on a particular platform.
459 laddr.sun_len = sizeof(struct sockaddr_un);
460 #endif
461 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
462 mask = umask(0);
463 if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
464 goto error;
465 umask(mask);
466
467 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) < 0)
468 {
469 my_perror("ERROR: could not set listen socket to non-blocking mode");
470 goto error;
471 }
472 listen(listenfd, LISTENQ);
473
474 if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
475 {
476 my_perror("ERROR: could not add listen socket to event loop");
477 goto error;
478 }
479
480 // set maximum file descriptor to 1024
481 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
482 {
483 my_perror("ERROR: Unable to get file descriptor limit");
484 return 0;
485 }
486 if (maxfds.rlim_max >= MAX_OPENFILES && maxfds.rlim_cur == maxfds.rlim_max)
487 {
488 // proper values already set
489 return 0;
490 }
491 maxfds.rlim_max = MAX_OPENFILES;
492 maxfds.rlim_cur = MAX_OPENFILES;
493 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0)
494 my_perror("ERROR: Unable to set maximum file descriptor limit");
495 return 0;
496
497 error:
498 my_perror("ERROR: udsserver_init");
499 return -1;
500 }
501
502 int udsserver_exit(void)
503 {
504 close(listenfd);
505 unlink(MDNS_UDS_SERVERPATH);
506 return 0;
507 }
508
509
510 mDNSs32 udsserver_idle(mDNSs32 nextevent)
511 {
512 request_state *req = all_requests, *tmp, *prev = NULL;
513 reply_state *fptr;
514 transfer_state result;
515 mDNSs32 now = mDNSPlatformTimeNow();
516
517 while(req)
518 {
519 result = t_uninitialized;
520 if (req->u_err)
521 result = send_undelivered_error(req);
522 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
523 (req->ts == t_complete || req->ts == t_morecoming))
524 {
525 while(req->replies)
526 {
527 if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
528 result = send_msg(req->replies);
529 if (result == t_complete)
530 {
531 fptr = req->replies;
532 req->replies = req->replies->next;
533 freeL("udsserver_idle", fptr);
534 req->time_blocked = 0; // reset failure counter after successful send
535 }
536 else if (result == t_terminated || result == t_error)
537 {
538 abort_request(req);
539 break;
540 }
541 else if (result == t_morecoming) break; // client's queues are full, move to next
542 }
543 }
544 if (result == t_morecoming)
545 {
546 if (!req->time_blocked) req->time_blocked = now;
547 debugf("udsserver_idle: client has been blocked for %d seconds", now - req->time_blocked);
548 if (now - req->time_blocked >= MAX_TIME_BLOCKED)
549 {
550 LogMsg("Could not write data to client after %d seconds - aborting connection", MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
551 abort_request(req);
552 result = t_terminated;
553 }
554 else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
555 }
556 if (result == t_terminated || result == t_error)
557 //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
558 {
559 tmp = req;
560 if (prev) prev->next = req->next;
561 if (req == all_requests) all_requests = all_requests->next;
562 req = req->next;
563 freeL("udsserver_idle", tmp);
564 }
565 else
566 {
567 prev = req;
568 req = req->next;
569 }
570 }
571 return nextevent;
572 }
573
574 void udsserver_info(void)
575 {
576 request_state *req;
577 qlist_t *qlist;
578 for (req = all_requests; req; req=req->next)
579 {
580 void *t = req->termination_context;
581 if (!t) continue;
582 if (req->terminate == regservice_termination_callback)
583 LogMsgNoIdent("DNSServiceRegister %##s %u", ((registered_service *)t)->srs->RR_SRV.resrec.name.c, SRS_PORT(((registered_service *)t)->srs));
584 else if (req->terminate == browse_termination_callback)
585 {
586 for (qlist = ((browse_termination_context *)t)->qlist; qlist; qlist = qlist->next)
587 LogMsgNoIdent("DNSServiceBrowse %##s", qlist->q.qname.c);
588 }
589 else if (req->terminate == resolve_termination_callback)
590 LogMsgNoIdent("DNSServiceResolve %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
591 else if (req->terminate == question_termination_callback)
592 LogMsgNoIdent("DNSServiceQueryRecord %##s", ((DNSQuestion *) t)->qname.c);
593 else if (req->terminate == enum_termination_callback)
594 LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t *) t)->all->question.qname.c);
595 }
596 }
597
598
599 static void rename_service(registered_service *srv)
600 {
601 mStatus err;
602
603 if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
604 {
605 srv->rename_on_memfree = 1;
606 err = mDNS_DeregisterService(gmDNS, srv->srs);
607 if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d. Continuing.", err);
608 // error should never occur - safest to log and continue
609 }
610 }
611
612 void udsserver_handle_configchange(void)
613 {
614 request_state *req;
615
616
617 for (req = all_requests; req; req = req->next)
618 {
619 if (req->servicepair.local) rename_service(req->servicepair.local);
620 if (req->servicepair.global) rename_service(req->servicepair.global);
621 }
622 }
623
624 static void connect_callback(void *info _UNUSED)
625 {
626 int sd, clilen, optval;
627 struct sockaddr_un cliaddr;
628 request_state *rstate;
629 // int errpipe[2];
630
631 clilen = sizeof(cliaddr);
632 sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
633
634 if (sd < 0)
635 {
636 if (errno == EWOULDBLOCK) return;
637 my_perror("ERROR: accept");
638 return;
639 }
640 optval = 1;
641 #ifdef SO_NOSIGPIPE
642 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
643 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
644 {
645 my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");
646 close(sd);
647 return;
648 }
649 #endif
650
651 if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
652 {
653 my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
654 close(sd);
655 return;
656 }
657
658 /*
659 // open a pipe to deliver error messages, pass descriptor to client
660 if (pipe(errpipe) < 0)
661 {
662 my_perror("ERROR: could not create pipe");
663 exit(1);
664 }
665
666 if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
667 {
668 my_perror("ERROR: could not pass pipe descriptor to client. Aborting client.\n");
669 close(sd);
670 return;
671 }
672 if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
673 {
674 my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
675 close(sd);
676 close(errpipe[1]);
677 return;
678 }
679 */
680
681 // allocate a request_state struct that will live with the socket
682 rstate = mallocL("connect_callback", sizeof(request_state));
683 if (!rstate)
684 {
685 my_perror("ERROR: malloc");
686 exit(1);
687 }
688 bzero(rstate, sizeof(request_state));
689 rstate->ts = t_morecoming;
690 rstate->sd = sd;
691 //rstate->errfd = errpipe[1];
692
693 if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
694 return;
695 rstate->next = all_requests;
696 all_requests = rstate;
697 }
698
699
700 // handler
701 static void request_callback(void *info)
702 {
703 request_state *rstate = info;
704 transfer_state result;
705 struct sockaddr_un cliaddr;
706 char ctrl_path[MAX_CTLPATH];
707
708 result = read_msg(rstate);
709 if (result == t_morecoming)
710 {
711 return;
712 }
713 if (result == t_terminated)
714 {
715 abort_request(rstate);
716 unlink_request(rstate);
717 return;
718 }
719 if (result == t_error)
720 {
721 abort_request(rstate);
722 unlink_request(rstate);
723 return;
724 }
725
726 if (rstate->hdr.version != VERSION)
727 {
728 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
729 "daemon version = %d)\n", rstate->hdr.version, VERSION);
730 abort_request(rstate);
731 unlink_request(rstate);
732 return;
733 }
734
735 if (validate_message(rstate) < 0)
736 {
737 // note that we cannot deliver an error message if validation fails, since the path to the error socket
738 // may be contained in the (invalid) message body for some message types
739 abort_request(rstate);
740 unlink_request(rstate);
741 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
742 return;
743 }
744
745 // check if client wants silent operation
746 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
747
748 // check if primary socket is to be used for synchronous errors, else open new socket
749 if (rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET)
750 rstate->errfd = rstate->sd;
751 else
752 {
753 if ((rstate->errfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
754 {
755 my_perror("ERROR: socket");
756 exit(1);
757 }
758 if (fcntl(rstate->errfd, F_SETFL, O_NONBLOCK) < 0)
759 {
760 my_perror("ERROR: could not set control socket to non-blocking mode");
761 abort_request(rstate);
762 unlink_request(rstate);
763 return;
764 }
765 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
766 bzero(&cliaddr, sizeof(cliaddr));
767 cliaddr.sun_family = AF_LOCAL;
768 strcpy(cliaddr.sun_path, ctrl_path);
769 if (connect(rstate->errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
770 {
771 my_perror("ERROR: connect");
772 abort_request(rstate);
773 unlink_request(rstate);
774 }
775 }
776
777
778
779
780 switch(rstate->hdr.op.request_op)
781 {
782 case resolve_request: handle_resolve_request(rstate); break;
783 case query_request: handle_query_request(rstate); break;
784 case browse_request: handle_browse_request(rstate); break;
785 case reg_service_request: handle_regservice_request(rstate); break;
786 case enumeration_request: handle_enum_request(rstate); break;
787 case reg_record_request: handle_regrecord_request(rstate); break;
788 case add_record_request: handle_add_request(rstate); break;
789 case update_record_request: handle_update_request(rstate); break;
790 case remove_record_request: handle_removerecord_request(rstate); break;
791 case reconfirm_record_request: handle_reconfirm_request(rstate); break;
792 default:
793 debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate->hdr.op.request_op);
794 }
795 }
796
797 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
798 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
799 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
800 // the mDNSCore operation if the client dies or closes its socket.
801
802
803 // query and resolve calls have separate request handlers that parse the arguments from the client and
804 // massage the name parameters appropriately, but the rest of the operations (making the query call,
805 // delivering the result to the client, and termination) are identical.
806
807 static void handle_query_request(request_state *rstate)
808 {
809 DNSServiceFlags flags;
810 uint32_t ifi;
811 char name[256];
812 uint16_t rrtype, rrclass;
813 char *ptr;
814 mStatus result;
815 mDNSInterfaceID InterfaceID;
816 DNSQuestion *q;
817
818 if (rstate->ts != t_complete)
819 {
820 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
821 goto error;
822 }
823 ptr = rstate->msgdata;
824 if (!ptr)
825 {
826 LogMsg("ERROR: handle_query_request - NULL msgdata");
827 goto error;
828 }
829
830 flags = get_flags(&ptr);
831 ifi = get_long(&ptr);
832 if (get_string(&ptr, name, 256) < 0) goto bad_param;
833 rrtype = get_short(&ptr);
834 rrclass = get_short(&ptr);
835 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
836 if (ifi && !InterfaceID) goto bad_param;
837
838 q = mallocL("DNSQuestion", sizeof(DNSQuestion));
839 if (!q)
840 {
841 my_perror("ERROR: handle_query - malloc");
842 exit(1);
843 }
844 bzero(q, sizeof(DNSQuestion));
845
846 if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
847 q->QuestionContext = rstate;
848 q->QuestionCallback = question_result_callback;
849 q->qtype = rrtype;
850 q->qclass = rrclass;
851 q->InterfaceID = InterfaceID;
852 q->Target = zeroAddr;
853 if (flags & kDNSServiceFlagsLongLivedQuery) q->LongLived = mDNStrue;
854 rstate->termination_context = q;
855 rstate->terminate = question_termination_callback;
856
857 result = mDNS_StartQuery(gmDNS, q);
858 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
859
860 if (result) rstate->terminate = NULL;
861 if (deliver_error(rstate, result) < 0) goto error;
862 return;
863
864 bad_param:
865 deliver_error(rstate, mStatus_BadParamErr);
866 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
867 error:
868 abort_request(rstate);
869 unlink_request(rstate);
870 return;
871 }
872
873 static void handle_resolve_request(request_state *rstate)
874 {
875 DNSServiceFlags flags;
876 uint32_t interfaceIndex;
877 mDNSInterfaceID InterfaceID;
878 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
879 char *ptr; // message data pointer
880 domainname fqdn;
881 resolve_t *srv, *txt;
882 resolve_termination_t *term;
883 mStatus err;
884
885 if (rstate->ts != t_complete)
886 {
887 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
888 abort_request(rstate);
889 unlink_request(rstate);
890 return;
891 }
892
893 // extract the data from the message
894 ptr = rstate->msgdata;
895 if (!ptr)
896 {
897 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
898 abort_request(rstate);
899 unlink_request(rstate);
900 return;
901 }
902 flags = get_flags(&ptr);
903 interfaceIndex = get_long(&ptr);
904 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
905 if (interfaceIndex && !InterfaceID) goto bad_param;
906 if (get_string(&ptr, name, 256) < 0 ||
907 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
908 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
909 goto bad_param;
910
911 // free memory in rstate since we don't need it anymore
912 freeL("handle_resolve_request", rstate->msgbuf);
913 rstate->msgbuf = NULL;
914
915 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
916 goto bad_param;
917
918 // allocate question wrapper structs
919 srv = mallocL("handle_resolve_request", sizeof(resolve_t));
920 txt = mallocL("handle_resolve_request", sizeof(resolve_t));
921 if (!srv || !txt) goto malloc_error;
922 srv->qtype = kDNSType_SRV;
923 txt->qtype = kDNSType_TXT;
924 srv->rstate = rstate;
925 txt->rstate = rstate;
926
927 // format questions
928 srv->question.QuestionContext = rstate;
929 srv->question.QuestionCallback = resolve_result_callback;
930 memcpy(&srv->question.qname, &fqdn, MAX_DOMAIN_NAME);
931 srv->question.qtype = kDNSType_SRV;
932 srv->question.qclass = kDNSClass_IN;
933 srv->question.InterfaceID = InterfaceID;
934 srv->question.Target = zeroAddr;
935
936 txt->question.QuestionContext = rstate;
937 txt->question.QuestionCallback = resolve_result_callback;
938 memcpy(&txt->question.qname, &fqdn, MAX_DOMAIN_NAME);
939 txt->question.qtype = kDNSType_TXT;
940 txt->question.qclass = kDNSClass_IN;
941 txt->question.InterfaceID = InterfaceID;
942 txt->question.Target = zeroAddr;
943
944 // set up termination info
945 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
946 if (!term) goto malloc_error;
947 term->srv = srv;
948 term->txt = txt;
949 term->rstate = rstate;
950 rstate->termination_context = term;
951 rstate->terminate = resolve_termination_callback;
952
953 // set up reply wrapper struct (since answer will come via 2 callbacks)
954 rstate->resolve_results = mallocL("handle_resolve_response", sizeof(resolve_result_t));
955 if (!rstate->resolve_results) goto malloc_error;
956 bzero(rstate->resolve_results, sizeof(resolve_result_t));
957
958 // ask the questions
959 err = mDNS_StartQuery(gmDNS, &srv->question);
960 if (!err) err = mDNS_StartQuery(gmDNS, &txt->question);
961
962 if (err)
963 {
964 freeL("handle_resolve_request", txt);
965 freeL("handle_resolve_request", srv);
966 freeL("handle_resolve_request", term);
967 freeL("handle_resolve_request", rstate->resolve_results);
968 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
969 }
970 if (deliver_error(rstate, err) < 0 || err)
971 {
972 abort_request(rstate);
973 unlink_request(rstate);
974 }
975 return;
976
977 bad_param:
978 deliver_error(rstate, mStatus_BadParamErr);
979 abort_request(rstate);
980 unlink_request(rstate);
981 return;
982
983 malloc_error:
984 my_perror("ERROR: malloc");
985 exit(1);
986 }
987
988 static void resolve_termination_callback(void *context)
989 {
990 resolve_termination_t *term = context;
991 request_state *rs;
992
993 if (!term)
994 {
995 LogMsg("ERROR: resolve_termination_callback: double termination");
996 return;
997 }
998 rs = term->rstate;
999
1000 mDNS_StopQuery(gmDNS, &term->txt->question);
1001 mDNS_StopQuery(gmDNS, &term->srv->question);
1002
1003 freeL("resolve_termination_callback", term->txt);
1004 freeL("resolve_termination_callback", term->srv);
1005 freeL("resolve_termination_callback", term);
1006 rs->termination_context = NULL;
1007 freeL("resolve_termination_callback", rs->resolve_results);
1008 rs->resolve_results = NULL;
1009 }
1010
1011
1012
1013 static void resolve_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1014 {
1015 int len = 0;
1016 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1017 char *data;
1018 transfer_state result;
1019 reply_state *rep;
1020 request_state *rs = question->QuestionContext;
1021 resolve_result_t *res = rs->resolve_results;
1022
1023 if (!AddRecord)
1024 {
1025 if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1026 if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1027 return;
1028 }
1029
1030 if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1031 if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1032
1033 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1034
1035 ConvertDomainNameToCString(&answer->name, fullname);
1036 ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
1037
1038 // calculate reply length
1039 len += sizeof(DNSServiceFlags);
1040 len += sizeof(uint32_t); // interface index
1041 len += sizeof(DNSServiceErrorType);
1042 len += strlen(fullname) + 1;
1043 len += strlen(target) + 1;
1044 len += 2 * sizeof(uint16_t); // port, txtLen
1045 len += res->txt->rdlength;
1046
1047 // allocate/init reply header
1048 rep = create_reply(resolve_reply, len, rs);
1049 rep->rhdr->flags = 0;
1050 rep->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
1051 rep->rhdr->error = kDNSServiceErr_NoError;
1052 data = rep->sdata;
1053
1054 // write reply data to message
1055 put_string(fullname, &data);
1056 put_string(target, &data);
1057 put_short(res->srv->rdata->u.srv.port.NotAnInteger, &data);
1058 put_short(res->txt->rdlength, &data);
1059 put_rdata(res->txt->rdlength, res->txt->rdata->u.txt.c, &data);
1060
1061 result = send_msg(rep);
1062 if (result == t_error || result == t_terminated)
1063 {
1064 abort_request(rs);
1065 unlink_request(rs);
1066 freeL("resolve_result_callback", rep);
1067 }
1068 else if (result == t_complete) freeL("resolve_result_callback", rep);
1069 else append_reply(rs, rep);
1070 }
1071
1072 // what gets called when a resolve is completed and we need to send the data back to the client
1073 static void question_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1074 {
1075 char *data;
1076 char name[MAX_ESCAPED_DOMAIN_NAME];
1077 request_state *req;
1078 reply_state *rep;
1079 int len;
1080
1081 //mDNS_StopQuery(m, question);
1082 req = question->QuestionContext;
1083
1084 // calculate reply data length
1085 len = sizeof(DNSServiceFlags);
1086 len += 2 * sizeof(uint32_t); // if index + ttl
1087 len += sizeof(DNSServiceErrorType);
1088 len += 3 * sizeof(uint16_t); // type, class, rdlen
1089 len += answer->rdlength;
1090 ConvertDomainNameToCString(&answer->name, name);
1091 len += strlen(name) + 1;
1092
1093 rep = create_reply(query_reply, len, req);
1094 rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : 0;
1095 rep->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
1096 rep->rhdr->error = kDNSServiceErr_NoError;
1097 data = rep->sdata;
1098
1099 put_string(name, &data);
1100 put_short(answer->rrtype, &data);
1101 put_short(answer->rrclass, &data);
1102 put_short(answer->rdlength, &data);
1103 put_rdata(answer->rdlength, (char *)&answer->rdata->u, &data);
1104 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1105
1106 append_reply(req, rep);
1107 return;
1108 }
1109
1110 static void question_termination_callback(void *context)
1111 {
1112 DNSQuestion *q = context;
1113
1114
1115 mDNS_StopQuery(gmDNS, q); // no need to error check
1116 freeL("question_termination_callback", q);
1117 }
1118
1119
1120 static void handle_browse_request(request_state *request)
1121 {
1122 DNSServiceFlags flags;
1123 uint32_t interfaceIndex;
1124 mDNSInterfaceID InterfaceID;
1125 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1126 qlist_t *qlist = NULL, *qlist_elem;
1127 domainname typedn;
1128 char *ptr;
1129 mStatus result;
1130 DNameListElem *search_domain_list, *sdom, tmp;
1131 browse_termination_context *term;
1132
1133 if (request->ts != t_complete)
1134 {
1135 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
1136 abort_request(request);
1137 unlink_request(request);
1138 return;
1139 }
1140
1141 // extract data from message
1142 ptr = request->msgdata;
1143 flags = get_flags(&ptr);
1144 interfaceIndex = get_long(&ptr);
1145 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1146 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1147 goto bad_param;
1148 freeL("handle_browse_request", request->msgbuf);
1149 request->msgbuf = NULL;
1150
1151 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1152 if (interfaceIndex && !InterfaceID) goto bad_param;
1153
1154 if (!MakeDomainNameFromDNSNameString(&typedn, regtype)) goto bad_param;
1155
1156 //!!!KRS browse locally for ichat
1157 if (!domain[0] && (!strcmp(regtype, "_ichat._tcp.") || !strcmp(regtype, "_presence._tcp.")))
1158 strcpy(domain,"local.");
1159
1160 if (domain[0])
1161 {
1162 // generate a fake list of one elem to reduce number of code paths
1163 if (!MakeDomainNameFromDNSNameString(&tmp.name, domain)) goto bad_param;
1164 tmp.next = NULL;
1165 search_domain_list = &tmp;
1166 }
1167 else search_domain_list = mDNSPlatformGetSearchDomainList();
1168
1169 for (sdom = search_domain_list; sdom; sdom = sdom->next)
1170 {
1171 qlist_elem = mallocL("handle_browse_request", sizeof(qlist_t));
1172 if (!qlist_elem)
1173 {
1174 my_perror("ERROR: handle_browse_request - malloc");
1175 exit(1);
1176 }
1177 bzero(qlist_elem, sizeof(qlist_t));
1178 qlist_elem->q.QuestionContext = request;
1179 qlist_elem->q.QuestionCallback = browse_result_callback;
1180 qlist_elem->next = qlist;
1181 qlist = qlist_elem;
1182 }
1183
1184 // setup termination context
1185 term = (browse_termination_context *)mallocL("handle_browse_request", sizeof(browse_termination_context));
1186 if (!term)
1187 {
1188 my_perror("ERROR: handle_browse_request - malloc");
1189 exit(1);
1190 }
1191 term->qlist = qlist;
1192 term->rstate = request;
1193 request->termination_context = term;
1194 request->terminate = browse_termination_callback;
1195
1196 // start the browses
1197 sdom = search_domain_list;
1198 for (qlist_elem = qlist; qlist_elem; qlist_elem = qlist_elem->next)
1199 {
1200 result = mDNS_StartBrowse(gmDNS, &qlist_elem->q, &typedn, &sdom->name, InterfaceID, browse_result_callback, request);
1201 if (result)
1202 {
1203 // bail here on error. questions not yet issued are in no core lists, so they can be deallocated lazily
1204 if (search_domain_list != &tmp) mDNS_FreeDNameList(search_domain_list);
1205 deliver_error(request, result);
1206 return;
1207 }
1208 sdom = sdom->next;
1209 }
1210 if (search_domain_list != &tmp) mDNS_FreeDNameList(search_domain_list);
1211 deliver_error(request, mStatus_NoError);
1212 return;
1213
1214 bad_param:
1215 deliver_error(request, mStatus_BadParamErr);
1216 abort_request(request);
1217 unlink_request(request);
1218 }
1219
1220 static void browse_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1221 {
1222 request_state *req;
1223 reply_state *rep;
1224 mStatus err;
1225
1226 req = question->QuestionContext;
1227
1228 err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
1229 if (err)
1230 {
1231 if (deliver_async_error(req, browse_reply, err) < 0)
1232 {
1233 abort_request(req);
1234 unlink_request(req);
1235 }
1236 return;
1237 }
1238 if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd; // non-zero TTL indicates add
1239 append_reply(req, rep);
1240 return;
1241 }
1242
1243 static void browse_termination_callback(void *context)
1244 {
1245 browse_termination_context *t = context;
1246 qlist_t *ptr, *fptr;
1247
1248 if (!t) return;
1249
1250 ptr = t->qlist;
1251 t->qlist = NULL;
1252
1253 while(ptr)
1254 {
1255 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
1256 fptr = ptr;
1257 ptr = ptr->next;
1258 freeL("browse_termination_callback", fptr);
1259 }
1260 t->rstate->termination_context = NULL;
1261 freeL("browse_termination_callback", t);
1262 }
1263
1264 static mStatus register_service(request_state *request, registered_service **srv_ptr, DNSServiceFlags flags,
1265 uint16_t txtlen, void *txtdata, mDNSIPPort port, domainlabel *n, char *type_as_string,
1266 domainname *t, domainname *d, domainname *h, mDNSBool autoname, int num_subtypes, mDNSInterfaceID InterfaceID)
1267 {
1268 registered_service *r_srv;
1269 int srs_size, i;
1270 char *sub;
1271 mStatus result;
1272 *srv_ptr = NULL;
1273
1274 r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
1275 if (!r_srv) goto malloc_error;
1276 srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
1277 r_srv->srs = mallocL("handle_regservice_request", srs_size);
1278 if (!r_srv->srs) goto malloc_error;
1279 if (num_subtypes > 0)
1280 {
1281 r_srv->subtypes = mallocL("handle_regservice_request", num_subtypes * sizeof(AuthRecord));
1282 if (!r_srv->subtypes) goto malloc_error;
1283 sub = type_as_string + strlen(type_as_string) + 1;
1284 for (i = 0; i < num_subtypes; i++)
1285 {
1286 if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
1287 {
1288 free_service_registration(r_srv);
1289 return mStatus_BadParamErr;
1290 }
1291 sub += strlen(sub) + 1;
1292 }
1293 }
1294 else r_srv->subtypes = NULL;
1295 r_srv->request = request;
1296
1297 r_srv->extras = NULL;
1298 r_srv->autoname = autoname;
1299 r_srv->rename_on_memfree = 0;
1300 r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
1301 memcpy(r_srv->name.c, n->c, n->c[0]);
1302
1303 result = mDNS_RegisterService(gmDNS, r_srv->srs, n, t, d, h, port,
1304 txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
1305
1306 if (result)
1307 free_service_registration(r_srv);
1308 else *srv_ptr = r_srv;
1309
1310 return result;
1311
1312 malloc_error:
1313 my_perror("ERROR: malloc");
1314 exit(1);
1315 }
1316
1317
1318 // service registration
1319 static void handle_regservice_request(request_state *request)
1320 {
1321 DNSServiceFlags flags;
1322 uint32_t ifi;
1323 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
1324 uint16_t txtlen;
1325 mDNSIPPort port;
1326 void *txtdata;
1327 char *ptr, *sub;
1328 domainlabel n;
1329 domainname d, h, t, srv;
1330 mStatus result;
1331 mDNSInterfaceID InterfaceID;
1332 int num_subtypes;
1333 char *rtype_ptr;
1334
1335 if (request->ts != t_complete)
1336 {
1337 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
1338 abort_request(request);
1339 unlink_request(request);
1340 return;
1341 }
1342
1343 // extract data from message
1344 ptr = request->msgdata;
1345 flags = get_flags(&ptr);
1346 ifi = get_long(&ptr);
1347 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1348 if (ifi && !InterfaceID) goto bad_param;
1349 if (get_string(&ptr, name, 256) < 0 ||
1350 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1351 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1352 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
1353 goto bad_param;
1354
1355 port.NotAnInteger = get_short(&ptr);
1356 txtlen = get_short(&ptr);
1357 txtdata = get_rdata(&ptr, txtlen);
1358
1359 if (!*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) goto bad_param;
1360
1361 // count subtypes, replacing commas w/ whitespace
1362 rtype_ptr = regtype;
1363 num_subtypes = -1;
1364 while((sub = strsep(&rtype_ptr, ",")))
1365 if (*sub) num_subtypes++;
1366
1367 if (!name[0]) n = (gmDNS)->nicelabel;
1368 else if (!MakeDomainLabelFromLiteralString(&n, name))
1369 goto bad_param;
1370
1371 if ((!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
1372 (!ConstructServiceName(&srv, &n, &t, &d)))
1373 goto bad_param;
1374
1375 if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
1376
1377 result = register_service(request, &request->servicepair.local, flags, txtlen, txtdata, port, &n, &regtype[0], &t, &d, host[0] ? &h : NULL, !name[0], num_subtypes, InterfaceID);
1378
1379 //!!!KRS if we got a dynamic reg domain from the config file, use it for default (except for iChat)
1380 if (!domain[0] && gmDNS->uDNS_info.ServiceRegDomain[0] && strcmp(regtype, "_presence._tcp.") && strcmp(regtype, "_ichat._tcp."))
1381 {
1382 MakeDomainNameFromDNSNameString(&d, gmDNS->uDNS_info.ServiceRegDomain);
1383 register_service(request, &request->servicepair.global, flags, txtlen, txtdata, port, &n, &regtype[0], &t, &d, host[0] ? &h : NULL, !name[0], num_subtypes, InterfaceID);
1384 // don't return default global errors - it will confuse legacy clients, and we want .local to still work for them
1385 }
1386
1387 request->termination_context = &request->servicepair;
1388 request->terminate = regservice_termination_callback;
1389
1390 deliver_error(request, result);
1391 if (result != mStatus_NoError)
1392 {
1393 abort_request(request);
1394 unlink_request(request);
1395 }
1396 else
1397 reset_connected_rstate(request); // reset to receive add/remove messages
1398
1399 return;
1400
1401 bad_param:
1402 deliver_error(request, mStatus_BadParamErr);
1403 abort_request(request);
1404 unlink_request(request);
1405 }
1406
1407
1408
1409
1410 // service registration callback performs three duties - frees memory for deregistered services,
1411 // handles name conflicts, and delivers completed registration information to the client (via
1412 // process_service_registraion())
1413
1414 static void regservice_callback(mDNS *const m _UNUSED, ServiceRecordSet *const srs, mStatus result)
1415 {
1416 mStatus err;
1417 registered_service *r_srv = srs->ServiceContext;
1418 request_state *rs = r_srv->request;
1419
1420 if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
1421 {
1422 // error should never happen - safest to log and continue
1423 LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
1424 return;
1425 }
1426
1427 if (result == mStatus_NoError)
1428 return process_service_registration(srs);
1429 else if (result == mStatus_MemFree)
1430 {
1431 if (r_srv->rename_on_memfree)
1432 {
1433 r_srv->rename_on_memfree = 0;
1434 r_srv->name = gmDNS->nicelabel;
1435 err = mDNS_RenameAndReregisterService(gmDNS, srs, &r_srv->name);
1436 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
1437 // error should never happen - safest to log and continue
1438 }
1439 else
1440 {
1441 free_service_registration(r_srv);
1442 return;
1443 }
1444 }
1445 else if (result == mStatus_NameConflict)
1446 {
1447 if (r_srv->autoname || r_srv->renameonconflict)
1448 {
1449 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
1450 return;
1451 }
1452 else
1453 {
1454 free_service_registration(r_srv);
1455 if (deliver_async_error(rs, reg_service_reply, result) < 0)
1456 {
1457 abort_request(rs);
1458 unlink_request(rs);
1459 }
1460 return;
1461 }
1462 }
1463 else
1464 {
1465 LogMsg("ERROR: unknown result in regservice_callback: %d", result);
1466 if (deliver_async_error(rs, reg_service_reply, result) < 0)
1467 {
1468 abort_request(rs);
1469 unlink_request(rs);
1470 }
1471 return;
1472 }
1473 }
1474
1475 static mStatus add_record_to_service(request_state *rstate, registered_service *r_srv, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
1476 {
1477 ServiceRecordSet *srs = r_srv->srs;
1478 ExtraResourceRecord *extra;
1479 extra_record_entry *ere;
1480 mStatus result;
1481 int size;
1482
1483 if (rdlen > sizeof(RDataBody)) size = rdlen;
1484 else size = sizeof(RDataBody);
1485
1486 ere = mallocL("hanle_add_request", sizeof(extra_record_entry) - sizeof(RDataBody) + size);
1487 if (!ere)
1488 {
1489 my_perror("ERROR: malloc");
1490 exit(1);
1491 }
1492
1493 bzero(ere, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
1494 extra = &ere->e;
1495 extra->r.resrec.rrtype = rrtype;
1496 extra->r.rdatastorage.MaxRDLength = size;
1497 extra->r.resrec.rdlength = rdlen;
1498 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
1499
1500 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
1501 if (result) { freeL("handle_add_request", ere); return result; }
1502
1503 ere->key = rstate->hdr.reg_index;
1504 ere->next = r_srv->extras;
1505 r_srv->extras = ere;
1506 return result;
1507 }
1508
1509
1510 static void handle_add_request(request_state *rstate)
1511 {
1512 uint32_t ttl;
1513 uint16_t rrtype, rdlen;
1514 char *ptr, *rdata;
1515 mStatus result;
1516 DNSServiceFlags flags;
1517 registered_service *local, *global;
1518
1519 local = rstate->servicepair.local;
1520 global = rstate->servicepair.global;
1521
1522 if (!local)
1523 {
1524 LogMsg("ERROR: handle_add_request - no service registered");
1525 deliver_error(rstate, mStatus_UnknownErr);
1526 return;
1527 }
1528
1529 ptr = rstate->msgdata;
1530 flags = get_flags(&ptr);
1531 rrtype = get_short(&ptr);
1532 rdlen = get_short(&ptr);
1533 rdata = get_rdata(&ptr, rdlen);
1534 ttl = get_long(&ptr);
1535
1536 result = add_record_to_service(rstate, local, rrtype, rdlen, rdata, ttl);
1537 if (global) add_record_to_service(rstate, global, rrtype, rdlen, rdata, ttl); // don't report global errors to client
1538
1539 deliver_error(rstate, result);
1540 reset_connected_rstate(rstate);
1541 }
1542
1543 static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
1544 {
1545 int rdsize;
1546 RData *newrd;
1547 mStatus result;
1548
1549 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
1550 else rdsize = sizeof(RDataBody);
1551 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
1552 if (!newrd)
1553 {
1554 my_perror("ERROR: malloc");
1555 exit(1);
1556 }
1557 newrd->MaxRDLength = rdsize;
1558 memcpy(&newrd->u, rdata, rdlen);
1559 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
1560 if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("handle_update_request", newrd); }
1561 return result;
1562 }
1563
1564 static mStatus find_extras_by_key(request_state *rstate, AuthRecord **lRR, AuthRecord **gRR)
1565 {
1566 extra_record_entry *e;
1567
1568 // find the extra record for the local service
1569 for (e = rstate->servicepair.local->extras; e; e = e->next)
1570 if (e->key == rstate->hdr.reg_index) break;
1571 if (!e) return mStatus_BadReferenceErr;
1572
1573 *lRR = &e->e.r;
1574
1575 // find the corresponding global record, if it exists
1576 if (rstate->servicepair.global)
1577 {
1578 for (e = rstate->servicepair.global->extras; e; e = e->next)
1579 if (e->key == rstate->hdr.reg_index) break;
1580 if (e) *gRR = &e->e.r;
1581 else *gRR = NULL;
1582 }
1583 return mStatus_NoError;
1584 }
1585
1586 static void handle_update_request(request_state *rstate)
1587 {
1588 registered_record_entry *reptr;
1589 AuthRecord *lRR, *gRR = NULL;
1590 uint16_t rdlen;
1591 char *ptr, *rdata;
1592 uint32_t ttl;
1593 mStatus result;
1594
1595 if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
1596 {
1597 if (!rstate->servicepair.local)
1598 {
1599 deliver_error(rstate, mStatus_BadParamErr);
1600 return;
1601 }
1602 lRR = &rstate->servicepair.local->srs->RR_TXT;
1603 if (rstate->servicepair.global) gRR = &rstate->servicepair.global->srs->RR_TXT;
1604 }
1605 else
1606 {
1607 if (rstate->servicepair.local) // registered service
1608 {
1609 if (find_extras_by_key(rstate, &lRR, &gRR))
1610 { deliver_error(rstate, mStatus_BadReferenceErr); return; }
1611 }
1612 else
1613 {
1614 // record created via RegisterRecord
1615 reptr = rstate->reg_recs;
1616 while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;
1617 if (!reptr) { deliver_error(rstate, mStatus_BadReferenceErr); return; }
1618 lRR = reptr->rr;
1619 }
1620 }
1621
1622 // get the message data
1623 ptr = rstate->msgdata;
1624 get_flags(&ptr); // flags unused
1625 rdlen = get_short(&ptr);
1626 rdata = get_rdata(&ptr, rdlen);
1627 ttl = get_long(&ptr);
1628
1629 result = update_record(lRR, rdlen, rdata, ttl);
1630 if (gRR) update_record(gRR, rdlen, rdata, ttl); // don't report errors for global registration
1631
1632 deliver_error(rstate, result);
1633 reset_connected_rstate(rstate);
1634 }
1635
1636 static void update_callback(mDNS *const m _UNUSED, AuthRecord *const rr, RData *oldrd)
1637 {
1638 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
1639 }
1640
1641 static void process_service_registration(ServiceRecordSet *const srs)
1642 {
1643 reply_state *rep;
1644 transfer_state send_result;
1645 mStatus err;
1646 registered_service *r_srv = srs->ServiceContext;
1647 request_state *req = r_srv->request;
1648
1649
1650 err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
1651 if (err)
1652 {
1653 if (deliver_async_error(req, reg_service_reply, err) < 0)
1654 {
1655 abort_request(req);
1656 unlink_request(req);
1657 }
1658 return;
1659 }
1660 send_result = send_msg(rep);
1661 if (send_result == t_error || send_result == t_terminated)
1662 {
1663 abort_request(req);
1664 unlink_request(req);
1665 freeL("process_service_registration", rep);
1666 }
1667 else if (send_result == t_complete) freeL("process_service_registration", rep);
1668 else append_reply(req, rep);
1669 }
1670
1671 static void free_service_registration(registered_service *srv)
1672 {
1673 request_state *rstate = srv->request;
1674 extra_record_entry *extra;
1675
1676 // clear pointers from parent struct
1677 if (rstate)
1678 {
1679 if (rstate->servicepair.local == srv) rstate->servicepair.local = NULL;
1680 else if (rstate->servicepair.global == srv) rstate->servicepair.global = NULL;
1681 }
1682
1683 while (srv->extras)
1684 {
1685 extra = srv->extras;
1686 srv->extras = srv->extras->next;
1687 if (extra->e.r.resrec.rdata != &extra->e.r.rdatastorage)
1688 freeL("free_service_registration", extra->e.r.resrec.rdata);
1689 freeL("regservice_callback", extra);
1690 }
1691
1692 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
1693 freeL("regservice_callback", srv->srs);
1694 srv->srs = NULL;
1695 freeL("regservice_callback", srv);
1696 }
1697
1698 static void regservice_termination_callback(void *context)
1699 {
1700 servicepair_t *pair = context;
1701
1702 if (!pair->local && !pair->global) { LogMsg("ERROR: regservice_termination_callback called with null services"); return; }
1703
1704 // clear service pointers to parent request state
1705 if (pair->local) pair->local->request = NULL;
1706 if (pair->global) pair->global->request = NULL;
1707
1708 // only safe to free memory if registration is not valid, ie deregister fails
1709 if (pair->local && mDNS_DeregisterService(gmDNS, pair->local->srs) != mStatus_NoError)
1710 free_service_registration(pair->local);
1711 if (pair->global && mDNS_DeregisterService(gmDNS, pair->global->srs) != mStatus_NoError)
1712 free_service_registration(pair->global);
1713
1714 // clear pointers to services - they'll get cleaned by MemFree callback
1715 pair->local = NULL;
1716 pair->global = NULL;
1717 }
1718
1719
1720 static void handle_regrecord_request(request_state *rstate)
1721 {
1722 AuthRecord *rr;
1723 regrecord_callback_context *rcc;
1724 registered_record_entry *re;
1725 mStatus result;
1726
1727 if (rstate->ts != t_complete)
1728 {
1729 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
1730 abort_request(rstate);
1731 unlink_request(rstate);
1732 return;
1733 }
1734
1735 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
1736 if (!rr)
1737 {
1738 deliver_error(rstate, mStatus_BadParamErr);
1739 return;
1740 }
1741
1742 rcc = mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context));
1743 if (!rcc) goto malloc_error;
1744 rcc->rstate = rstate;
1745 rcc->client_context = rstate->hdr.client_context;
1746 rr->RecordContext = rcc;
1747 rr->RecordCallback = regrecord_callback;
1748
1749 // allocate registration entry, link into list
1750 re = mallocL("hanlde_regrecord_request", sizeof(registered_record_entry));
1751 if (!re) goto malloc_error;
1752 re->key = rstate->hdr.reg_index;
1753 re->rr = rr;
1754 re->next = rstate->reg_recs;
1755 rstate->reg_recs = re;
1756
1757 if (!rstate->terminate)
1758 {
1759 rstate->terminate = connected_registration_termination;
1760 rstate->termination_context = rstate;
1761 }
1762
1763 result = mDNS_Register(gmDNS, rr);
1764 deliver_error(rstate, result);
1765 reset_connected_rstate(rstate);
1766 return;
1767
1768 malloc_error:
1769 my_perror("ERROR: malloc");
1770 return;
1771 }
1772
1773 static void regrecord_callback(mDNS *const m _UNUSED, AuthRecord *const rr, mStatus result)
1774 {
1775 regrecord_callback_context *rcc = rr->RecordContext;
1776 int len;
1777 reply_state *reply;
1778 transfer_state ts;
1779
1780 if (result == mStatus_MemFree)
1781 {
1782 freeL("regrecord_callback", rcc);
1783 rr->RecordContext = NULL;
1784 freeL("regrecord_callback", rr);
1785 return;
1786 }
1787
1788 // format result, add to the list for the request, including the client context in the header
1789 len = sizeof(DNSServiceFlags);
1790 len += sizeof(uint32_t); //interfaceIndex
1791 len += sizeof(DNSServiceErrorType);
1792
1793 reply = create_reply(reg_record_reply, len, rcc->rstate);
1794 reply->mhdr->client_context = rcc->client_context;
1795 reply->rhdr->flags = 0;
1796 reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID);
1797 reply->rhdr->error = result;
1798
1799 ts = send_msg(reply);
1800 if (ts == t_error || ts == t_terminated)
1801 {
1802 abort_request(rcc->rstate);
1803 unlink_request(rcc->rstate);
1804 }
1805 else if (ts == t_complete) freeL("regrecord_callback", reply);
1806 else if (ts == t_morecoming) append_reply(rcc->rstate, reply); // client is blocked, link reply into list
1807 }
1808
1809 static void connected_registration_termination(void *context)
1810 {
1811 int shared;
1812 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
1813 while(ptr)
1814 {
1815 fptr = ptr;
1816 ptr = ptr->next;
1817 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
1818 mDNS_Deregister(gmDNS, fptr->rr);
1819 if (!shared)
1820 // shared records free'd via callback w/ mStatus_MemFree
1821 {
1822 freeL("connected_registration_termination", fptr->rr->RecordContext);
1823 fptr->rr->RecordContext = NULL;
1824 freeL("connected_registration_termination", fptr->rr);
1825 fptr->rr = NULL;
1826 }
1827 freeL("connected_registration_termination", fptr);
1828 }
1829 }
1830
1831
1832
1833 static void handle_removerecord_request(request_state *rstate)
1834 {
1835 mStatus err;
1836 char *ptr;
1837
1838 ptr = rstate->msgdata;
1839 get_flags(&ptr); // flags unused
1840
1841 if (rstate->servicepair.local) err = remove_extra_rr_from_service(rstate);
1842 else err = remove_record(rstate);
1843
1844 reset_connected_rstate(rstate);
1845 if (deliver_error(rstate, err) < 0)
1846 {
1847 abort_request(rstate);
1848 unlink_request(rstate);
1849 }
1850 }
1851
1852 // remove a resource record registered via DNSServiceRegisterRecord()
1853 static mStatus remove_record(request_state *rstate)
1854 {
1855 int shared;
1856 registered_record_entry *reptr, *prev = NULL;
1857 mStatus err = mStatus_UnknownErr;
1858 reptr = rstate->reg_recs;
1859
1860 while(reptr)
1861 {
1862 if (reptr->key == rstate->hdr.reg_index) // found match
1863 {
1864 if (prev) prev->next = reptr->next;
1865 else rstate->reg_recs = reptr->next;
1866 shared = reptr->rr->resrec.RecordType == kDNSRecordTypeShared;
1867 err = mDNS_Deregister(gmDNS, reptr->rr);
1868 if (err)
1869 {
1870 LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
1871 return err; // this should not happen. don't try to free memory if there's an error
1872 }
1873 if (!shared)
1874 // shared records free'd via callback w/ mStatus_MemFree
1875 {
1876 freeL("remove_record", reptr->rr->RecordContext);
1877 reptr->rr->RecordContext = NULL;
1878 freeL("remove_record", reptr->rr);
1879 reptr->rr = NULL;
1880 }
1881 freeL("remove_record", reptr);
1882 break;
1883 }
1884 prev = reptr;
1885 reptr = reptr->next;
1886 }
1887 return err;
1888 }
1889
1890
1891 static mStatus remove_extra(request_state *rstate, registered_service *serv)
1892 {
1893 mStatus err = mStatus_BadReferenceErr;
1894 extra_record_entry *ptr, *prev = NULL;
1895
1896 ptr = serv->extras;
1897 while (ptr)
1898 {
1899 if (ptr->key == rstate->hdr.reg_index) // found match
1900 {
1901 if (prev) prev->next = ptr->next;
1902 else serv->extras = ptr->next;
1903 err = mDNS_RemoveRecordFromService(gmDNS, serv->srs, &ptr->e);
1904 if (err) return err;
1905 freeL("remove_extra_rr_from_service", ptr);
1906 break;
1907 }
1908 prev = ptr;
1909 ptr = ptr->next;
1910 }
1911 return err;
1912 }
1913
1914 static mStatus remove_extra_rr_from_service(request_state *rstate)
1915 {
1916 mStatus err = mStatus_UnknownErr;
1917
1918 err = remove_extra(rstate, rstate->servicepair.local);
1919 if (rstate->servicepair.global) remove_extra(rstate, rstate->servicepair.global); // don't return error for global
1920
1921 return err;
1922 }
1923
1924
1925
1926 // domain enumeration
1927 static void handle_enum_request(request_state *rstate)
1928 {
1929 DNSServiceFlags flags, add_default;
1930 uint32_t ifi;
1931 mDNSInterfaceID InterfaceID;
1932 char *ptr = rstate->msgdata;
1933 domain_enum_t *def, *all;
1934 enum_termination_t *term;
1935 reply_state *reply; // initial default reply
1936 transfer_state tr;
1937 mStatus err;
1938 int result;
1939
1940 if (rstate->ts != t_complete)
1941 {
1942 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
1943 abort_request(rstate);
1944 unlink_request(rstate);
1945 return;
1946 }
1947
1948 flags = get_flags(&ptr);
1949 ifi = get_long(&ptr);
1950 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1951 if (ifi && !InterfaceID)
1952 {
1953 deliver_error(rstate, mStatus_BadParamErr);
1954 abort_request(rstate);
1955 unlink_request(rstate);
1956 }
1957
1958 // allocate context structures
1959 def = mallocL("hanlde_enum_request", sizeof(domain_enum_t));
1960 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
1961 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
1962 if (!def || !all || !term)
1963 {
1964 my_perror("ERROR: malloc");
1965 exit(1);
1966 }
1967
1968 // enumeration requires multiple questions, so we must link all the context pointers so that
1969 // necessary context can be reached from the callbacks
1970 def->rstate = rstate;
1971 all->rstate = rstate;
1972 term->def = def;
1973 term->all = all;
1974 term->rstate = rstate;
1975 rstate->termination_context = term;
1976 rstate->terminate = enum_termination_callback;
1977 def->question.QuestionContext = def;
1978 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
1979 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
1980 all->question.QuestionContext = all;
1981 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
1982 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
1983
1984 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
1985 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
1986
1987 // make the calls
1988 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
1989 if (err == mStatus_NoError)
1990 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
1991 result = deliver_error(rstate, err); // send error *before* returning local domain
1992
1993 if (result < 0 || err)
1994 {
1995 abort_request(rstate);
1996 unlink_request(rstate);
1997 return;
1998 }
1999
2000 // provide local. as the first domain automatically
2001 add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd;
2002 reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
2003 tr = send_msg(reply);
2004 if (tr == t_error || tr == t_terminated)
2005 {
2006 freeL("handle_enum_request", def);
2007 freeL("handle_enum_request", all);
2008 abort_request(rstate);
2009 unlink_request(rstate);
2010 return;
2011 }
2012 if (tr == t_complete) freeL("handle_enum_request", reply);
2013 if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
2014 }
2015
2016 static void enum_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2017 {
2018 char domain[MAX_ESCAPED_DOMAIN_NAME];
2019 domain_enum_t *de = question->QuestionContext;
2020 DNSServiceFlags flags = 0;
2021 reply_state *reply;
2022
2023 if (answer->rrtype != kDNSType_PTR) return;
2024 if (AddRecord)
2025 {
2026 flags |= kDNSServiceFlagsAdd;
2027 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
2028 flags |= kDNSServiceFlagsDefault;
2029 }
2030 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
2031 reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID), kDNSServiceErr_NoError);
2032 if (!reply)
2033 {
2034 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
2035 return;
2036 }
2037 reply->next = NULL;
2038 append_reply(de->rstate, reply);
2039 return;
2040 }
2041
2042 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
2043 {
2044 int len;
2045 reply_state *reply;
2046 char *data;
2047
2048
2049 len = sizeof(DNSServiceFlags);
2050 len += sizeof(uint32_t);
2051 len += sizeof(DNSServiceErrorType);
2052 len += strlen(domain) + 1;
2053
2054 reply = create_reply(enumeration_reply, len, rstate);
2055 reply->rhdr->flags = flags;
2056 reply->rhdr->ifi = ifi;
2057 reply->rhdr->error = err;
2058 data = reply->sdata;
2059 put_string(domain, &data);
2060 return reply;
2061 }
2062
2063 static void enum_termination_callback(void *context)
2064 {
2065 enum_termination_t *t = context;
2066 mDNS *coredata = gmDNS;
2067
2068 mDNS_StopGetDomains(coredata, &t->all->question);
2069 mDNS_StopGetDomains(coredata, &t->def->question);
2070 freeL("enum_termination_callback", t->all);
2071 freeL("enum_termination_callback", t->def);
2072 t->rstate->termination_context = NULL;
2073 freeL("enum_termination_callback", t);
2074 }
2075
2076 static void handle_reconfirm_request(request_state *rstate)
2077 {
2078 AuthRecord *rr;
2079
2080 rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
2081 if (!rr) return;
2082 mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
2083 abort_request(rstate);
2084 unlink_request(rstate);
2085 freeL("handle_reconfirm_request", rr);
2086 }
2087
2088
2089 // setup rstate to accept new reg/dereg requests
2090 static void reset_connected_rstate(request_state *rstate)
2091 {
2092 rstate->ts = t_morecoming;
2093 rstate->hdr_bytes = 0;
2094 rstate->data_bytes = 0;
2095 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
2096 rstate->msgbuf = NULL;
2097 rstate->bufsize = 0;
2098 }
2099
2100
2101
2102 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
2103 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
2104 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
2105 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags)
2106 {
2107 char *rdata, name[256];
2108 AuthRecord *rr;
2109 DNSServiceFlags flags;
2110 uint32_t interfaceIndex;
2111 uint16_t type, class, rdlen;
2112 int storage_size;
2113
2114 flags = get_flags(&msgbuf);
2115 if (validate_flags &&
2116 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
2117 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
2118 {
2119 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
2120 return NULL;
2121 }
2122
2123 interfaceIndex = get_long(&msgbuf);
2124 if (get_string(&msgbuf, name, 256) < 0)
2125 {
2126 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
2127 return NULL;
2128 }
2129 type = get_short(&msgbuf);
2130 class = get_short(&msgbuf);
2131 rdlen = get_short(&msgbuf);
2132
2133 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
2134 else storage_size = sizeof(RDataBody);
2135
2136 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
2137 if (!rr)
2138 {
2139 my_perror("ERROR: malloc");
2140 exit(1);
2141 }
2142 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
2143 rr->resrec.rdata = &rr->rdatastorage;
2144 rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
2145 if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
2146 {
2147 LogMsg("ERROR: bad name: %s", name);
2148 freeL("read_rr_from_ipc_msg", rr);
2149 return NULL;
2150 }
2151 rr->resrec.rrtype = type;
2152 if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
2153 rr->resrec.RecordType = kDNSRecordTypeShared;
2154 if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
2155 rr->resrec.RecordType = kDNSRecordTypeUnique;
2156 rr->resrec.rrclass = class;
2157 rr->resrec.rdlength = rdlen;
2158 rr->resrec.rdata->MaxRDLength = rdlen;
2159 rdata = get_rdata(&msgbuf, rdlen);
2160 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
2161 if (ttl)
2162 {
2163 rr->resrec.rroriginalttl = get_long(&msgbuf);
2164 }
2165 return rr;
2166 }
2167
2168
2169 // generate a response message for a browse result, service registration result, or any other call with the
2170 // identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
2171 // and mStatus_NoError is returned. otherwise the appropriate error is returned.
2172
2173 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
2174 {
2175 char *data;
2176 int len;
2177 domainlabel name;
2178 domainname type, dom;
2179 char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2180 char typestr[MAX_ESCAPED_DOMAIN_NAME];
2181 char domstr [MAX_ESCAPED_DOMAIN_NAME];
2182
2183 *rep = NULL;
2184
2185 if (!DeconstructServiceName(servicename, &name, &type, &dom))
2186 return kDNSServiceErr_Unknown;
2187
2188 ConvertDomainLabelToCString_unescaped(&name, namestr);
2189 ConvertDomainNameToCString(&type, typestr);
2190 ConvertDomainNameToCString(&dom, domstr);
2191
2192 // calculate reply data length
2193 len = sizeof(DNSServiceFlags);
2194 len += sizeof(uint32_t); // if index
2195 len += sizeof(DNSServiceErrorType);
2196 len += strlen(namestr) + 1;
2197 len += strlen(typestr) + 1;
2198 len += strlen(domstr) + 1;
2199
2200 *rep = create_reply(query_reply, len, request);
2201 (*rep)->rhdr->flags = 0;
2202 (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id);
2203 (*rep)->rhdr->error = kDNSServiceErr_NoError;
2204 data = (*rep)->sdata;
2205
2206 put_string(namestr, &data);
2207 put_string(typestr, &data);
2208 put_string(domstr, &data);
2209 return mStatus_NoError;
2210 }
2211
2212
2213 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
2214 {
2215 domainlabel n;
2216 domainname d, t;
2217
2218 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
2219 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
2220 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
2221 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
2222 return 0;
2223 }
2224
2225
2226 // append a reply to the list in a request object
2227 static void append_reply(request_state *req, reply_state *rep)
2228 {
2229 reply_state *ptr;
2230
2231 if (!req->replies) req->replies = rep;
2232 else
2233 {
2234 ptr = req->replies;
2235 while (ptr->next) ptr = ptr->next;
2236 ptr->next = rep;
2237 }
2238 rep->next = NULL;
2239 }
2240
2241
2242 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
2243 // returns the current state of the request (morecoming, error, complete, terminated.)
2244 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
2245 static int read_msg(request_state *rs)
2246 {
2247 uint32_t nleft;
2248 int nread;
2249 char buf[4]; // dummy for death notification
2250
2251 if (rs->ts == t_terminated || rs->ts == t_error)
2252 {
2253 LogMsg("ERROR: read_msg called with transfer state terminated or error");
2254 rs->ts = t_error;
2255 return t_error;
2256 }
2257
2258 if (rs->ts == t_complete)
2259 { // this must be death or something is wrong
2260 nread = recv(rs->sd, buf, 4, 0);
2261 if (!nread) { rs->ts = t_terminated; return t_terminated; }
2262 if (nread < 0) goto rerror;
2263 LogMsg("ERROR: read data from a completed request.");
2264 rs->ts = t_error;
2265 return t_error;
2266 }
2267
2268 if (rs->ts != t_morecoming)
2269 {
2270 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
2271 rs->ts = t_error;
2272 return t_error;
2273 }
2274
2275 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
2276 {
2277 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
2278 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
2279 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
2280 if (nread < 0) goto rerror;
2281 rs->hdr_bytes += nread;
2282 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
2283 {
2284 LogMsg("ERROR: read_msg - read too many header bytes");
2285 rs->ts = t_error;
2286 return t_error;
2287 }
2288 }
2289
2290 // only read data if header is complete
2291 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
2292 {
2293 if (rs->hdr.datalen == 0) // ok in removerecord requests
2294 {
2295 rs->ts = t_complete;
2296 rs->msgbuf = NULL;
2297 return t_complete;
2298 }
2299
2300 if (!rs->msgbuf) // allocate the buffer first time through
2301 {
2302 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
2303 if (!rs->msgbuf)
2304 {
2305 my_perror("ERROR: malloc");
2306 rs->ts = t_error;
2307 return t_error;
2308 }
2309 rs->msgdata = rs->msgbuf;
2310 }
2311 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
2312 nleft = rs->hdr.datalen - rs->data_bytes;
2313 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
2314 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
2315 if (nread < 0) goto rerror;
2316 rs->data_bytes += nread;
2317 if (rs->data_bytes > rs->hdr.datalen)
2318 {
2319 LogMsg("ERROR: read_msg - read too many data bytes");
2320 rs->ts = t_error;
2321 return t_error;
2322 }
2323 }
2324
2325 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
2326 rs->ts = t_complete;
2327 else rs->ts = t_morecoming;
2328
2329 return rs->ts;
2330
2331 rerror:
2332 if (errno == EAGAIN || errno == EINTR) return rs->ts;
2333 my_perror("ERROR: read_msg");
2334 rs->ts = t_error;
2335 return t_error;
2336 }
2337
2338
2339 static int send_msg(reply_state *rs)
2340 {
2341 ssize_t nwriten;
2342
2343 if (!rs->msgbuf)
2344 {
2345 LogMsg("ERROR: send_msg called with NULL message buffer");
2346 return t_error;
2347 }
2348
2349 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
2350 {
2351 rs->ts = t_complete;
2352 freeL("send_msg", rs->msgbuf);
2353 return t_complete;
2354 }
2355
2356 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
2357 if (nwriten < 0)
2358 {
2359 if (errno == EINTR || errno == EAGAIN) nwriten = 0;
2360 else
2361 {
2362 if (errno == EPIPE)
2363 {
2364 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
2365 rs->ts = t_terminated;
2366 rs->request->ts = t_terminated;
2367 return t_terminated;
2368 }
2369 else
2370 {
2371 my_perror("ERROR: send\n");
2372 rs->ts = t_error;
2373 return t_error;
2374 }
2375 }
2376 }
2377 rs->nwriten += nwriten;
2378
2379 if (rs->nwriten == rs->len)
2380 {
2381 rs->ts = t_complete;
2382 freeL("send_msg", rs->msgbuf);
2383 }
2384 return rs->ts;
2385 }
2386
2387
2388
2389 static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
2390 {
2391 reply_state *reply;
2392 int totallen;
2393
2394
2395 if ((unsigned)datalen < sizeof(reply_hdr))
2396 {
2397 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
2398 return NULL;
2399 }
2400
2401 totallen = datalen + sizeof(ipc_msg_hdr);
2402 reply = mallocL("create_reply", sizeof(reply_state));
2403 if (!reply)
2404 {
2405 my_perror("ERROR: malloc");
2406 exit(1);
2407 }
2408 bzero(reply, sizeof(reply_state));
2409 reply->ts = t_morecoming;
2410 reply->sd = request->sd;
2411 reply->request = request;
2412 reply->len = totallen;
2413 reply->msgbuf = mallocL("create_reply", totallen);
2414 if (!reply->msgbuf)
2415 {
2416 my_perror("ERROR: malloc");
2417 exit(1);
2418 }
2419 bzero(reply->msgbuf, totallen);
2420 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
2421 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
2422 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
2423 reply->mhdr->version = VERSION;
2424 reply->mhdr->op.reply_op = op;
2425 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
2426 return reply;
2427 }
2428
2429
2430 static int deliver_error(request_state *rstate, mStatus err)
2431 {
2432 int nwritten = -1;
2433 undelivered_error_t *undeliv;
2434
2435 nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
2436 if (nwritten < (int)sizeof(mStatus))
2437 {
2438 if (errno == EINTR || errno == EAGAIN)
2439 nwritten = 0;
2440 if (nwritten < 0)
2441 {
2442 my_perror("ERROR: send - unable to deliver error to client");
2443 goto error;
2444 }
2445 //client blocked - store result and come backr
2446 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
2447 if (!undeliv)
2448 {
2449 my_perror("ERROR: malloc");
2450 exit(1);
2451 }
2452 undeliv->err = err;
2453 undeliv->nwritten = nwritten;
2454 undeliv->sd = rstate->errfd;
2455 rstate->u_err = undeliv;
2456 return 0;
2457 }
2458 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2459 return 0;
2460
2461 error:
2462 if (rstate->errfd != rstate->sd) close(rstate->errfd);
2463 return -1;
2464
2465 }
2466
2467
2468 // returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
2469 static transfer_state send_undelivered_error(request_state *rs)
2470 {
2471 int nwritten;
2472
2473 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
2474 if (nwritten < 0)
2475 {
2476 if (errno == EINTR || errno == EAGAIN)
2477 nwritten = 0;
2478 else
2479 {
2480 my_perror("ERROR: send - unable to deliver error to client\n");
2481 if (rs->u_err->sd == rs->sd) close (rs->u_err->sd);
2482 return t_error;
2483 }
2484 }
2485 if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
2486 {
2487 if (rs->u_err->sd == rs->sd) close(rs->u_err->sd);
2488 freeL("send_undelivered_error", rs->u_err);
2489 rs->u_err = NULL;
2490 return t_complete;
2491 }
2492 rs->u_err->nwritten += nwritten;
2493 return t_morecoming;
2494 }
2495
2496
2497 // send bogus data along with an error code to the app callback
2498 // returns 0 on success (linking reply into list of not fully delivered),
2499 // -1 on failure (request should be aborted)
2500 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
2501 {
2502 int len;
2503 reply_state *reply;
2504 transfer_state ts;
2505
2506 if (rs->no_reply) return 0;
2507 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
2508 reply = create_reply(op, len, rs);
2509 reply->rhdr->error = err;
2510 ts = send_msg(reply);
2511 if (ts == t_error || ts == t_terminated)
2512 {
2513 freeL("deliver_async_error", reply);
2514 return -1;
2515 }
2516 else if (ts == t_complete) freeL("deliver_async_error", reply);
2517 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
2518 return 0;
2519 }
2520
2521
2522 static void abort_request(request_state *rs)
2523 {
2524 reply_state *rep, *ptr;
2525
2526 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
2527 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
2528 udsSupportRemoveFDFromEventLoop(rs->sd);
2529 rs->sd = -1;
2530 if (rs->errfd >= 0) close(rs->errfd);
2531 rs->errfd = -1;
2532
2533 // free pending replies
2534 rep = rs->replies;
2535 while(rep)
2536 {
2537 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
2538 ptr = rep;
2539 rep = rep->next;
2540 freeL("abort_request", ptr);
2541 }
2542
2543 if (rs->u_err)
2544 {
2545 freeL("abort_request", rs->u_err);
2546 rs->u_err = NULL;
2547 }
2548 }
2549
2550
2551 static void unlink_request(request_state *rs)
2552 {
2553 request_state *ptr;
2554
2555 if (rs == all_requests)
2556 {
2557 all_requests = all_requests->next;
2558 freeL("unlink_request", rs);
2559 return;
2560 }
2561 for(ptr = all_requests; ptr->next; ptr = ptr->next)
2562 if (ptr->next == rs)
2563 {
2564 ptr->next = rs->next;
2565 freeL("unlink_request", rs);
2566 return;
2567 }
2568 }
2569
2570
2571
2572 //hack to search-replace perror's to LogMsg's
2573 static void my_perror(char *errmsg)
2574 {
2575 LogMsg("%s: %s", errmsg, strerror(errno));
2576 }
2577
2578 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
2579 // without overrunning it.
2580 // returns 0 on success, -1 on error.
2581
2582 static int validate_message(request_state *rstate)
2583 {
2584 uint32_t min_size;
2585
2586 switch(rstate->hdr.op.request_op)
2587 {
2588 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
2589 sizeof(uint32_t) + // interface
2590 (3 * sizeof(char)); // name, regtype, domain
2591 break;
2592 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
2593 sizeof(uint32_t) + // interface
2594 sizeof(char) + // fullname
2595 (2 * sizeof(uint16_t)); // type, class
2596 break;
2597 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
2598 sizeof(uint32_t) + // interface
2599 (2 * sizeof(char)); // regtype, domain
2600 break;
2601 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
2602 sizeof(uint32_t) + // interface
2603 (4 * sizeof(char)) + // name, type, domain, host
2604 (2 * sizeof(uint16_t)); // port, textlen
2605 break;
2606 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
2607 sizeof(uint32_t); // interface
2608 break;
2609 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
2610 sizeof(uint32_t) + // interface
2611 sizeof(char) + // fullname
2612 (3 * sizeof(uint16_t)) + // type, class, rdlen
2613 sizeof(uint32_t); // ttl
2614 break;
2615 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
2616 (2 * sizeof(uint16_t)) + // type, rdlen
2617 sizeof(uint32_t); // ttl
2618 break;
2619 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
2620 sizeof(uint16_t) + // rdlen
2621 sizeof(uint32_t); // ttl
2622 break;
2623 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
2624 break;
2625 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
2626 sizeof(uint32_t) + // interface
2627 sizeof(char) + // fullname
2628 (3 * sizeof(uint16_t)); // type, class, rdlen
2629 default:
2630 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op.request_op);
2631 return -1;
2632 }
2633
2634 return (rstate->data_bytes >= min_size ? 0 : -1);
2635
2636 }
2637
2638