Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / Private / dnsctl_server.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2015 Apple Inc. All rights reserved.
4  *
5  * dnsctl_server.c
6  * mDNSResponder 
7  *
8  * XPC as an IPC mechanism to communicate with dnsctl. Open only to Apple OSX/iOS clients
9  */
10
11 #include "xpc_services.h"
12 #include "dns_xpc.h"
13
14 #include "mDNSMacOSX.h"      // KQueueLock/KQueueUnlock
15 #include "helper.h"          // mDNSResponderHelper tests
16 #include <xpc/xpc.h>
17
18 // ***************************************************************************
19 // Globals
20 extern mDNS mDNSStorage;
21 static dispatch_queue_t dnsctlserver_queue = NULL;
22 // ***************************************************************************
23
24 mDNSlocal void handle_logging(mDNSu32 log_level)
25 {
26     KQueueLock();
27     
28     switch (log_level)
29     {
30         case log_level1:
31             mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0;
32             LogMsg("USR1 Logging:[%s] USR2 Logging:[%s]", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
33             break;
34             
35         case log_level2:
36             mDNS_LoggingEnabled = 1;
37             LogMsg("USR1 Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
38             break;
39             
40         case log_level3:
41             mDNS_PacketLoggingEnabled = 1;
42             LogMsg("USR2 Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
43             break;
44             
45         case log_level4:
46             mDNS_LoggingEnabled = 1 ;
47             mDNS_PacketLoggingEnabled = 1;
48             LogMsg("USR1 Logging:%s USR2 Logging:%s", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
49             break;
50             
51         default:
52             mDNS_LoggingEnabled = 0 ;
53             mDNS_PacketLoggingEnabled = 0;
54             break;
55     }
56     UpdateDebugState();
57     
58     KQueueUnlock("LogLevel changed");
59 }
60
61 mDNSlocal void handle_stateinfo(mDNSu32 state_level)
62 {
63     KQueueLock();
64     
65     switch (state_level)
66     {
67         case full_state:
68             INFOCallback();
69             break;
70             
71         default:
72             INFOCallback();
73             break;
74     }
75     
76     KQueueUnlock("StateInfo dumped");
77 }
78
79
80 mDNSlocal void handle_test_mode(mDNSu32 test_mode)
81 {
82     KQueueLock();
83     
84     switch (test_mode)
85     {
86         case test_helper_ipc:
87             mDNSNotify("mDNSResponderHelperTest", "This is just a test message to mDNSResponderHelper. This is NOT an actual alert");
88             break;
89             
90         case test_mDNS_log:
91             LogInfo("LogInfo: Should be logged at INFO level");
92             LogOperation("LogOperation: Should be logged at INFO level");
93             LogMsg("LogMsg: Should be logged at DEFAULT level");
94             LogSPS("LogSPS: Should be logged at INFO level");
95             break;
96             
97         default:
98             LogMsg("Unidentified Test mode: Please add this test");
99             break;
100     }
101     
102     KQueueUnlock("Test Msg to mDNSResponderHelper");
103 }
104
105 mDNSlocal void handle_terminate()
106 {
107     
108     LogInfo("handle_terminate: Client terminated connection.");
109     
110 }
111
112 mDNSlocal void handle_requests(xpc_object_t req)
113 {
114     mDNSu32 log_level, state_level, test_mode;
115     xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
116
117     LogInfo("handle_requests: Handler for dnsctl requests");
118  
119     xpc_object_t response = xpc_dictionary_create_reply(req);
120     
121     // Return Success Status to the client (essentially ACKing the request)
122     if (response)
123     {
124         xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
125         xpc_connection_send_message(remote_conn, response);
126         xpc_release(response);  
127     }
128     else
129     { 
130         LogMsg("handle_requests: Response Dictionary could not be created");
131         return;
132     }
133
134     // switch here based on dictionary
135     // to handle various different requests like logging, INFO snapshot, etc..
136     if ((xpc_dictionary_get_uint64(req, kDNSLogLevel)))
137     {
138         log_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSLogLevel));
139         handle_logging(log_level);
140     }
141     else if ((xpc_dictionary_get_uint64(req, kDNSStateInfo)))
142     {
143         state_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSStateInfo));
144         handle_stateinfo(state_level);
145     }
146     else if ((xpc_dictionary_get_uint64(req, kmDNSResponderTests)))
147     {
148         test_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kmDNSResponderTests));
149         handle_test_mode(test_mode);
150     }
151 }
152
153 mDNSlocal void accept_client(xpc_connection_t conn)
154 {
155     uid_t c_euid;
156     int   c_pid;
157     c_euid  = xpc_connection_get_euid(conn);
158     c_pid   = xpc_connection_get_pid(conn);
159
160     if (c_euid != 0 || !IsEntitled(conn, kDNSCTLService))
161     {   
162         LogMsg("accept_client: Client PID[%d] is missing Entitlement or is NOT running as root!", c_pid);
163         xpc_connection_cancel(conn);
164         return; 
165     }
166     
167     xpc_retain(conn);
168     xpc_connection_set_target_queue(conn, dnsctlserver_queue);
169     xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
170         {
171             xpc_type_t type = xpc_get_type(req_msg);
172
173             if (type == XPC_TYPE_DICTIONARY)
174             {
175                 handle_requests(req_msg);
176             }
177             else // We hit this case ONLY if Client Terminated Connection OR Crashed
178             {
179                 LogInfo("accept_client: Client %p teared down the connection", (void *) conn);
180                 handle_terminate();
181                 xpc_release(conn);
182             }
183         });
184     
185     xpc_connection_resume(conn);
186                 
187 }
188
189 mDNSexport void init_dnsctl_service(void)
190 {
191     
192     xpc_connection_t dnsctl_listener = xpc_connection_create_mach_service(kDNSCTLService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
193     if (!dnsctl_listener || xpc_get_type(dnsctl_listener) != XPC_TYPE_CONNECTION)
194     {
195         LogMsg("init_dnsctl_service: Error Creating XPC Listener for DNSCTL Server!");
196         return;
197     }
198     
199     dnsctlserver_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsctlserver_queue", NULL);
200     
201     xpc_connection_set_event_handler(dnsctl_listener, ^(xpc_object_t eventmsg)
202         {
203             xpc_type_t type = xpc_get_type(eventmsg);
204
205             if (type == XPC_TYPE_CONNECTION)
206             {
207                 LogInfo("init_dnsctl_service: New DNSCTL Client %p", eventmsg);
208                 accept_client(eventmsg);
209             }
210             else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
211             {
212                 LogMsg("init_dnsctl_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
213             }
214             else
215             {
216                 LogMsg("init_dnsctl_service: Unknown EventMsg type");
217             }
218         });
219     
220     xpc_connection_resume(dnsctl_listener);
221 }
222
223
224