diff options
| author | 2022-12-10 02:22:12 +0100 | |
|---|---|---|
| committer | 2022-12-10 02:22:12 +0100 | |
| commit | a6775bc588db13838bebec42b139748d337e7189 (patch) | |
| tree | d4e929e40bb8b2c812fcc38443033abf65bffdb6 | |
| parent | b314f04bd791b263cf43fadc6ac0756e67ab4ed0 (diff) | |
| download | libimobiledevice-a6775bc588db13838bebec42b139748d337e7189.tar.gz libimobiledevice-a6775bc588db13838bebec42b139748d337e7189.tar.bz2 | |
tools: Add idevicedevmodectl tool
| -rw-r--r-- | docs/Makefile.am | 1 | ||||
| -rw-r--r-- | docs/idevicedevmodectl.1 | 58 | ||||
| -rw-r--r-- | tools/Makefile.am | 6 | ||||
| -rw-r--r-- | tools/idevicedevmodectl.c | 451 |
4 files changed, 516 insertions, 0 deletions
diff --git a/docs/Makefile.am b/docs/Makefile.am index 9cdf82e..4a4c56f 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am | |||
| @@ -16,6 +16,7 @@ man_MANS = \ | |||
| 16 | idevicecrashreport.1 \ | 16 | idevicecrashreport.1 \ |
| 17 | idevicename.1 \ | 17 | idevicename.1 \ |
| 18 | idevicedebug.1 \ | 18 | idevicedebug.1 \ |
| 19 | idevicedevmodectl.1 \ | ||
| 19 | idevicenotificationproxy.1 \ | 20 | idevicenotificationproxy.1 \ |
| 20 | idevicesetlocation.1 | 21 | idevicesetlocation.1 |
| 21 | 22 | ||
diff --git a/docs/idevicedevmodectl.1 b/docs/idevicedevmodectl.1 new file mode 100644 index 0000000..5edaa80 --- /dev/null +++ b/docs/idevicedevmodectl.1 | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | .TH "idevicedevmodectl" 1 | ||
| 2 | .SH NAME | ||
| 3 | idevicedevmodectl \- Enable Developer Mode on iOS 16+ devices or print the current status. | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .B idevicedevmodectl | ||
| 6 | COMMAND | ||
| 7 | [OPTIONS] | ||
| 8 | |||
| 9 | .SH DESCRIPTION | ||
| 10 | |||
| 11 | Enable Developer Mode on iOS 16+ devices or print the current status. | ||
| 12 | |||
| 13 | .SH NOTE | ||
| 14 | Passcode-protected devices will NOT allow enabling of Developer Mode from the command line. It has to be enabled on the device itself under Settings -> Privacy & Security -> Developer Mode. | ||
| 15 | The \f[B]enable\f[] command will try to enable it, and tell you if that's the case. | ||
| 16 | If the menu is not shown, you may use the \f[B]reveal\f[] command to reveal it. | ||
| 17 | |||
| 18 | .SH COMMANDS | ||
| 19 | .TP | ||
| 20 | .B list | ||
| 21 | Prints the Developer Mode status of all connected devices, or for a specific one if \f[B]\-\-udid\f[] is given. | ||
| 22 | .TP | ||
| 23 | .B enable | ||
| 24 | Enable Developer Mode (device will reboot), and confirm it after device booted up again. | ||
| 25 | .TP | ||
| 26 | .B arm | ||
| 27 | Arm the Developer Mode (device will reboot) | ||
| 28 | .TP | ||
| 29 | .B confirm | ||
| 30 | Confirm enabling of Developer Mode | ||
| 31 | .TP | ||
| 32 | .B reveal | ||
| 33 | Reveal the Developer Mode menu on the device under Settings -> Privacy & Security | ||
| 34 | |||
| 35 | .SH OPTIONS | ||
| 36 | .TP | ||
| 37 | .B \-u, \-\-udid UDID | ||
| 38 | target specific device by UDID | ||
| 39 | .TP | ||
| 40 | .B \-n, \-\-network | ||
| 41 | connect to network device | ||
| 42 | .TP | ||
| 43 | .B \-d, \-\-debug | ||
| 44 | enable communication debugging | ||
| 45 | .TP | ||
| 46 | .B \-h, \-\-help | ||
| 47 | print usage information | ||
| 48 | .TP | ||
| 49 | .B \-v, \-\-version | ||
| 50 | print version information | ||
| 51 | |||
| 52 | .SH AUTHORS | ||
| 53 | Nikias Bassen | ||
| 54 | |||
| 55 | .SH ON THE WEB | ||
| 56 | https://libimobiledevice.org | ||
| 57 | |||
| 58 | https://github.com/libimobiledevice/libimobiledevice | ||
diff --git a/tools/Makefile.am b/tools/Makefile.am index e8ef3ab..47e05b2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am | |||
| @@ -27,6 +27,7 @@ bin_PROGRAMS = \ | |||
| 27 | idevicedebugserverproxy \ | 27 | idevicedebugserverproxy \ |
| 28 | idevicediagnostics \ | 28 | idevicediagnostics \ |
| 29 | idevicedebug \ | 29 | idevicedebug \ |
| 30 | idevicedevmodectl \ | ||
| 30 | idevicenotificationproxy \ | 31 | idevicenotificationproxy \ |
| 31 | idevicecrashreport \ | 32 | idevicecrashreport \ |
| 32 | idevicesetlocation | 33 | idevicesetlocation |
| @@ -111,6 +112,11 @@ idevicedebug_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) | |||
| 111 | idevicedebug_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) | 112 | idevicedebug_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) |
| 112 | idevicedebug_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la | 113 | idevicedebug_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la |
| 113 | 114 | ||
| 115 | idevicedevmodectl_SOURCES = idevicedevmodectl.c | ||
| 116 | idevicedevmodectl_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) | ||
| 117 | idevicedevmodectl_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) | ||
| 118 | idevicedevmodectl_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la | ||
| 119 | |||
| 114 | idevicenotificationproxy_SOURCES = idevicenotificationproxy.c | 120 | idevicenotificationproxy_SOURCES = idevicenotificationproxy.c |
| 115 | idevicenotificationproxy_CFLAGS = $(AM_CFLAGS) | 121 | idevicenotificationproxy_CFLAGS = $(AM_CFLAGS) |
| 116 | idevicenotificationproxy_LDFLAGS = $(AM_LDFLAGS) | 122 | idevicenotificationproxy_LDFLAGS = $(AM_LDFLAGS) |
diff --git a/tools/idevicedevmodectl.c b/tools/idevicedevmodectl.c new file mode 100644 index 0000000..739bc13 --- /dev/null +++ b/tools/idevicedevmodectl.c | |||
| @@ -0,0 +1,451 @@ | |||
| 1 | /* | ||
| 2 | * idevicedevmodectl.c | ||
| 3 | * List or enable Developer Mode on iOS 16+ devices | ||
| 4 | * | ||
| 5 | * Copyright (c) 2022 Nikias Bassen, All Rights Reserved. | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifdef HAVE_CONFIG_H | ||
| 23 | #include <config.h> | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #define TOOL_NAME "idevicedevmodectl" | ||
| 27 | |||
| 28 | #include <stdio.h> | ||
| 29 | #include <stdlib.h> | ||
| 30 | #include <string.h> | ||
| 31 | #include <getopt.h> | ||
| 32 | #include <sys/stat.h> | ||
| 33 | #include <errno.h> | ||
| 34 | #ifndef WIN32 | ||
| 35 | #include <signal.h> | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #ifdef WIN32 | ||
| 39 | #include <windows.h> | ||
| 40 | #define __usleep(x) Sleep(x/1000) | ||
| 41 | #else | ||
| 42 | #include <arpa/inet.h> | ||
| 43 | #define __usleep(x) usleep(x) | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #include <libimobiledevice/libimobiledevice.h> | ||
| 47 | #include <libimobiledevice/lockdown.h> | ||
| 48 | #include <libimobiledevice/property_list_service.h> | ||
| 49 | #include <libimobiledevice-glue/utils.h> | ||
| 50 | |||
| 51 | #define AMFI_LOCKDOWN_SERVICE_NAME "com.apple.amfi.lockdown" | ||
| 52 | |||
| 53 | static char* udid = NULL; | ||
| 54 | static int use_network = 0; | ||
| 55 | |||
| 56 | static void print_usage(int argc, char **argv, int is_error) | ||
| 57 | { | ||
| 58 | char *name = strrchr(argv[0], '/'); | ||
| 59 | fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] COMMAND\n", (name ? name + 1: argv[0])); | ||
| 60 | fprintf(is_error ? stderr : stdout, | ||
| 61 | "\n" | ||
| 62 | "Enable Developer Mode on iOS 16+ devices or print the current status.\n" | ||
| 63 | "\n" | ||
| 64 | "Where COMMAND is one of:\n" | ||
| 65 | " list Print the Developer Mode status of all connected devices\n" | ||
| 66 | " or for a specific one if --udid is given.\n" | ||
| 67 | " enable Enable Developer Mode (device will reboot),\n" | ||
| 68 | " and confirm it after device booted up again.\n" | ||
| 69 | "\n" | ||
| 70 | " arm Arm the Developer Mode (device will reboot)\n" | ||
| 71 | " confirm Confirm enabling of Developer Mode\n" | ||
| 72 | " reveal Reveal the Developer Mode menu on the device\n" | ||
| 73 | "\n" | ||
| 74 | "The following OPTIONS are accepted:\n" | ||
| 75 | " -u, --udid UDID target specific device by UDID\n" | ||
| 76 | " -n, --network connect to network device\n" | ||
| 77 | " -d, --debug enable communication debugging\n" | ||
| 78 | " -h, --help print usage information\n" | ||
| 79 | " -v, --version print version information\n" | ||
| 80 | "\n" | ||
| 81 | "Homepage: <" PACKAGE_URL ">\n" | ||
| 82 | "Bug Reports: <" PACKAGE_BUGREPORT ">\n" | ||
| 83 | ); | ||
| 84 | } | ||
| 85 | |||
| 86 | enum { | ||
| 87 | OP_LIST, | ||
| 88 | OP_ENABLE, | ||
| 89 | OP_ARM, | ||
| 90 | OP_CONFIRM, | ||
| 91 | OP_REVEAL, | ||
| 92 | NUM_OPS | ||
| 93 | }; | ||
| 94 | #define DEV_MODE_REVEAL 0 | ||
| 95 | #define DEV_MODE_ARM 1 | ||
| 96 | #define DEV_MODE_ENABLE 2 | ||
| 97 | |||
| 98 | static int get_developer_mode_status(const char* device_udid, int _use_network) | ||
| 99 | { | ||
| 100 | idevice_error_t ret; | ||
| 101 | idevice_t device = NULL; | ||
| 102 | lockdownd_client_t lockdown = NULL; | ||
| 103 | lockdownd_error_t lerr = LOCKDOWN_E_UNKNOWN_ERROR; | ||
| 104 | plist_t val = NULL; | ||
| 105 | |||
| 106 | ret = idevice_new_with_options(&device, device_udid, (_use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); | ||
| 107 | if (ret != IDEVICE_E_SUCCESS) { | ||
| 108 | return -1; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { | ||
| 112 | idevice_free(device); | ||
| 113 | return -1; | ||
| 114 | } | ||
| 115 | |||
| 116 | lerr = lockdownd_get_value(lockdown, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); | ||
| 117 | if (lerr != LOCKDOWN_E_SUCCESS) { | ||
| 118 | fprintf(stderr, "ERROR: Could not get DeveloperModeStatus: %s\nPlease note that this feature is only available on iOS 16+.\n", lockdownd_strerror(lerr)); | ||
| 119 | lockdownd_client_free(lockdown); | ||
| 120 | idevice_free(device); | ||
| 121 | return -2; | ||
| 122 | } | ||
| 123 | |||
| 124 | uint8_t dev_mode_status = 0; | ||
| 125 | plist_get_bool_val(val, &dev_mode_status); | ||
| 126 | plist_free(val); | ||
| 127 | |||
| 128 | lockdownd_client_free(lockdown); | ||
| 129 | idevice_free(device); | ||
| 130 | |||
| 131 | return dev_mode_status; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int amfi_service_send_msg(property_list_service_client_t amfi, plist_t msg) | ||
| 135 | { | ||
| 136 | int res; | ||
| 137 | property_list_service_error_t perr; | ||
| 138 | |||
| 139 | perr = property_list_service_send_xml_plist(amfi, plist_copy(msg)); | ||
| 140 | if (perr != PROPERTY_LIST_SERVICE_E_SUCCESS) { | ||
| 141 | fprintf(stderr, "Could not send request to device: %d\n", perr); | ||
| 142 | res = 2; | ||
| 143 | } else { | ||
| 144 | plist_t reply = NULL; | ||
| 145 | perr = property_list_service_receive_plist(amfi, &reply); | ||
| 146 | if (perr == PROPERTY_LIST_SERVICE_E_SUCCESS) { | ||
| 147 | uint8_t success = 0; | ||
| 148 | plist_t val = plist_dict_get_item(reply, "Error"); | ||
| 149 | if (val) { | ||
| 150 | const char* err = plist_get_string_ptr(val, NULL); | ||
| 151 | fprintf(stderr, "Request failed: %s\n", err); | ||
| 152 | if (strstr(err, "passcode")) { | ||
| 153 | res = 2; | ||
| 154 | } else { | ||
| 155 | res = 1; | ||
| 156 | } | ||
| 157 | } else { | ||
| 158 | val = plist_dict_get_item(reply, "success"); | ||
| 159 | if (val) { | ||
| 160 | plist_get_bool_val(val, &success); | ||
| 161 | } | ||
| 162 | if (success) { | ||
| 163 | res = 0; | ||
| 164 | } else { | ||
| 165 | res = 1; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } else { | ||
| 169 | fprintf(stderr, "Could not receive reply from device: %d\n", perr); | ||
| 170 | res = 2; | ||
| 171 | } | ||
| 172 | plist_free(reply); | ||
| 173 | } | ||
| 174 | return res; | ||
| 175 | } | ||
| 176 | |||
| 177 | static int amfi_send_action(idevice_t device, unsigned int action) | ||
| 178 | { | ||
| 179 | lockdownd_client_t lockdown = NULL; | ||
| 180 | lockdownd_service_descriptor_t service = NULL; | ||
| 181 | lockdownd_error_t lerr; | ||
| 182 | |||
| 183 | if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { | ||
| 184 | fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lerr); | ||
| 185 | return 1; | ||
| 186 | } | ||
| 187 | |||
| 188 | lerr = lockdownd_start_service(lockdown, AMFI_LOCKDOWN_SERVICE_NAME, &service); | ||
| 189 | if (lerr != LOCKDOWN_E_SUCCESS) { | ||
| 190 | fprintf(stderr, "Could not start service %s: %s\nPlease note that this feature is only available on iOS 16+.\n", AMFI_LOCKDOWN_SERVICE_NAME, lockdownd_strerror(lerr)); | ||
| 191 | lockdownd_client_free(lockdown); | ||
| 192 | return 1; | ||
| 193 | } | ||
| 194 | lockdownd_client_free(lockdown); | ||
| 195 | lockdown = NULL; | ||
| 196 | |||
| 197 | property_list_service_client_t amfi = NULL; | ||
| 198 | if (property_list_service_client_new(device, service, &amfi) != PROPERTY_LIST_SERVICE_E_SUCCESS) { | ||
| 199 | fprintf(stderr, "Could not connect to %s on device\n", AMFI_LOCKDOWN_SERVICE_NAME); | ||
| 200 | if (service) | ||
| 201 | lockdownd_service_descriptor_free(service); | ||
| 202 | idevice_free(device); | ||
| 203 | return 1; | ||
| 204 | } | ||
| 205 | lockdownd_service_descriptor_free(service); | ||
| 206 | |||
| 207 | plist_t dict = plist_new_dict(); | ||
| 208 | plist_dict_set_item(dict, "action", plist_new_uint(action)); | ||
| 209 | |||
| 210 | int result = amfi_service_send_msg(amfi, dict); | ||
| 211 | plist_free(dict); | ||
| 212 | |||
| 213 | property_list_service_client_free(amfi); | ||
| 214 | amfi = NULL; | ||
| 215 | |||
| 216 | return result; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int device_connected = 0; | ||
| 220 | |||
| 221 | static void device_event_cb(const idevice_event_t* event, void* userdata) | ||
| 222 | { | ||
| 223 | if (use_network && event->conn_type != CONNECTION_NETWORK) { | ||
| 224 | return; | ||
| 225 | } | ||
| 226 | if (!use_network && event->conn_type != CONNECTION_USBMUXD) { | ||
| 227 | return; | ||
| 228 | } | ||
| 229 | if (event->event == IDEVICE_DEVICE_ADD) { | ||
| 230 | if (!udid) { | ||
| 231 | udid = strdup(event->udid); | ||
| 232 | } | ||
| 233 | if (strcmp(udid, event->udid) == 0) { | ||
| 234 | device_connected = 1; | ||
| 235 | } | ||
| 236 | } else if (event->event == IDEVICE_DEVICE_REMOVE) { | ||
| 237 | if (strcmp(udid, event->udid) == 0) { | ||
| 238 | device_connected = 0; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | |||
| 244 | #define WAIT_INTERVAL 200000 | ||
| 245 | #define WAIT_MAX(x) (x * (1000000 / WAIT_INTERVAL)) | ||
| 246 | #define WAIT_FOR(cond, timeout) { int __repeat = WAIT_MAX(timeout); while (!(cond) && __repeat-- > 0) { __usleep(WAIT_INTERVAL); } } | ||
| 247 | |||
| 248 | int main(int argc, char *argv[]) | ||
| 249 | { | ||
| 250 | idevice_t device = NULL; | ||
| 251 | idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; | ||
| 252 | lockdownd_client_t lockdown = NULL; | ||
| 253 | lockdownd_error_t lerr = LOCKDOWN_E_UNKNOWN_ERROR; | ||
| 254 | int res = 0; | ||
| 255 | int i; | ||
| 256 | int op = -1; | ||
| 257 | plist_t val = NULL; | ||
| 258 | |||
| 259 | int c = 0; | ||
| 260 | const struct option longopts[] = { | ||
| 261 | { "debug", no_argument, NULL, 'd' }, | ||
| 262 | { "help", no_argument, NULL, 'h' }, | ||
| 263 | { "udid", required_argument, NULL, 'u' }, | ||
| 264 | { "network", no_argument, NULL, 'n' }, | ||
| 265 | { "version", no_argument, NULL, 'v' }, | ||
| 266 | { NULL, 0, NULL, 0} | ||
| 267 | }; | ||
| 268 | |||
| 269 | #ifndef WIN32 | ||
| 270 | signal(SIGPIPE, SIG_IGN); | ||
| 271 | #endif | ||
| 272 | /* parse cmdline args */ | ||
| 273 | while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { | ||
| 274 | switch (c) { | ||
| 275 | case 'd': | ||
| 276 | idevice_set_debug_level(1); | ||
| 277 | break; | ||
| 278 | case 'u': | ||
| 279 | if (!*optarg) { | ||
| 280 | fprintf(stderr, "ERROR: UDID argument must not be empty!\n"); | ||
| 281 | print_usage(argc, argv, 1); | ||
| 282 | return 2; | ||
| 283 | } | ||
| 284 | udid = optarg; | ||
| 285 | break; | ||
| 286 | case 'n': | ||
| 287 | use_network = 1; | ||
| 288 | break; | ||
| 289 | case 'h': | ||
| 290 | print_usage(argc, argv, 0); | ||
| 291 | return 0; | ||
| 292 | case 'v': | ||
| 293 | printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); | ||
| 294 | return 0; | ||
| 295 | default: | ||
| 296 | print_usage(argc, argv, 1); | ||
| 297 | return 2; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | argc -= optind; | ||
| 301 | argv += optind; | ||
| 302 | |||
| 303 | if (!argv[0]) { | ||
| 304 | fprintf(stderr, "ERROR: Missing command.\n"); | ||
| 305 | print_usage(argc+optind, argv-optind, 1); | ||
| 306 | return 2; | ||
| 307 | } | ||
| 308 | |||
| 309 | i = 0; | ||
| 310 | if (!strcmp(argv[i], "list")) { | ||
| 311 | op = OP_LIST; | ||
| 312 | } | ||
| 313 | else if (!strcmp(argv[i], "enable")) { | ||
| 314 | op = OP_ENABLE; | ||
| 315 | } | ||
| 316 | else if (!strcmp(argv[i], "arm")) { | ||
| 317 | op = OP_ARM; | ||
| 318 | } | ||
| 319 | else if (!strcmp(argv[i], "confirm")) { | ||
| 320 | op = OP_CONFIRM; | ||
| 321 | } | ||
| 322 | else if (!strcmp(argv[i], "reveal")) { | ||
| 323 | op = OP_REVEAL; | ||
| 324 | } | ||
| 325 | |||
| 326 | if ((op == -1) || (op >= NUM_OPS)) { | ||
| 327 | fprintf(stderr, "ERROR: Unsupported command '%s'\n", argv[i]); | ||
| 328 | print_usage(argc+optind, argv-optind, 1); | ||
| 329 | return 2; | ||
| 330 | } | ||
| 331 | |||
| 332 | if (op == OP_LIST) { | ||
| 333 | idevice_info_t *dev_list = NULL; | ||
| 334 | |||
| 335 | if (idevice_get_device_list_extended(&dev_list, &i) < 0) { | ||
| 336 | fprintf(stderr, "ERROR: Unable to retrieve device list!\n"); | ||
| 337 | return -1; | ||
| 338 | } | ||
| 339 | if (i > 0) { | ||
| 340 | printf("%-40s %s\n", "Device", "DeveloperMode"); | ||
| 341 | } | ||
| 342 | for (i = 0; dev_list[i] != NULL; i++) { | ||
| 343 | if (dev_list[i]->conn_type == CONNECTION_USBMUXD && use_network) continue; | ||
| 344 | if (dev_list[i]->conn_type == CONNECTION_NETWORK && !use_network) continue; | ||
| 345 | if (udid && (strcmp(dev_list[i]->udid, udid) != 0)) continue; | ||
| 346 | int mode = get_developer_mode_status(dev_list[i]->udid, use_network); | ||
| 347 | const char *mode_str = "N/A"; | ||
| 348 | if (mode == 1) { | ||
| 349 | mode_str = "enabled"; | ||
| 350 | } else if (mode == 0) { | ||
| 351 | mode_str = "disabled"; | ||
| 352 | } | ||
| 353 | printf("%-40s %s\n", dev_list[i]->udid, mode_str); | ||
| 354 | } | ||
| 355 | idevice_device_list_extended_free(dev_list); | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | idevice_subscription_context_t context = NULL; | ||
| 361 | idevice_events_subscribe(&context, device_event_cb, NULL); | ||
| 362 | |||
| 363 | WAIT_FOR(device_connected, 10); | ||
| 364 | |||
| 365 | ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); | ||
| 366 | if (ret != IDEVICE_E_SUCCESS) { | ||
| 367 | if (udid) { | ||
| 368 | printf("No device found with udid %s.\n", udid); | ||
| 369 | } else { | ||
| 370 | printf("No device found.\n"); | ||
| 371 | } | ||
| 372 | return 1; | ||
| 373 | } | ||
| 374 | |||
| 375 | if (!udid) { | ||
| 376 | idevice_get_udid(device, &udid); | ||
| 377 | } | ||
| 378 | |||
| 379 | if (LOCKDOWN_E_SUCCESS != (lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) { | ||
| 380 | fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", lerr); | ||
| 381 | idevice_free(device); | ||
| 382 | return 1; | ||
| 383 | } | ||
| 384 | |||
| 385 | lerr = lockdownd_get_value(lockdown, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); | ||
| 386 | lockdownd_client_free(lockdown); | ||
| 387 | lockdown = NULL; | ||
| 388 | if (lerr != LOCKDOWN_E_SUCCESS) { | ||
| 389 | fprintf(stderr, "ERROR: Could not get DeveloperModeStatus: %s\nPlease note that this feature is only available on iOS 16+.\n", lockdownd_strerror(lerr)); | ||
| 390 | idevice_free(device); | ||
| 391 | return 1; | ||
| 392 | } | ||
| 393 | |||
| 394 | uint8_t dev_mode_status = 0; | ||
| 395 | plist_get_bool_val(val, &dev_mode_status); | ||
| 396 | |||
| 397 | if ((op == OP_ENABLE || op == OP_ARM) && dev_mode_status) { | ||
| 398 | if (dev_mode_status) { | ||
| 399 | printf("DeveloperMode is already enabled.\n"); | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | res = 0; | ||
| 403 | } else { | ||
| 404 | if (op == OP_ENABLE || op == OP_ARM) { | ||
| 405 | res = amfi_send_action(device, DEV_MODE_ARM); | ||
| 406 | if (res == 0) { | ||
| 407 | if (op == OP_ARM) { | ||
| 408 | printf("%s: Developer Mode armed, device will reboot now.\n", udid); | ||
| 409 | } else { | ||
| 410 | printf("%s: Developer Mode armed, waiting for reboot...\n", udid); | ||
| 411 | |||
| 412 | // waiting for device to disconnect... | ||
| 413 | WAIT_FOR(!device_connected, 20); | ||
| 414 | |||
| 415 | // waiting for device to reconnect... | ||
| 416 | WAIT_FOR(device_connected, 60); | ||
| 417 | |||
| 418 | res = amfi_send_action(device, DEV_MODE_ENABLE); | ||
| 419 | if (res == 0) { | ||
| 420 | printf("%s: Developer Mode successfully enabled.\n", udid); | ||
| 421 | } else { | ||
| 422 | printf("%s: Failed to enable developer mode (%d)\n", udid, res); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } else if (res == 2) { | ||
| 426 | amfi_send_action(device, DEV_MODE_REVEAL); | ||
| 427 | printf("%s: Developer Mode could not be enabled because the device has a passcode set. You have to enable it on the device itself under Settings -> Privacy & Security -> Developer Mode.\n", udid); | ||
| 428 | } else { | ||
| 429 | printf("%s: Failed to arm Developer Mode (%d)\n", udid, res); | ||
| 430 | } | ||
| 431 | } else if (op == OP_CONFIRM) { | ||
| 432 | res = amfi_send_action(device, DEV_MODE_ENABLE); | ||
| 433 | if (res == 0) { | ||
| 434 | printf("%s: Developer Mode successfully enabled.\n", udid); | ||
| 435 | } else { | ||
| 436 | printf("%s: Failed to enable Developer Mode (%d)\n", udid, res); | ||
| 437 | } | ||
| 438 | } else if (op == OP_REVEAL) { | ||
| 439 | res = amfi_send_action(device, DEV_MODE_REVEAL); | ||
| 440 | if (res == 0) { | ||
| 441 | printf("%s: Developer Mode menu revealed successfully.\n", udid); | ||
| 442 | } else { | ||
| 443 | printf("%s: Failed to reveal Developer Mode menu (%d)\n", udid, res); | ||
| 444 | } | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | idevice_free(device); | ||
| 449 | |||
| 450 | return res; | ||
| 451 | } | ||
