diff options
| author | 2022-02-09 04:04:36 +0100 | |
|---|---|---|
| committer | 2022-02-09 04:04:36 +0100 | |
| commit | e41dbc3ddbe30a414e73fa25d9c7c304ffe6989e (patch) | |
| tree | 599c99a2f32bc18f1e9ebc740d0a12d71c49bb10 /tools | |
| parent | ee9104bcb8d494b579e122a2dcc94a2b79d38e4b (diff) | |
| download | libimobiledevice-e41dbc3ddbe30a414e73fa25d9c7c304ffe6989e.tar.gz libimobiledevice-e41dbc3ddbe30a414e73fa25d9c7c304ffe6989e.tar.bz2 | |
Add support for wireless pairing
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/idevicepair.c | 185 |
1 files changed, 179 insertions, 6 deletions
diff --git a/tools/idevicepair.c b/tools/idevicepair.c index 0dcd45f..a2dc944 100644 --- a/tools/idevicepair.c +++ b/tools/idevicepair.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * idevicepair.c | 2 | * idevicepair.c |
| 3 | * Manage pairings with devices and this host | 3 | * Manage pairings with devices and this host |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved. | 5 | * Copyright (c) 2010-2021 Nikias Bassen, All Rights Reserved. |
| 6 | * Copyright (c) 2014 Martin Szulecki, All Rights Reserved. | 6 | * Copyright (c) 2014 Martin Szulecki, All Rights Reserved. |
| 7 | * | 7 | * |
| 8 | * This library is free software; you can redistribute it and/or | 8 | * This library is free software; you can redistribute it and/or |
| @@ -30,16 +30,88 @@ | |||
| 30 | #include <string.h> | 30 | #include <string.h> |
| 31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
| 32 | #include <getopt.h> | 32 | #include <getopt.h> |
| 33 | #ifndef WIN32 | 33 | #include <ctype.h> |
| 34 | #include <unistd.h> | ||
| 35 | #ifdef WIN32 | ||
| 36 | #include <windows.h> | ||
| 37 | #include <conio.h> | ||
| 38 | #else | ||
| 39 | #include <termios.h> | ||
| 34 | #include <signal.h> | 40 | #include <signal.h> |
| 35 | #endif | 41 | #endif |
| 42 | |||
| 36 | #include "common/userpref.h" | 43 | #include "common/userpref.h" |
| 44 | #include <libimobiledevice-glue/utils.h> | ||
| 37 | 45 | ||
| 38 | #include <libimobiledevice/libimobiledevice.h> | 46 | #include <libimobiledevice/libimobiledevice.h> |
| 39 | #include <libimobiledevice/lockdown.h> | 47 | #include <libimobiledevice/lockdown.h> |
| 48 | #include <plist/plist.h> | ||
| 40 | 49 | ||
| 41 | static char *udid = NULL; | 50 | static char *udid = NULL; |
| 42 | 51 | ||
| 52 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 53 | |||
| 54 | #ifdef WIN32 | ||
| 55 | #define BS_CC '\b' | ||
| 56 | #define my_getch getch | ||
| 57 | #else | ||
| 58 | #define BS_CC 0x7f | ||
| 59 | static int my_getch(void) | ||
| 60 | { | ||
| 61 | struct termios oldt, newt; | ||
| 62 | int ch; | ||
| 63 | tcgetattr(STDIN_FILENO, &oldt); | ||
| 64 | newt = oldt; | ||
| 65 | newt.c_lflag &= ~(ICANON | ECHO); | ||
| 66 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); | ||
| 67 | ch = getchar(); | ||
| 68 | tcsetattr(STDIN_FILENO, TCSANOW, &oldt); | ||
| 69 | return ch; | ||
| 70 | } | ||
| 71 | #endif | ||
| 72 | |||
| 73 | static int get_hidden_input(char *buf, int maxlen) | ||
| 74 | { | ||
| 75 | int pwlen = 0; | ||
| 76 | int c; | ||
| 77 | |||
| 78 | while ((c = my_getch())) { | ||
| 79 | if ((c == '\r') || (c == '\n')) { | ||
| 80 | break; | ||
| 81 | } else if (isprint(c)) { | ||
| 82 | if (pwlen < maxlen-1) | ||
| 83 | buf[pwlen++] = c; | ||
| 84 | fputc('*', stderr); | ||
| 85 | } else if (c == BS_CC) { | ||
| 86 | if (pwlen > 0) { | ||
| 87 | fputs("\b \b", stderr); | ||
| 88 | pwlen--; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | buf[pwlen] = 0; | ||
| 93 | return pwlen; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void pairing_cb(lockdownd_cu_pairing_cb_type_t cb_type, void *user_data, void* data_ptr, unsigned int* data_size) | ||
| 97 | { | ||
| 98 | if (cb_type == LOCKDOWN_CU_PAIRING_PIN_REQUESTED) { | ||
| 99 | printf("Enter PIN: "); | ||
| 100 | fflush(stdout); | ||
| 101 | |||
| 102 | *data_size = get_hidden_input((char*)data_ptr, *data_size); | ||
| 103 | |||
| 104 | printf("\n"); | ||
| 105 | } else if (cb_type == LOCKDOWN_CU_PAIRING_DEVICE_INFO) { | ||
| 106 | printf("Device info:\n"); | ||
| 107 | plist_print_to_stream_with_indentation((plist_t)data_ptr, stdout, 2); | ||
| 108 | } else if (cb_type == LOCKDOWN_CU_PAIRING_ERROR) { | ||
| 109 | printf("ERROR: %s\n", (data_ptr) ? (char*)data_ptr : "(unknown)"); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | #endif /* HAVE_WIRELESS_PAIRING */ | ||
| 114 | |||
| 43 | static void print_error_message(lockdownd_error_t err) | 115 | static void print_error_message(lockdownd_error_t err) |
| 44 | { | 116 | { |
| 45 | switch (err) { | 117 | switch (err) { |
| @@ -56,6 +128,16 @@ static void print_error_message(lockdownd_error_t err) | |||
| 56 | case LOCKDOWN_E_USER_DENIED_PAIRING: | 128 | case LOCKDOWN_E_USER_DENIED_PAIRING: |
| 57 | printf("ERROR: Device %s said that the user denied the trust dialog.\n", udid); | 129 | printf("ERROR: Device %s said that the user denied the trust dialog.\n", udid); |
| 58 | break; | 130 | break; |
| 131 | case LOCKDOWN_E_PAIRING_FAILED: | ||
| 132 | printf("ERROR: Pairing with device %s failed.\n", udid); | ||
| 133 | break; | ||
| 134 | case LOCKDOWN_E_GET_PROHIBITED: | ||
| 135 | case LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION: | ||
| 136 | printf("ERROR: Pairing is not possible over this connection.\n"); | ||
| 137 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 138 | printf("To perform a wireless pairing use the -w command line switch. See usage or man page for details.\n"); | ||
| 139 | #endif | ||
| 140 | break; | ||
| 59 | default: | 141 | default: |
| 60 | printf("ERROR: Device %s returned unhandled error code %d\n", udid, err); | 142 | printf("ERROR: Device %s returned unhandled error code %d\n", udid, err); |
| 61 | break; | 143 | break; |
| @@ -81,9 +163,20 @@ static void print_usage(int argc, char **argv) | |||
| 81 | printf("\n"); | 163 | printf("\n"); |
| 82 | printf("The following OPTIONS are accepted:\n"); | 164 | printf("The following OPTIONS are accepted:\n"); |
| 83 | printf(" -u, --udid UDID target specific device by UDID\n"); | 165 | printf(" -u, --udid UDID target specific device by UDID\n"); |
| 166 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 167 | printf(" -w, --wireless perform wireless pairing (see NOTE)\n"); | ||
| 168 | printf(" -n, --network connect to network device (see NOTE)\n"); | ||
| 169 | #endif | ||
| 84 | printf(" -d, --debug enable communication debugging\n"); | 170 | printf(" -d, --debug enable communication debugging\n"); |
| 85 | printf(" -h, --help prints usage information\n"); | 171 | printf(" -h, --help prints usage information\n"); |
| 86 | printf(" -v, --version prints version information\n"); | 172 | printf(" -v, --version prints version information\n"); |
| 173 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 174 | printf("\n"); | ||
| 175 | printf("NOTE: Pairing over network (wireless pairing) is only supported by Apple TV\n"); | ||
| 176 | printf("devices. To perform a wireless pairing, you need to use the -w command line\n"); | ||
| 177 | printf("switch. Make sure to put the device into pairing mode first by opening\n"); | ||
| 178 | printf("Settings > Remotes and Devices > Remote App and Devices.\n"); | ||
| 179 | #endif | ||
| 87 | printf("\n"); | 180 | printf("\n"); |
| 88 | printf("Homepage: <" PACKAGE_URL ">\n"); | 181 | printf("Homepage: <" PACKAGE_URL ">\n"); |
| 89 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); | 182 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); |
| @@ -95,10 +188,20 @@ int main(int argc, char **argv) | |||
| 95 | static struct option longopts[] = { | 188 | static struct option longopts[] = { |
| 96 | { "help", no_argument, NULL, 'h' }, | 189 | { "help", no_argument, NULL, 'h' }, |
| 97 | { "udid", required_argument, NULL, 'u' }, | 190 | { "udid", required_argument, NULL, 'u' }, |
| 191 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 192 | { "wireless", no_argument, NULL, 'w' }, | ||
| 193 | { "network", no_argument, NULL, 'n' }, | ||
| 194 | { "hostinfo", required_argument, NULL, 1 }, | ||
| 195 | #endif | ||
| 98 | { "debug", no_argument, NULL, 'd' }, | 196 | { "debug", no_argument, NULL, 'd' }, |
| 99 | { "version", no_argument, NULL, 'v' }, | 197 | { "version", no_argument, NULL, 'v' }, |
| 100 | { NULL, 0, NULL, 0} | 198 | { NULL, 0, NULL, 0} |
| 101 | }; | 199 | }; |
| 200 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 201 | #define SHORT_OPTIONS "hu:wndv" | ||
| 202 | #else | ||
| 203 | #define SHORT_OPTIONS "hu:dv" | ||
| 204 | #endif | ||
| 102 | lockdownd_client_t client = NULL; | 205 | lockdownd_client_t client = NULL; |
| 103 | idevice_t device = NULL; | 206 | idevice_t device = NULL; |
| 104 | idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; | 207 | idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; |
| @@ -106,13 +209,18 @@ int main(int argc, char **argv) | |||
| 106 | int result; | 209 | int result; |
| 107 | 210 | ||
| 108 | char *type = NULL; | 211 | char *type = NULL; |
| 212 | int use_network = 0; | ||
| 213 | int wireless_pairing = 0; | ||
| 214 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 215 | plist_t host_info_plist = NULL; | ||
| 216 | #endif | ||
| 109 | char *cmd; | 217 | char *cmd; |
| 110 | typedef enum { | 218 | typedef enum { |
| 111 | OP_NONE = 0, OP_PAIR, OP_VALIDATE, OP_UNPAIR, OP_LIST, OP_HOSTID, OP_SYSTEMBUID | 219 | OP_NONE = 0, OP_PAIR, OP_VALIDATE, OP_UNPAIR, OP_LIST, OP_HOSTID, OP_SYSTEMBUID |
| 112 | } op_t; | 220 | } op_t; |
| 113 | op_t op = OP_NONE; | 221 | op_t op = OP_NONE; |
| 114 | 222 | ||
| 115 | while ((c = getopt_long(argc, argv, "hu:dv", longopts, NULL)) != -1) { | 223 | while ((c = getopt_long(argc, argv, SHORT_OPTIONS, longopts, NULL)) != -1) { |
| 116 | switch (c) { | 224 | switch (c) { |
| 117 | case 'h': | 225 | case 'h': |
| 118 | print_usage(argc, argv); | 226 | print_usage(argc, argv); |
| @@ -127,6 +235,43 @@ int main(int argc, char **argv) | |||
| 127 | free(udid); | 235 | free(udid); |
| 128 | udid = strdup(optarg); | 236 | udid = strdup(optarg); |
| 129 | break; | 237 | break; |
| 238 | #ifdef HAVE_WIRELESS_PAIRING | ||
| 239 | case 'w': | ||
| 240 | wireless_pairing = 1; | ||
| 241 | break; | ||
| 242 | case 'n': | ||
| 243 | use_network = 1; | ||
| 244 | break; | ||
| 245 | case 1: | ||
| 246 | if (!*optarg) { | ||
| 247 | fprintf(stderr, "ERROR: --hostinfo argument must not be empty!\n"); | ||
| 248 | result = EXIT_FAILURE; | ||
| 249 | goto leave; | ||
| 250 | } | ||
| 251 | if (*optarg == '@') { | ||
| 252 | plist_read_from_filename(&host_info_plist, optarg+1); | ||
| 253 | if (!host_info_plist) { | ||
| 254 | fprintf(stderr, "ERROR: Could not read from file '%s'\n", optarg+1); | ||
| 255 | result = EXIT_FAILURE; | ||
| 256 | goto leave; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | #ifdef HAVE_PLIST_JSON | ||
| 260 | else if (*optarg == '{') { | ||
| 261 | if (plist_from_json(optarg, strlen(optarg), &host_info_plist) != PLIST_ERR_SUCCESS) { | ||
| 262 | fprintf(stderr, "ERROR: --hostinfo argument not valid. Make sure it is a JSON dictionary.\n"); | ||
| 263 | result = EXIT_FAILURE; | ||
| 264 | goto leave; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | #endif | ||
| 268 | else { | ||
| 269 | fprintf(stderr, "ERROR: --hostinfo argument not valid. To specify a path prefix with '@'\n"); | ||
| 270 | result = EXIT_FAILURE; | ||
| 271 | goto leave; | ||
| 272 | } | ||
| 273 | break; | ||
| 274 | #endif | ||
| 130 | case 'd': | 275 | case 'd': |
| 131 | idevice_set_debug_level(1); | 276 | idevice_set_debug_level(1); |
| 132 | break; | 277 | break; |
| @@ -152,6 +297,13 @@ int main(int argc, char **argv) | |||
| 152 | goto leave; | 297 | goto leave; |
| 153 | } | 298 | } |
| 154 | 299 | ||
| 300 | if (wireless_pairing && use_network) { | ||
| 301 | printf("ERROR: You cannot use -w and -n together.\n"); | ||
| 302 | print_usage(argc, argv); | ||
| 303 | result = EXIT_FAILURE; | ||
| 304 | goto leave; | ||
| 305 | } | ||
| 306 | |||
| 155 | cmd = (argv+optind)[0]; | 307 | cmd = (argv+optind)[0]; |
| 156 | 308 | ||
| 157 | if (!strcmp(cmd, "pair")) { | 309 | if (!strcmp(cmd, "pair")) { |
| @@ -169,7 +321,18 @@ int main(int argc, char **argv) | |||
| 169 | } else { | 321 | } else { |
| 170 | printf("ERROR: Invalid command '%s' specified\n", cmd); | 322 | printf("ERROR: Invalid command '%s' specified\n", cmd); |
| 171 | print_usage(argc, argv); | 323 | print_usage(argc, argv); |
| 172 | exit(EXIT_FAILURE); | 324 | result = EXIT_FAILURE; |
| 325 | goto leave; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (wireless_pairing) { | ||
| 329 | if (op == OP_VALIDATE || op == OP_UNPAIR) { | ||
| 330 | printf("ERROR: Command '%s' is not supported with -w\n", cmd); | ||
| 331 | print_usage(argc, argv); | ||
| 332 | result = EXIT_FAILURE; | ||
| 333 | goto leave; | ||
| 334 | } | ||
| 335 | use_network = 1; | ||
| 173 | } | 336 | } |
| 174 | 337 | ||
| 175 | if (op == OP_SYSTEMBUID) { | 338 | if (op == OP_SYSTEMBUID) { |
| @@ -198,7 +361,7 @@ int main(int argc, char **argv) | |||
| 198 | goto leave; | 361 | goto leave; |
| 199 | } | 362 | } |
| 200 | 363 | ||
| 201 | ret = idevice_new(&device, udid); | 364 | ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); |
| 202 | if (ret != IDEVICE_E_SUCCESS) { | 365 | if (ret != IDEVICE_E_SUCCESS) { |
| 203 | if (udid) { | 366 | if (udid) { |
| 204 | printf("No device found with udid %s.\n", udid); | 367 | printf("No device found with udid %s.\n", udid); |
| @@ -257,7 +420,17 @@ int main(int argc, char **argv) | |||
| 257 | switch(op) { | 420 | switch(op) { |
| 258 | default: | 421 | default: |
| 259 | case OP_PAIR: | 422 | case OP_PAIR: |
| 260 | lerr = lockdownd_pair(client, NULL); | 423 | #ifdef HAVE_WIRELESS_PAIRING |
| 424 | if (wireless_pairing) { | ||
| 425 | lerr = lockdownd_cu_pairing_create(client, pairing_cb, NULL, host_info_plist, NULL); | ||
| 426 | if (lerr == LOCKDOWN_E_SUCCESS) { | ||
| 427 | lerr = lockdownd_pair_cu(client); | ||
| 428 | } | ||
| 429 | } else | ||
| 430 | #endif | ||
| 431 | { | ||
| 432 | lerr = lockdownd_pair(client, NULL); | ||
| 433 | } | ||
| 261 | if (lerr == LOCKDOWN_E_SUCCESS) { | 434 | if (lerr == LOCKDOWN_E_SUCCESS) { |
| 262 | printf("SUCCESS: Paired with device %s\n", udid); | 435 | printf("SUCCESS: Paired with device %s\n", udid); |
| 263 | } else { | 436 | } else { |
