hotboxxgenn commited on
Commit
3db5480
·
verified ·
1 Parent(s): 712619f

Upload 181 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. AUTHORS +21 -0
  2. COPYING +340 -0
  3. COPYING.LESSER +502 -0
  4. Makefile.am +21 -0
  5. NEWS +602 -0
  6. README.md +201 -10
  7. ac_pkg_cython.m4 +67 -0
  8. afc.c +1314 -0
  9. afc.h +110 -0
  10. afc.pxi +337 -0
  11. afcclient.c +1630 -0
  12. as-compiler-flag.m4 +62 -0
  13. asprintf.h +36 -0
  14. asr.c +461 -0
  15. asr.h +59 -0
  16. autogen.sh +26 -0
  17. ax_pthread.m4 +522 -0
  18. ax_python_devel.m4 +468 -0
  19. bt_packet_logger.c +231 -0
  20. bt_packet_logger.h +37 -0
  21. common.c +647 -0
  22. common.h +173 -0
  23. companion_proxy.c +380 -0
  24. companion_proxy.h +35 -0
  25. configure.ac +356 -0
  26. cython_python.m4 +7 -0
  27. debug.c +174 -0
  28. debug.h +53 -0
  29. debugserver.c +657 -0
  30. debugserver.h +44 -0
  31. debugserver.pxi +246 -0
  32. device_link_service.c +474 -0
  33. device_link_service.h +57 -0
  34. dfu.c +470 -0
  35. dfu.h +58 -0
  36. diagnostics_relay.c +467 -0
  37. diagnostics_relay.h +33 -0
  38. diagnostics_relay.pxi +128 -0
  39. download.c +156 -0
  40. download.h +38 -0
  41. doxygen.cfg.in +0 -0
  42. endianness.h +123 -0
  43. fdr.c +629 -0
  44. fdr.h +54 -0
  45. file_relay.c +165 -0
  46. file_relay.h +33 -0
  47. file_relay.pxi +68 -0
  48. fls.c +338 -0
  49. fls.h +85 -0
  50. ftab.c +197 -0
AUTHORS ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Bastien Nocera
2
+ Bryan Forbes
3
+ Christophe Fergeau
4
+ Geoff Paul
5
+ Ingmar Vanhassel
6
+ John Maguire
7
+ Jonathan Beck
8
+ Joshua Hill
9
+ Julien Lavergne
10
+ Martin Aumueller
11
+ Martin Szulecki
12
+ Marty Rosenberg
13
+ Matt Colyer
14
+ Nikias Bassen
15
+ Patrick Walton
16
+ Paul Sladen
17
+ Peter Hoepfner
18
+ Petr Uzel
19
+ Todd Zullinger
20
+ Zach C
21
+ Zoltan Balaton
COPYING ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ <signature of Ty Coon>, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
340
+
COPYING.LESSER ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 2.1, February 1999
3
+
4
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ [This is the first released version of the Lesser GPL. It also counts
10
+ as the successor of the GNU Library Public License, version 2, hence
11
+ the version number 2.1.]
12
+
13
+ Preamble
14
+
15
+ The licenses for most software are designed to take away your
16
+ freedom to share and change it. By contrast, the GNU General Public
17
+ Licenses are intended to guarantee your freedom to share and change
18
+ free software--to make sure the software is free for all its users.
19
+
20
+ This license, the Lesser General Public License, applies to some
21
+ specially designated software packages--typically libraries--of the
22
+ Free Software Foundation and other authors who decide to use it. You
23
+ can use it too, but we suggest you first think carefully about whether
24
+ this license or the ordinary General Public License is the better
25
+ strategy to use in any particular case, based on the explanations below.
26
+
27
+ When we speak of free software, we are referring to freedom of use,
28
+ not price. Our General Public Licenses are designed to make sure that
29
+ you have the freedom to distribute copies of free software (and charge
30
+ for this service if you wish); that you receive source code or can get
31
+ it if you want it; that you can change the software and use pieces of
32
+ it in new free programs; and that you are informed that you can do
33
+ these things.
34
+
35
+ To protect your rights, we need to make restrictions that forbid
36
+ distributors to deny you these rights or to ask you to surrender these
37
+ rights. These restrictions translate to certain responsibilities for
38
+ you if you distribute copies of the library or if you modify it.
39
+
40
+ For example, if you distribute copies of the library, whether gratis
41
+ or for a fee, you must give the recipients all the rights that we gave
42
+ you. You must make sure that they, too, receive or can get the source
43
+ code. If you link other code with the library, you must provide
44
+ complete object files to the recipients, so that they can relink them
45
+ with the library after making changes to the library and recompiling
46
+ it. And you must show them these terms so they know their rights.
47
+
48
+ We protect your rights with a two-step method: (1) we copyright the
49
+ library, and (2) we offer you this license, which gives you legal
50
+ permission to copy, distribute and/or modify the library.
51
+
52
+ To protect each distributor, we want to make it very clear that
53
+ there is no warranty for the free library. Also, if the library is
54
+ modified by someone else and passed on, the recipients should know
55
+ that what they have is not the original version, so that the original
56
+ author's reputation will not be affected by problems that might be
57
+ introduced by others.
58
+
59
+ Finally, software patents pose a constant threat to the existence of
60
+ any free program. We wish to make sure that a company cannot
61
+ effectively restrict the users of a free program by obtaining a
62
+ restrictive license from a patent holder. Therefore, we insist that
63
+ any patent license obtained for a version of the library must be
64
+ consistent with the full freedom of use specified in this license.
65
+
66
+ Most GNU software, including some libraries, is covered by the
67
+ ordinary GNU General Public License. This license, the GNU Lesser
68
+ General Public License, applies to certain designated libraries, and
69
+ is quite different from the ordinary General Public License. We use
70
+ this license for certain libraries in order to permit linking those
71
+ libraries into non-free programs.
72
+
73
+ When a program is linked with a library, whether statically or using
74
+ a shared library, the combination of the two is legally speaking a
75
+ combined work, a derivative of the original library. The ordinary
76
+ General Public License therefore permits such linking only if the
77
+ entire combination fits its criteria of freedom. The Lesser General
78
+ Public License permits more lax criteria for linking other code with
79
+ the library.
80
+
81
+ We call this license the "Lesser" General Public License because it
82
+ does Less to protect the user's freedom than the ordinary General
83
+ Public License. It also provides other free software developers Less
84
+ of an advantage over competing non-free programs. These disadvantages
85
+ are the reason we use the ordinary General Public License for many
86
+ libraries. However, the Lesser license provides advantages in certain
87
+ special circumstances.
88
+
89
+ For example, on rare occasions, there may be a special need to
90
+ encourage the widest possible use of a certain library, so that it becomes
91
+ a de-facto standard. To achieve this, non-free programs must be
92
+ allowed to use the library. A more frequent case is that a free
93
+ library does the same job as widely used non-free libraries. In this
94
+ case, there is little to gain by limiting the free library to free
95
+ software only, so we use the Lesser General Public License.
96
+
97
+ In other cases, permission to use a particular library in non-free
98
+ programs enables a greater number of people to use a large body of
99
+ free software. For example, permission to use the GNU C Library in
100
+ non-free programs enables many more people to use the whole GNU
101
+ operating system, as well as its variant, the GNU/Linux operating
102
+ system.
103
+
104
+ Although the Lesser General Public License is Less protective of the
105
+ users' freedom, it does ensure that the user of a program that is
106
+ linked with the Library has the freedom and the wherewithal to run
107
+ that program using a modified version of the Library.
108
+
109
+ The precise terms and conditions for copying, distribution and
110
+ modification follow. Pay close attention to the difference between a
111
+ "work based on the library" and a "work that uses the library". The
112
+ former contains code derived from the library, whereas the latter must
113
+ be combined with the library in order to run.
114
+
115
+ GNU LESSER GENERAL PUBLIC LICENSE
116
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
+
118
+ 0. This License Agreement applies to any software library or other
119
+ program which contains a notice placed by the copyright holder or
120
+ other authorized party saying it may be distributed under the terms of
121
+ this Lesser General Public License (also called "this License").
122
+ Each licensee is addressed as "you".
123
+
124
+ A "library" means a collection of software functions and/or data
125
+ prepared so as to be conveniently linked with application programs
126
+ (which use some of those functions and data) to form executables.
127
+
128
+ The "Library", below, refers to any such software library or work
129
+ which has been distributed under these terms. A "work based on the
130
+ Library" means either the Library or any derivative work under
131
+ copyright law: that is to say, a work containing the Library or a
132
+ portion of it, either verbatim or with modifications and/or translated
133
+ straightforwardly into another language. (Hereinafter, translation is
134
+ included without limitation in the term "modification".)
135
+
136
+ "Source code" for a work means the preferred form of the work for
137
+ making modifications to it. For a library, complete source code means
138
+ all the source code for all modules it contains, plus any associated
139
+ interface definition files, plus the scripts used to control compilation
140
+ and installation of the library.
141
+
142
+ Activities other than copying, distribution and modification are not
143
+ covered by this License; they are outside its scope. The act of
144
+ running a program using the Library is not restricted, and output from
145
+ such a program is covered only if its contents constitute a work based
146
+ on the Library (independent of the use of the Library in a tool for
147
+ writing it). Whether that is true depends on what the Library does
148
+ and what the program that uses the Library does.
149
+
150
+ 1. You may copy and distribute verbatim copies of the Library's
151
+ complete source code as you receive it, in any medium, provided that
152
+ you conspicuously and appropriately publish on each copy an
153
+ appropriate copyright notice and disclaimer of warranty; keep intact
154
+ all the notices that refer to this License and to the absence of any
155
+ warranty; and distribute a copy of this License along with the
156
+ Library.
157
+
158
+ You may charge a fee for the physical act of transferring a copy,
159
+ and you may at your option offer warranty protection in exchange for a
160
+ fee.
161
+
162
+ 2. You may modify your copy or copies of the Library or any portion
163
+ of it, thus forming a work based on the Library, and copy and
164
+ distribute such modifications or work under the terms of Section 1
165
+ above, provided that you also meet all of these conditions:
166
+
167
+ a) The modified work must itself be a software library.
168
+
169
+ b) You must cause the files modified to carry prominent notices
170
+ stating that you changed the files and the date of any change.
171
+
172
+ c) You must cause the whole of the work to be licensed at no
173
+ charge to all third parties under the terms of this License.
174
+
175
+ d) If a facility in the modified Library refers to a function or a
176
+ table of data to be supplied by an application program that uses
177
+ the facility, other than as an argument passed when the facility
178
+ is invoked, then you must make a good faith effort to ensure that,
179
+ in the event an application does not supply such function or
180
+ table, the facility still operates, and performs whatever part of
181
+ its purpose remains meaningful.
182
+
183
+ (For example, a function in a library to compute square roots has
184
+ a purpose that is entirely well-defined independent of the
185
+ application. Therefore, Subsection 2d requires that any
186
+ application-supplied function or table used by this function must
187
+ be optional: if the application does not supply it, the square
188
+ root function must still compute square roots.)
189
+
190
+ These requirements apply to the modified work as a whole. If
191
+ identifiable sections of that work are not derived from the Library,
192
+ and can be reasonably considered independent and separate works in
193
+ themselves, then this License, and its terms, do not apply to those
194
+ sections when you distribute them as separate works. But when you
195
+ distribute the same sections as part of a whole which is a work based
196
+ on the Library, the distribution of the whole must be on the terms of
197
+ this License, whose permissions for other licensees extend to the
198
+ entire whole, and thus to each and every part regardless of who wrote
199
+ it.
200
+
201
+ Thus, it is not the intent of this section to claim rights or contest
202
+ your rights to work written entirely by you; rather, the intent is to
203
+ exercise the right to control the distribution of derivative or
204
+ collective works based on the Library.
205
+
206
+ In addition, mere aggregation of another work not based on the Library
207
+ with the Library (or with a work based on the Library) on a volume of
208
+ a storage or distribution medium does not bring the other work under
209
+ the scope of this License.
210
+
211
+ 3. You may opt to apply the terms of the ordinary GNU General Public
212
+ License instead of this License to a given copy of the Library. To do
213
+ this, you must alter all the notices that refer to this License, so
214
+ that they refer to the ordinary GNU General Public License, version 2,
215
+ instead of to this License. (If a newer version than version 2 of the
216
+ ordinary GNU General Public License has appeared, then you can specify
217
+ that version instead if you wish.) Do not make any other change in
218
+ these notices.
219
+
220
+ Once this change is made in a given copy, it is irreversible for
221
+ that copy, so the ordinary GNU General Public License applies to all
222
+ subsequent copies and derivative works made from that copy.
223
+
224
+ This option is useful when you wish to copy part of the code of
225
+ the Library into a program that is not a library.
226
+
227
+ 4. You may copy and distribute the Library (or a portion or
228
+ derivative of it, under Section 2) in object code or executable form
229
+ under the terms of Sections 1 and 2 above provided that you accompany
230
+ it with the complete corresponding machine-readable source code, which
231
+ must be distributed under the terms of Sections 1 and 2 above on a
232
+ medium customarily used for software interchange.
233
+
234
+ If distribution of object code is made by offering access to copy
235
+ from a designated place, then offering equivalent access to copy the
236
+ source code from the same place satisfies the requirement to
237
+ distribute the source code, even though third parties are not
238
+ compelled to copy the source along with the object code.
239
+
240
+ 5. A program that contains no derivative of any portion of the
241
+ Library, but is designed to work with the Library by being compiled or
242
+ linked with it, is called a "work that uses the Library". Such a
243
+ work, in isolation, is not a derivative work of the Library, and
244
+ therefore falls outside the scope of this License.
245
+
246
+ However, linking a "work that uses the Library" with the Library
247
+ creates an executable that is a derivative of the Library (because it
248
+ contains portions of the Library), rather than a "work that uses the
249
+ library". The executable is therefore covered by this License.
250
+ Section 6 states terms for distribution of such executables.
251
+
252
+ When a "work that uses the Library" uses material from a header file
253
+ that is part of the Library, the object code for the work may be a
254
+ derivative work of the Library even though the source code is not.
255
+ Whether this is true is especially significant if the work can be
256
+ linked without the Library, or if the work is itself a library. The
257
+ threshold for this to be true is not precisely defined by law.
258
+
259
+ If such an object file uses only numerical parameters, data
260
+ structure layouts and accessors, and small macros and small inline
261
+ functions (ten lines or less in length), then the use of the object
262
+ file is unrestricted, regardless of whether it is legally a derivative
263
+ work. (Executables containing this object code plus portions of the
264
+ Library will still fall under Section 6.)
265
+
266
+ Otherwise, if the work is a derivative of the Library, you may
267
+ distribute the object code for the work under the terms of Section 6.
268
+ Any executables containing that work also fall under Section 6,
269
+ whether or not they are linked directly with the Library itself.
270
+
271
+ 6. As an exception to the Sections above, you may also combine or
272
+ link a "work that uses the Library" with the Library to produce a
273
+ work containing portions of the Library, and distribute that work
274
+ under terms of your choice, provided that the terms permit
275
+ modification of the work for the customer's own use and reverse
276
+ engineering for debugging such modifications.
277
+
278
+ You must give prominent notice with each copy of the work that the
279
+ Library is used in it and that the Library and its use are covered by
280
+ this License. You must supply a copy of this License. If the work
281
+ during execution displays copyright notices, you must include the
282
+ copyright notice for the Library among them, as well as a reference
283
+ directing the user to the copy of this License. Also, you must do one
284
+ of these things:
285
+
286
+ a) Accompany the work with the complete corresponding
287
+ machine-readable source code for the Library including whatever
288
+ changes were used in the work (which must be distributed under
289
+ Sections 1 and 2 above); and, if the work is an executable linked
290
+ with the Library, with the complete machine-readable "work that
291
+ uses the Library", as object code and/or source code, so that the
292
+ user can modify the Library and then relink to produce a modified
293
+ executable containing the modified Library. (It is understood
294
+ that the user who changes the contents of definitions files in the
295
+ Library will not necessarily be able to recompile the application
296
+ to use the modified definitions.)
297
+
298
+ b) Use a suitable shared library mechanism for linking with the
299
+ Library. A suitable mechanism is one that (1) uses at run time a
300
+ copy of the library already present on the user's computer system,
301
+ rather than copying library functions into the executable, and (2)
302
+ will operate properly with a modified version of the library, if
303
+ the user installs one, as long as the modified version is
304
+ interface-compatible with the version that the work was made with.
305
+
306
+ c) Accompany the work with a written offer, valid for at
307
+ least three years, to give the same user the materials
308
+ specified in Subsection 6a, above, for a charge no more
309
+ than the cost of performing this distribution.
310
+
311
+ d) If distribution of the work is made by offering access to copy
312
+ from a designated place, offer equivalent access to copy the above
313
+ specified materials from the same place.
314
+
315
+ e) Verify that the user has already received a copy of these
316
+ materials or that you have already sent this user a copy.
317
+
318
+ For an executable, the required form of the "work that uses the
319
+ Library" must include any data and utility programs needed for
320
+ reproducing the executable from it. However, as a special exception,
321
+ the materials to be distributed need not include anything that is
322
+ normally distributed (in either source or binary form) with the major
323
+ components (compiler, kernel, and so on) of the operating system on
324
+ which the executable runs, unless that component itself accompanies
325
+ the executable.
326
+
327
+ It may happen that this requirement contradicts the license
328
+ restrictions of other proprietary libraries that do not normally
329
+ accompany the operating system. Such a contradiction means you cannot
330
+ use both them and the Library together in an executable that you
331
+ distribute.
332
+
333
+ 7. You may place library facilities that are a work based on the
334
+ Library side-by-side in a single library together with other library
335
+ facilities not covered by this License, and distribute such a combined
336
+ library, provided that the separate distribution of the work based on
337
+ the Library and of the other library facilities is otherwise
338
+ permitted, and provided that you do these two things:
339
+
340
+ a) Accompany the combined library with a copy of the same work
341
+ based on the Library, uncombined with any other library
342
+ facilities. This must be distributed under the terms of the
343
+ Sections above.
344
+
345
+ b) Give prominent notice with the combined library of the fact
346
+ that part of it is a work based on the Library, and explaining
347
+ where to find the accompanying uncombined form of the same work.
348
+
349
+ 8. You may not copy, modify, sublicense, link with, or distribute
350
+ the Library except as expressly provided under this License. Any
351
+ attempt otherwise to copy, modify, sublicense, link with, or
352
+ distribute the Library is void, and will automatically terminate your
353
+ rights under this License. However, parties who have received copies,
354
+ or rights, from you under this License will not have their licenses
355
+ terminated so long as such parties remain in full compliance.
356
+
357
+ 9. You are not required to accept this License, since you have not
358
+ signed it. However, nothing else grants you permission to modify or
359
+ distribute the Library or its derivative works. These actions are
360
+ prohibited by law if you do not accept this License. Therefore, by
361
+ modifying or distributing the Library (or any work based on the
362
+ Library), you indicate your acceptance of this License to do so, and
363
+ all its terms and conditions for copying, distributing or modifying
364
+ the Library or works based on it.
365
+
366
+ 10. Each time you redistribute the Library (or any work based on the
367
+ Library), the recipient automatically receives a license from the
368
+ original licensor to copy, distribute, link with or modify the Library
369
+ subject to these terms and conditions. You may not impose any further
370
+ restrictions on the recipients' exercise of the rights granted herein.
371
+ You are not responsible for enforcing compliance by third parties with
372
+ this License.
373
+
374
+ 11. If, as a consequence of a court judgment or allegation of patent
375
+ infringement or for any other reason (not limited to patent issues),
376
+ conditions are imposed on you (whether by court order, agreement or
377
+ otherwise) that contradict the conditions of this License, they do not
378
+ excuse you from the conditions of this License. If you cannot
379
+ distribute so as to satisfy simultaneously your obligations under this
380
+ License and any other pertinent obligations, then as a consequence you
381
+ may not distribute the Library at all. For example, if a patent
382
+ license would not permit royalty-free redistribution of the Library by
383
+ all those who receive copies directly or indirectly through you, then
384
+ the only way you could satisfy both it and this License would be to
385
+ refrain entirely from distribution of the Library.
386
+
387
+ If any portion of this section is held invalid or unenforceable under any
388
+ particular circumstance, the balance of the section is intended to apply,
389
+ and the section as a whole is intended to apply in other circumstances.
390
+
391
+ It is not the purpose of this section to induce you to infringe any
392
+ patents or other property right claims or to contest validity of any
393
+ such claims; this section has the sole purpose of protecting the
394
+ integrity of the free software distribution system which is
395
+ implemented by public license practices. Many people have made
396
+ generous contributions to the wide range of software distributed
397
+ through that system in reliance on consistent application of that
398
+ system; it is up to the author/donor to decide if he or she is willing
399
+ to distribute software through any other system and a licensee cannot
400
+ impose that choice.
401
+
402
+ This section is intended to make thoroughly clear what is believed to
403
+ be a consequence of the rest of this License.
404
+
405
+ 12. If the distribution and/or use of the Library is restricted in
406
+ certain countries either by patents or by copyrighted interfaces, the
407
+ original copyright holder who places the Library under this License may add
408
+ an explicit geographical distribution limitation excluding those countries,
409
+ so that distribution is permitted only in or among countries not thus
410
+ excluded. In such case, this License incorporates the limitation as if
411
+ written in the body of this License.
412
+
413
+ 13. The Free Software Foundation may publish revised and/or new
414
+ versions of the Lesser General Public License from time to time.
415
+ Such new versions will be similar in spirit to the present version,
416
+ but may differ in detail to address new problems or concerns.
417
+
418
+ Each version is given a distinguishing version number. If the Library
419
+ specifies a version number of this License which applies to it and
420
+ "any later version", you have the option of following the terms and
421
+ conditions either of that version or of any later version published by
422
+ the Free Software Foundation. If the Library does not specify a
423
+ license version number, you may choose any version ever published by
424
+ the Free Software Foundation.
425
+
426
+ 14. If you wish to incorporate parts of the Library into other free
427
+ programs whose distribution conditions are incompatible with these,
428
+ write to the author to ask for permission. For software which is
429
+ copyrighted by the Free Software Foundation, write to the Free
430
+ Software Foundation; we sometimes make exceptions for this. Our
431
+ decision will be guided by the two goals of preserving the free status
432
+ of all derivatives of our free software and of promoting the sharing
433
+ and reuse of software generally.
434
+
435
+ NO WARRANTY
436
+
437
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438
+ WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440
+ OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444
+ LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445
+ THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
+
447
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449
+ AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456
+ DAMAGES.
457
+
458
+ END OF TERMS AND CONDITIONS
459
+
460
+ How to Apply These Terms to Your New Libraries
461
+
462
+ If you develop a new library, and you want it to be of the greatest
463
+ possible use to the public, we recommend making it free software that
464
+ everyone can redistribute and change. You can do so by permitting
465
+ redistribution under these terms (or, alternatively, under the terms of the
466
+ ordinary General Public License).
467
+
468
+ To apply these terms, attach the following notices to the library. It is
469
+ safest to attach them to the start of each source file to most effectively
470
+ convey the exclusion of warranty; and each file should have at least the
471
+ "copyright" line and a pointer to where the full notice is found.
472
+
473
+ <one line to give the library's name and a brief idea of what it does.>
474
+ Copyright (C) <year> <name of author>
475
+
476
+ This library is free software; you can redistribute it and/or
477
+ modify it under the terms of the GNU Lesser General Public
478
+ License as published by the Free Software Foundation; either
479
+ version 2.1 of the License, or (at your option) any later version.
480
+
481
+ This library is distributed in the hope that it will be useful,
482
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
483
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484
+ Lesser General Public License for more details.
485
+
486
+ You should have received a copy of the GNU Lesser General Public
487
+ License along with this library; if not, write to the Free Software
488
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489
+
490
+ Also add information on how to contact you by electronic and paper mail.
491
+
492
+ You should also get your employer (if you work as a programmer) or your
493
+ school, if any, to sign a "copyright disclaimer" for the library, if
494
+ necessary. Here is a sample; alter the names:
495
+
496
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
497
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
+
499
+ <signature of Ty Coon>, 1 April 1990
500
+ Ty Coon, President of Vice
501
+
502
+ That's all there is to it!
Makefile.am ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ AUTOMAKE_OPTIONS = foreign
2
+ ACLOCAL_AMFLAGS = -I m4
3
+ SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs
4
+
5
+ EXTRA_DIST = \
6
+ README.md \
7
+ git-version-gen
8
+
9
+ dist-hook:
10
+ @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi
11
+ echo $(VERSION) > $(distdir)/.tarball-version
12
+
13
+ docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h $(top_srcdir)/include/libimobiledevice/*.h
14
+ rm -rf docs/html
15
+ doxygen doxygen.cfg
16
+
17
+ docs: doxygen.cfg docs/html
18
+
19
+ indent:
20
+ indent -kr -ut -ts4 -l120 src/*.c src/*.h
21
+
NEWS ADDED
@@ -0,0 +1,602 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Version 1.4.0
2
+ ~~~~~~~~~~~~~
3
+
4
+ * Development release
5
+ - From now on, releases will be made more frequently
6
+ * Changes:
7
+ - Add support for MbedTLS
8
+ - Add Reverse Proxy implementation
9
+ - Add support for wireless pairing (AppleTV)
10
+ - Embed 3rd party libraries for ed25519 and SRP6a
11
+ - Fixes in idevicedebug
12
+ - idevicecrashreport: Allow filtering crash reports by filename
13
+ - Add idevicedevmodectl tool
14
+ - Fixes for idevicebackup2
15
+ - Add property_list_client_get_service_client() and service_get_connection() functions
16
+ - Add idevicebtlogger
17
+ - Add new idevice_events_subscribe/unsubscribe API
18
+ - Move LIBIMOBILEDEVICE_API to public headers
19
+ - Add afc_strerror function
20
+ - Add libimobiledevice_version() function
21
+ - Use libimobiledevice-glue's SHA1 implementation
22
+ - Add support for iOS 17+ Personalized Developer Disk image mounting
23
+ - Fix compilation on MSVC
24
+ - Add idevice_strerror() to interface
25
+ - Add new idevice_get_device_version() to interface
26
+ - Add os_trace_relay service implementation
27
+ - Fixes for idevicesyslog
28
+ - afc: Add afc_get_file_info_plist and afc_get_device_info_plist functions
29
+ ... and several other internal changes
30
+
31
+
32
+ Version 1.3.0
33
+ ~~~~~~~~~~~~~
34
+
35
+ * Development release "Let's get the party started."
36
+ * Changes:
37
+ - Fix Python 3 support
38
+ - Add more lockdown error codes
39
+ - Add new lockdownd_pair_with_options() function
40
+ - Fix GnuTLS support with iOS 10
41
+ - Make sure sockets only listen locally due to security reasons
42
+ - Plug various memory leaks
43
+ - Fix SSL version negotiation for newer versions of OpenSSL
44
+ - Optimize lockdown pair record handling
45
+ - Return proper error code when a lockdown pair record is missing
46
+ - Fix building with MingGW
47
+ - Store application information in Info.plist using idevicebackup2
48
+ - Fix application backup handling to allow the device to restore applications
49
+ that were installed using idevicebackup2
50
+ - Make idevicebackup2 reboot after restore the default to allow the device to
51
+ migrate data correctly and thus improve the restored device data state
52
+ - Improve console frontend information output in idevicebackup2
53
+ - Extend ideviceprovision tool to allow retrieving and removing all
54
+ provisioning profiles
55
+ - Fix parsing large provisioning profile using ideviceprovision
56
+ - Fix receiving large property lists in property list service
57
+ - Propagate lower level errors to callers instead of returning
58
+ IDEVICE_E_UNKNOWN_ERROR
59
+ - API: Add IDEVICE_DEVICE_PAIRED event type
60
+ - Detect screenshot format to support png, tiff and dat formats using
61
+ idevicescreenshot tool
62
+ - API: Add mobileactivation service implementation
63
+ - Wait for passcode entry if required using idevicesyslog
64
+ - Add HDMI option to diagnostics command for idevicediagnostics
65
+ - Fix IORegistry command for iOS 11+ devices in idevicediagnostics
66
+ - Remove 40-digit character limit for UDID in tools to support newer devices
67
+ - Fix broken validate command in idevicepair with iOS 11+
68
+ - Fix OpenSSL version checks for configure target when using LibreSSL
69
+ - Migrate latest improved common code from libusbmuxd
70
+ - Convert README file to markdown format
71
+ - Fix idevicecrashreport tool to work with iOS 13+
72
+ - Fix various errors in SSL communication logic
73
+ - API: Add preboard service implementation
74
+ - Output hint to user to enter passcode when changing password using
75
+ idevicebackup2
76
+ - Cython: Fix and improve debugserver and diagnostics service bindings
77
+ - API: Add WiFi device support via new idevice_new_with_options() function
78
+ - API: Add idevice_get_device_list_extended() to also list network devices
79
+ - API: Add lockdown_strerror() helper to get error representation as string
80
+ - Add network device support to idevicesyslog and ideviceinfo tools
81
+ - Make debug output consistently output to stderr
82
+ - Add new idevicesetlocation tool (requires mounted developer image)
83
+ - Add option to exit if device disconnects in idevicesyslog
84
+ - API: Add syslog_relay_start_capture_raw() for raw syslog capture
85
+ - Add color output and process filter support to idevicesyslog
86
+ - API: Add companion_proxy service implementation
87
+ - Bump dependency to libusbmuxd 2.0.2
88
+ - Bump dependency to libplist 2.2.0
89
+ - Improve error handling and reporting in library and tools
90
+ - Fix various memory leaks in library and tools
91
+ - Add "--network" and "--version" options to all tools
92
+ - Fix socket_connect_addr() not connecting to network devices using IPv6
93
+ in some cases.
94
+ - Improve IPv6 "scope id" detection to fix connecting to network devices with
95
+ link-local adresses.
96
+ - Update man pages
97
+ - Fix various inconsistent declarations in public headers
98
+ - Allow OpenSSL >= 1.1.0 to use older/disallowed TLS versions fixing issues
99
+ where pairing records were getting removed repeatingly
100
+ - Fixed memory leaks
101
+ - Cython: Rewrite version detection logic in configure.ac
102
+ - Rename "--enable-debug-code" configure option to "--enable-debug"
103
+ - Improve README.md with project description, installation, contributing and
104
+ usage sections
105
+ - Rename library and all related files by adding an API version resulting
106
+ in "libimobiledevice-1.0"
107
+ - Bump soname version
108
+ * API is UNSTABLE
109
+
110
+ Version 1.2.0
111
+ ~~~~~~~~~~~~~
112
+
113
+ * Stable release "It took you so long baby!"
114
+ * Changes:
115
+ - Require autoconf 2.64 or later
116
+ - Remove dev tools, will return either as proper tools or website examples
117
+ - Refactor installation proxy service implementation and normalize code
118
+ - API: Added instproxy_lookup() to efficiently lookup app information
119
+ - API: Added instproxy_check_capabilities_match() to check device capabilities
120
+ - API: Added various instproxy command and status plist getters
121
+ - API: Make debugserver_client_set_ack_mode() public
122
+ - Fix handling of clients reconnecting in idevicedebugserverproxy which
123
+ previously didn't work properly
124
+ - Flush stdout for every line in idevicesyslog
125
+ - Fix shutdown of idevicedebugserverproxy tool which could hang
126
+ - Notify user when erroneously using idevicebackup with iOS 4 or later
127
+ - Enable build of idevicecrashreport on WIN32
128
+ - Fix thread handle leaks on WIN32 adding thread_new and thread_free
129
+ - cython: Add receive/receive_timeout methods for iDeviceConnection to
130
+ receive raw data from a connection
131
+ - cython: Add new FILE_RELAY_E_PERMISSION_DENIED(-6) error
132
+ - API: Refactor lockdown service internal error checking and add a bunch of
133
+ new native errors
134
+ - Convert int16_t macro error types into enum within common module, too
135
+ - Add new "idevicenotificationproxy" tool to post or observe notifications
136
+ - Fix overlong blocking in np_client_free()
137
+ - Improve maintainability and Requires of pkg-config file
138
+ - API: Add new LOCKDOWN_E_SERVICE_LIMIT error to detect service limit states
139
+ - API: Remove const argv requirement for debugserver_command_new
140
+ - cython: Add get_path_for_bundle_identifier() method to
141
+ InstallationProxyClient
142
+ - cython: Add DebugServerClient class to communicate with debugserver
143
+ - Comply to strict function prototypes by using (void) instead of just ()
144
+ - Fix notification proxy shutdown process which was incorrectly implemented
145
+ - Fix linking problems on OS X
146
+ - Fix missing debug output which broke with the last release
147
+ - Unify and improve various debug messages
148
+ - Fix re-pairing if pairing with existing pair record failed initially
149
+ - Skip printing long plist (16kb+) files to prevent excessive debug output
150
+ - Move a few common helpers from backup tools to common utility helper code
151
+ - Remove incorrect flags from afc_file_open() documentation
152
+ - Fix various memory leaks
153
+
154
+ Version 1.1.7
155
+ ~~~~~~~~~~~~~
156
+
157
+ * Development release "Cleaning up the yard."
158
+ * Changes:
159
+ - Fix broken app args, environment handling and memory leaks in idevicedebug
160
+ - Make all tools print an error if lockdown connection fails
161
+ - Convert int16_t macro error types into enum for better type-checking and
162
+ for various debugging benefits
163
+ - Avoid exporting non-public symbols for better ABI stability
164
+ - Fix failing backup process for devices having a passcode set and entering
165
+ lock state during the process in idevicebackup2
166
+ - API: Added lockdownd_start_service_with_escrow_bag()
167
+ - API: Added afc_remove_path_and_contents() for recursive deletion
168
+ - Fix last memory leak with OpenSSL through proper library deinitialization
169
+ - Add new idevicedebug tool to interact with debugserver on a device
170
+ - API: Add debugserver service implementation
171
+ - Handle new PermissionDenied error of file_relay due new security in iOS 8+
172
+ - Fix retry loop problem when device requests 0 files in idevicebackup2
173
+ - Add trust dialog related error codes to Cython bindings
174
+ - Fix various memory leaks in AFC implementation
175
+ - Fix disk image upload with latest iOS 8 in ideviceimagemounter
176
+ - Add new "dump" command to print information about a provisioning profile in
177
+ ideviceprovision
178
+ - Refactor plist print helper code and move it into common module for better
179
+ reuse accross the tools
180
+ - Do not crash if retrieving the system buid fails
181
+ - API: Make generic "propery_list_service_client" public
182
+ - Moved doc comments from private to public headers
183
+ - Fix possible segfault when using lockdownd_get_value() due to always
184
+ returning success
185
+ - Do not read files entirely into memory during restore in idevicebackup
186
+ - Plug a few memory leaks and fix invalid password check in idevicebackup2
187
+ - Add support for file sizes > 4GB on Win32 in idevicebackup2
188
+ - Fix declaration for DllMain on Win32
189
+ - Silence various compiler warnings
190
+ - Fix assert within pairing logic
191
+ * API is UNSTABLE
192
+
193
+ Version 1.1.6
194
+ ~~~~~~~~~~~~~
195
+
196
+ * Development release "Way too overdue."
197
+ * Changes:
198
+ - Remove segmentation code from afc_file_read() to provide raw interface and
199
+ more control to API consumer I/O logic
200
+ - Implement global thread safe library initialization, especially to control
201
+ SSL backend lifecycle
202
+ - Major refactoring of pair record code and logic to use new usbmuxd pair
203
+ record management interface
204
+ - Replace user level with system wide pair record file handling
205
+ - Bump dependency to libplist 1.11 and remove use of "plist_dict_insert_item"
206
+ - Bump dependency to libusbmuxd 1.0.9
207
+ - Finish pair record and trust dialog handling for iOS 7+
208
+ - Improve AFC write performance and memory usage
209
+ - Add support for custom output filename to idevicescreenshot
210
+ - Fix detection and compilation for Python 3.x
211
+ - API: Added file_relay_request_sources_timeout()
212
+ - Fix broken HouseArrestClient class in cython bindings
213
+ - Add new idevicecrashreport tool to retrieve crash reports and logs from a
214
+ device
215
+ - Prevent "Failed to restart/shutdown device" messages in idevicediagnostics
216
+ - Link against ws2_32.dll on Win32
217
+ - Add support for iOS 7+ disk image mounting to ideviceimagemounter
218
+ - Add new idevicename tool to get or set the device name
219
+ - Allow unbacking of encrypted backups with a given password to idevicebackup2
220
+ - Remove sending "Goodbye" request on lockdown
221
+ - Add support for newer PLIST_REAL based time type to idevicedate
222
+ - Add note about setting time not working on iOS 6+ to idevicedate
223
+ - Handle partial SSL reads correctly now to prevent random crashes
224
+ - Fix duplicated output in ideviceinfo output
225
+ - Remove a bunch of dead code
226
+ - Fix deprecated OpenSSL "RSA_generate_key" with "RSA_generate_key_ex" which
227
+ is available since OpenSSL 0.9.8 (July 2005)
228
+ - Improve debug messages
229
+ - Enforce "-fsigned-char" to fix issues on embedded platforms
230
+ - Fix compilation with Clang/LLVM
231
+ - Avoid versioning for shared library on Win32
232
+ - Add experimental support for controlling cloud backup mode to idevicebackup2
233
+ - Save EscrowBag when starting service for automatic unlocking in pair record
234
+ - Remove pairing logic which is obsoleted by usbmuxd's preflight handler
235
+ - Fix shutdown of SSL connection to be correct and no longer generate errors
236
+ on device
237
+ - Add support for GnuTLS 3.x and fix broken GnuTLS backend
238
+ - Add extensions to generated certificates to match native ones
239
+ - Add "systembuid" command to idevicepair
240
+ - Allow starting service without the need for a running SSL session
241
+ - Refactor more code into common module
242
+ - Add option to filerelaytest to specify a source to request
243
+ - Fix support for partial messages in webinspector implementation
244
+ - Implement support for encrypted backups in idevicebackup2
245
+ - API: Export SSL control functions for idevice_connection_t
246
+ - API: Make generic service client public to allow external service
247
+ implementations
248
+ - Implement *_start_service() helper for easier creation of service clients
249
+ - Add public *_SERVICE_NAME defines for each service
250
+ - Fix a great bunch of memory leaks after intensive valgrind session
251
+ - Security: Fix insecure use of the /tmp directory (CVE-2013-2142)
252
+ - A bunch of memory leak fixes
253
+ - Python: Various fixes and support for "with" statement for AfcFile class
254
+ - Python: Add Afc2Client class to allow jailbroken filesystem access
255
+ - Fix linking issue with newer libtool as reported for Ubuntu
256
+ - Fix stuck thread in idevicesyslog which broke quit from within the tool
257
+ - Add syslog_relay service implementation and use it in idevicesyslog
258
+ - API: Add instproxy_client_get_path_for_bundle_identifier() helper
259
+ - API: Add afc_dictionary_free() helper
260
+ - Move thread, socket, debug and userpref code to "common" source directory
261
+ in order to improve code reuse
262
+ - Fix broken byte order detection in configure.ac which could lead to broken
263
+ AFC protocol communication on platforms without endian.h (Raspberry PI)
264
+ * API is UNSTABLE
265
+
266
+ Version 1.1.5
267
+ ~~~~~~~~~~~~~
268
+
269
+ * Development release
270
+ * Changes:
271
+ - Implement automatic reconnecting in idevicesyslog
272
+ - Refactor all services to use new base service
273
+ - Add new generic service_client_factory_start_service() helper
274
+ - Implement a base service that all services inherit from
275
+ - API: Refactor use of "port numbers" into a "service descriptor" which is
276
+ a needed change as all services must now transparently support SSL.
277
+ Fortunately, only minor changes are needed to migrate your code properly.
278
+ - Add experimental ideviceheartbeat to allow service checkin over the network
279
+ - Add heartbeat service implementation to keep alive network connections
280
+ - Add webinspector service implementation for WebKit remote debugging
281
+ - Fix idevicebackup2 failing due to integer overflow in free disk space
282
+ calculation on 32 bit architectures and large disk capacities
283
+ - Add support for encrypted and password protected backups to idevicebackup2
284
+ - Fix major "too long filename received" bug in idevicebackup2
285
+ - Various fixes for proper and tested WIN32 support including MinGW building
286
+ - Fix various crashers and improve quality of idevicebackup2 tool
287
+ - Add endianness helpers for systems lacking support
288
+ - Fix idevicedate to work on iOS 6+
289
+ - Add idevicediagnostics tool
290
+ - Add diagnostics_relay service implementation
291
+ - Add idevicedebugserverproxy tool for remote lldb debugging
292
+ - Add ideviceprovision tool
293
+ - Add misagent service implementation to manage provisioning profiles
294
+ - Fix crash if $HOME is empty or not defined
295
+ - Fix non-ASCII characters being stripped when using plist communication
296
+ - Improve compile support for cython and check it at configure time
297
+ - Bump cython requirement to 0.17.0+
298
+ - Fix compilation of cython bindings
299
+ - Python bindings now cover all C APIs
300
+ - Fix iOS 6 compatibility for mobilesync, mobilebackup, mobilebackup2 and
301
+ screenshotr by bumping device link protocol version number
302
+ - Do not strip non_ASCII characters from XML plists
303
+ - Fix possible crash when using OpenSSL
304
+ * API is UNSTABLE
305
+
306
+ Version 1.1.4
307
+ ~~~~~~~~~~~~~
308
+
309
+ * Development release
310
+ * Changes:
311
+ - Fix a bug in idevicesyslog causing the connection to close after timeout
312
+ - Bump soname revision
313
+ * API is UNSTABLE
314
+
315
+ Version 1.1.3
316
+ ~~~~~~~~~~~~~
317
+
318
+ * Development release
319
+ * Changes:
320
+ - Bump libusbmuxd dependency to 1.0.8
321
+ - Fix reading from syslog_relay and remove null characters
322
+ - Relicense ideviceimagemounter and idevicescreenshot to LGPL
323
+ - Fix a crash when using restored_client_free()
324
+ - API: Add sbservices_get_interface_orientation()
325
+ - Update man pages and code comments for documentation
326
+ - Minor cleanup
327
+ * API is UNSTABLE
328
+
329
+ Version 1.1.2
330
+ ~~~~~~~~~~~~~
331
+
332
+ * Development release
333
+ * Changes:
334
+ - Add Python bindings generated by Cython
335
+ - Bump libplist requirement to latest 1.8
336
+ - Add support for OpenSSL with fallback to GNUTLS
337
+ - Improvements and various fixes for Win32 and OS X build
338
+ - Remove glib dependency
339
+ - Improve restored implementation
340
+ - Fix various memory leaks
341
+ - Fix support for iOS 5 and later
342
+ * SWIG Python Bindings are removed
343
+ * API is UNSTABLE
344
+
345
+ Version 1.1.1
346
+ ~~~~~~~~~~~~~
347
+
348
+ * Development release
349
+ * Changes:
350
+ - Add new idevicebackup2 tool for full backup and restore support on iOS 4+
351
+ - Add a workaround for a bug in iOS 4.3 affecting lockdown_get_value() which
352
+ most prominently affected libgpod, gvfs, ideviceinfo and some other tools
353
+ - Read ProxyDeath message to preventing obsolete messages in device syslog
354
+ - Rework SWIG detection and includes
355
+ - Add new idevicedate tool to get or set the clock on iDevices
356
+ - API: Add mobilesync_clear_all_records_on_device()
357
+ - API: Change device_link_service_disconnect() to accept a message
358
+ - Add manpages for ideviceenterrecovery, idevicepair, idevicebackup2 and
359
+ idevicedate
360
+ - Add missing libgen.h include to silence compiler warnings
361
+ - Fix a segfault that might occour if locally stored certs could not be read
362
+ - Fix various memory leaks
363
+ - Update documentation
364
+ * Python Bindings will get refactored completely
365
+ * API is UNSTABLE
366
+
367
+ Version 1.1.0
368
+ ~~~~~~~~~~~~~
369
+
370
+ * Development release
371
+ * Changes:
372
+ - Implement restoring backups using idevicebackup
373
+ - Allow connecting without pairing using "ideviceinfo -s"
374
+ - Add ideviceenterrecovery tool
375
+ - Add mobilesync service implementation
376
+ - Add restored service implementation for restore mode
377
+ - Add home_arrest service implementation for document sharing
378
+ - Add API afc_client_new_from_connection()
379
+ - Support to fetch wallpaper in sbservices
380
+ - Support for formatVersion 2 of iOS 4+ in sbservices
381
+ - Add new lockdownd domains to ideviceinfo
382
+ - Give the device time to prepare backup data to prevent abort
383
+ - Improve idevicebackup output
384
+ - notification_proxy fixes and new notification type
385
+ - Silence some 64bit compiler warnings
386
+ - Fix various memory leaks
387
+ - Update documentation
388
+ * Python Bindings will get refactored completely
389
+ * API is UNSTABLE
390
+
391
+ Version 1.0.7
392
+ ~~~~~~~~~~~~~
393
+
394
+ * Maintenance release of stable series
395
+ * Changes:
396
+ - Fix SWIG 2.x detection
397
+ - Fix support for iOS 5 and later
398
+ - Flush output of idevicesyslog immediately
399
+ - Replace deprecated GNUTLS functions properly
400
+ - Fix segfaults in library and some tools
401
+ - Fix memory leaks
402
+ - Build fixes
403
+
404
+ Version 1.0.6
405
+ ~~~~~~~~~~~~~
406
+
407
+ * Quick follow up release
408
+ * Changes:
409
+ - Add ideviceenterrecovery which was missing in last release by accident
410
+
411
+ Version 1.0.5
412
+ ~~~~~~~~~~~~~
413
+
414
+ * Maintenance release of stable series
415
+ * Changes:
416
+ - Add a workaround for a bug in iOS 4.3 affecting lockdown_get_value() which
417
+ most prominently affected libgpod, gvfs, ideviceinfo and some other tools
418
+ - Read ProxyDeath message to preventing obsolete messages in device syslog
419
+ - Rework SWIG detection and includes
420
+ - Add manpages for ideviceenterrecovery and idevicepair
421
+ - Add missing libgen.h include to silence compiler warnings
422
+
423
+ Version 1.0.4
424
+ ~~~~~~~~~~~~~
425
+
426
+ * Maintenance release of stable series
427
+ * Changes:
428
+ - Fix a possible crash in lockdownd_client_new_with_handshake()
429
+ - Do not not check for Swig/Python if --without-swig is set
430
+ - Fail with an error message if libgcrypt is not found
431
+ - Pass host certificate with GNUTLS correctly
432
+ - Fix connecting to iOS 4.2.1+ devices
433
+
434
+ Version 1.0.3
435
+ ~~~~~~~~~~~~~
436
+
437
+ * Maintenance release of stable series
438
+ * Changes:
439
+ - Terminate idevicesyslog on receive errors (like device unplug)
440
+ - Bugfixes for idevicebackup tool
441
+ - Hopefully the last fixes for big endian machines
442
+ - Build fixes for FreeBSD Python support
443
+ - Fix build on Mac OS X
444
+
445
+ Version 1.0.2
446
+ ~~~~~~~~~~~~~
447
+
448
+ * Maintenance release of stable series
449
+ * Changes:
450
+ - Backport new idevicepair tool to manage pairings
451
+ - Fix a bug causing bad backup data
452
+ - Silence 64bit compiler warnings
453
+ - Plug some memory leaks
454
+
455
+ Version 1.0.1
456
+ ~~~~~~~~~~~~~
457
+
458
+ * Maintenance release of stable series
459
+ * Changes:
460
+ - Cleanup includes of files
461
+ - Use glib instead of netinet for endianess
462
+ - Fix installation_proxy not adding client options correctly
463
+ - idevicebackup: better handle broken or missing plist files
464
+ - Fix some memory leaks in pairing/handshake process
465
+ - Fix label not being used in lockdownd_client_new()
466
+ - Update AUTHORS, README and installation instructions
467
+
468
+ Version 1.0.0
469
+ ~~~~~~~~~~~~~
470
+
471
+ * Changes:
472
+ - Update and fix documentation for full coverage
473
+ - Add man pages for tools
474
+ - Extend mobilebackup interface
475
+ - Add user data argument to notification callback function
476
+ - Fix broken Python bindings
477
+ - Add Python bindings for notification proxy interface
478
+ - Add screenshotr interface and tool
479
+ - Add mobile_image_mounter interface and tool
480
+ - Remove HAL fdi rules
481
+
482
+ Version 0.9.7 (RC1)
483
+ ~~~~~~~~~~~~~~~~~~~
484
+
485
+ * Project is now called libimobiledevice due to legal reasons
486
+ * Changes:
487
+ - Project renamed to libimobiledevice
488
+ - Add soname versioning for future releases
489
+ - Fix regression causing never paired devices to not work by adding
490
+ auto-pairing for devices in lockdownd_client_new_with_handshake
491
+ - Add file_relay service implementation and dev test tool
492
+ - Minor device link service fixes
493
+ - New idevicebackup tool with support for full and incremental backups
494
+ - Add mobilebackup service implementation
495
+
496
+ Version 0.9.6
497
+ ~~~~~~~~~~~~~
498
+
499
+ * Changes:
500
+ - Minor public API changes to prepare for 1.0 release:
501
+ * lockdownd_client_new -> lockdownd_client_new_with_handshake
502
+ * fooservice_recv -> fooservice_receive
503
+ * iphone_device_send/_recv -> iphone_connection_send/_receive
504
+ - Rename some code for consistency
505
+ - Refactor pairing to allow custom pair records
506
+ - Move SSL handling out of lockdownd code
507
+ - Refactor lockdown session handling code
508
+ - Remove debug mask support
509
+ - No longer do a full lockdown handshake on client_new
510
+ - Refactor debug code to be consistent and easier to use
511
+ - Run validate_pair by default during lockdown handshake
512
+ - Allow retrieving the type for lockdown query_type request
513
+ - Add new property_list_service and device_link_service abstractions
514
+ - Detect pairing failure due to having a password set on the device
515
+ - Implement lockdown phone activation and deactivation
516
+ - Fix iphoneinfo not printing values in key/value mode
517
+ - Implement lockdownd_unpair() request
518
+ - Add more notification ids and lockdown domains
519
+ - Implement label support for lockdown requests
520
+ - Add new installation_proxy interface
521
+ - Add new sbservices interface
522
+ - Implement lockdownd_validate_pair() request
523
+ - Add endian safety to AFC
524
+ - Make lockdown sessions without SSL work
525
+ - Fix linking on Mandriva Linux
526
+ - Minor bugfixes and documentation updates
527
+
528
+ Version 0.9.5
529
+ ~~~~~~~~~~~~~
530
+
531
+ * Changes:
532
+ - Updated to the latest libplist 0.16 API
533
+ - Fixed various minor leaks and issues
534
+ - Updated Python bindings and module name
535
+
536
+ Version 0.9.4
537
+ ~~~~~~~~~~~~~
538
+
539
+ * Changes:
540
+ - Update to libplist 0.15 API rework
541
+ - Update Python bindings
542
+ - Bufixes around usbmuxd daemon usage
543
+ - Use automake 1.11 silent rules if available
544
+ - Various bugfixes
545
+
546
+ Version 0.9.3
547
+ ~~~~~~~~~~~~~
548
+
549
+ * Changes:
550
+ - Bump libplist requirement to 0.13 and remove deprecated code
551
+
552
+ Version 0.9.2
553
+ ~~~~~~~~~~~~~
554
+
555
+ * Changes:
556
+ - Migrate to use the new usbmuxd daemon
557
+ - Refactor whole API
558
+ - Add iPhone 3GS support
559
+ - Add hard/symlink support for AFC
560
+ - New iphone_id tool to list connected devices and get the device
561
+ name
562
+ - iphoneinfo now allows plist/xml output and queries by
563
+ domain/key
564
+ - Fix a lot of bugs/crashes, compiler warnings and comments
565
+
566
+ Version 0.9.1
567
+ ~~~~~~~~~~~~~
568
+
569
+ * Changes:
570
+ - Fix make distcheck
571
+ - Bump libplist requirement to 0.12 and remove deprecated code
572
+ - A bunch of autotools fixes
573
+
574
+ Version 0.9.0
575
+ ~~~~~~~~~~~~~
576
+
577
+ * Changes:
578
+ - Fix pkg-config dependancies
579
+ - Fix Python binding generation
580
+ - AFC cleanup and improved error handling
581
+ - Add support for the notification proxy service
582
+ - Add tools to show device information and relay syslog
583
+ - More robust pairing implementation
584
+ - Remove libiphone-initconf, SSL implementation handles it at
585
+ runtime now
586
+ - Fix receive of plists larger than a packet
587
+ - Return an error if failed to start a service on the device
588
+ - Fix usb enumeration
589
+ - Fix udev rule to catch usb hubs, too
590
+ - Add large file support
591
+ - Move out plist handling into libplist and depend on it
592
+ - Add Python bindings
593
+ - Lots of bugfixes
594
+
595
+ Version 0.1.0
596
+ ~~~~~~~~~~~~~
597
+
598
+ * Changes:
599
+ - Use udev to set usb configuration; iphone kmod is obsolete now
600
+ - Remove HAL mounting
601
+ - Bugfixes
602
+
README.md CHANGED
@@ -1,10 +1,201 @@
1
- ---
2
- title: Restore
3
- emoji: 🦀
4
- colorFrom: green
5
- colorTo: green
6
- sdk: static
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # libimobiledevice
2
+
3
+ *A library to communicate with services on iOS devices using native protocols.*
4
+
5
+ ![](https://github.com/libimobiledevice/libimobiledevice/actions/workflows/build.yml/badge.svg)
6
+
7
+ ## Features
8
+
9
+ libimobiledevice is a cross-platform software library that talks the protocols
10
+ to interact with iOS devices.
11
+
12
+ Unlike other projects, it does not depend on using any existing proprietary
13
+ libraries and does not require jailbreaking.
14
+
15
+ Some key features are:
16
+
17
+ - **Interface**: Implements many high-level interfaces for device services
18
+ - **Implementation**: Object oriented architecture and service abstraction layer
19
+ - **Cross-Platform:** Tested on Linux, macOS, Windows and Android platforms
20
+ - **Utilities**: Provides various command-line utilities for device services
21
+ - **SSL**: Allows choosing between OpenSSL, GnuTLS, or MbedTLS to handle SSL communication
22
+ - **Network**: Supports network connections with "WiFi sync" enabled devices
23
+ - **Python:** Provides Cython based bindings for Python
24
+
25
+ The implemented interfaces of many device service protocols allow applications
26
+ to:
27
+
28
+ * Access filesystem of a device
29
+ * Access documents of file sharing apps
30
+ * Retrieve information about a device and modify various settings
31
+ * Backup and restore the device in a native way compatible with iTunes
32
+ * Manage app icons arrangement on the device
33
+ * Install, remove, list and basically manage apps
34
+ * Activate a device using official servers
35
+ * Manage contacts, calendars, notes and bookmarks
36
+ * Retrieve and remove crashreports
37
+ * Retrieve various diagnostics information
38
+ * Establish a debug connection for app debugging
39
+ * Mount filesystem images
40
+ * Forward device notifications
41
+ * Manage device provisioning
42
+ * Take screenshots from the device screen (requires mounted developer image)
43
+ * Simulate changed geolocation of the device (requires mounted developer image)
44
+ * Relay the syslog of the device
45
+ * Expose a connection for WebKit remote debugging
46
+
47
+ ... and much more.
48
+
49
+ The library is in development since August 2007 with the goal to bring support
50
+ for these devices to the Linux Desktop.
51
+
52
+ ## Installation / Getting started
53
+
54
+ ### Debian / Ubuntu Linux
55
+
56
+ First install all required dependencies and build tools:
57
+ ```shell
58
+ sudo apt-get install \
59
+ build-essential \
60
+ pkg-config \
61
+ checkinstall \
62
+ git \
63
+ autoconf \
64
+ automake \
65
+ libtool-bin \
66
+ libplist-dev \
67
+ libusbmuxd-dev \
68
+ libimobiledevice-glue-dev \
69
+ libtatsu-dev \
70
+ libssl-dev \
71
+ usbmuxd
72
+ ```
73
+ NOTE: [libtatsu](https://github.com/libimobiledevice/libtatsu) (and thus `libtatsu-dev`)
74
+ is a new library that was just published recently, you have to
75
+ [build it from source](https://github.com/libimobiledevice/libtatsu?tab=readme-ov-file#building).
76
+
77
+ If you want to optionally build the documentation or Python bindings use:
78
+ ```shell
79
+ sudo apt-get install \
80
+ doxygen \
81
+ cython
82
+ ```
83
+
84
+ Then clone the actual project repository:
85
+ ```shell
86
+ git clone https://github.com/libimobiledevice/libimobiledevice.git
87
+ cd libimobiledevice
88
+ ```
89
+
90
+ Now you can build and install it:
91
+ ```shell
92
+ ./autogen.sh
93
+ make
94
+ sudo make install
95
+ ```
96
+
97
+ If you require a custom prefix or other option being passed to `./configure`
98
+ you can pass them directly to `./autogen.sh` like this:
99
+ ```bash
100
+ ./autogen.sh --prefix=/opt/local --enable-debug
101
+ make
102
+ sudo make install
103
+ ```
104
+
105
+ By default, OpenSSL will be used as TLS/SSL library. If you prefer GnuTLS,
106
+ configure with `--with-gnutls` like this:
107
+ ```bash
108
+ ./autogen.sh --with-gnutls
109
+ ```
110
+
111
+ MbedTLS is also supported and can be enabled by passing `--with-mbedtls` to
112
+ configure. If mbedTLS is not installed in a default location, you need to set
113
+ the environment variables `mbedtls_INCLUDES` to the path that contains the
114
+ MbedTLS headers and `mbedtls_LIBDIR` to set the library path. Optionally,
115
+ `mbedtls_LIBS` can be used to set the library names directly. Example:
116
+ ```bash
117
+ ./autogen.sh --with-mbedtls mbedtls_INCLUDES=/opt/local/include mbedtls_LIBDIR=/opt/local/lib
118
+ ```
119
+
120
+ ## Usage
121
+
122
+ Documentation about using the library in your application is not available yet.
123
+ The "hacker way" for now is to look at the implementation of the included
124
+ utilities.
125
+
126
+ ### Utilities
127
+
128
+ The library bundles the following command-line utilities in the tools directory:
129
+
130
+ | Utility | Description |
131
+ | -------------------------- | ------------------------------------------------------------------ |
132
+ | `idevice_id` | List attached devices or print device name of given device |
133
+ | `idevicebackup` | Create or restore backup for devices (legacy) |
134
+ | `idevicebackup2` | Create or restore backups for devices running iOS 4 or later |
135
+ | `idevicebtlogger` | Capture Bluetooth HCI traffic from a device (requires log profile) |
136
+ | `idevicecrashreport` | Retrieve crash reports from a device |
137
+ | `idevicedate` | Display the current date or set it on a device |
138
+ | `idevicedebug` | Interact with the debugserver service of a device |
139
+ | `idevicedebugserverproxy` | Proxy a debugserver connection from a device for remote debugging |
140
+ | `idevicediagnostics` | Interact with the diagnostics interface of a device |
141
+ | `ideviceenterrecovery` | Make a device enter recovery mode |
142
+ | `ideviceimagemounter` | Mount disk images on the device |
143
+ | `ideviceinfo` | Show information about a connected device |
144
+ | `idevicename` | Display or set the device name |
145
+ | `idevicenotificationproxy` | Post or observe notifications on a device |
146
+ | `idevicepair` | Manage host pairings with devices and usbmuxd |
147
+ | `ideviceprovision` | Manage provisioning profiles on a device |
148
+ | `idevicescreenshot` | Gets a screenshot from the connected device |
149
+ | `idevicesetlocation` | Simulate location on device |
150
+ | `idevicesyslog` | Relay syslog of a connected device |
151
+ | `afcclient` | Interact with device filesystem via AFC/HouseArrest |
152
+
153
+ Please consult the usage information or manual pages of each utility for a
154
+ documentation of available command line options and usage examples like this:
155
+ ```shell
156
+ ideviceinfo --help
157
+ man ideviceinfo
158
+ ```
159
+
160
+ ## Contributing
161
+
162
+ We welcome contributions from anyone and are grateful for every pull request!
163
+
164
+ If you'd like to contribute, please fork the `master` branch, change, commit and
165
+ send a pull request for review. Once approved it can be merged into the main
166
+ code base.
167
+
168
+ If you plan to contribute larger changes or a major refactoring, please create a
169
+ ticket first to discuss the idea upfront to ensure less effort for everyone.
170
+
171
+ Please make sure your contribution adheres to:
172
+ * Try to follow the code style of the project
173
+ * Commit messages should describe the change well without being too short
174
+ * Try to split larger changes into individual commits of a common domain
175
+ * Use your real name and a valid email address for your commits
176
+
177
+ We are still working on the guidelines so bear with us!
178
+
179
+ ## Links
180
+
181
+ * Homepage: https://libimobiledevice.org/
182
+ * Repository: https://github.com/libimobiledevice/libimobiledevice.git
183
+ * Repository (Mirror): https://git.libimobiledevice.org/libimobiledevice.git
184
+ * Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues
185
+ * Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
186
+ * Twitter: https://twitter.com/libimobiledev
187
+
188
+ ## License
189
+
190
+ This library and utilities are licensed under the [GNU Lesser General Public License v2.1](https://www.gnu.org/licenses/lgpl-2.1.en.html),
191
+ also included in the repository in the `COPYING` file.
192
+
193
+ ## Credits
194
+
195
+ Apple, iPhone, iPad, iPod, iPod Touch, Apple TV, Apple Watch, Mac, iOS,
196
+ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
197
+
198
+ This project is an independent software and has not been authorized, sponsored,
199
+ or otherwise approved by Apple Inc.
200
+
201
+ README Updated on: 2024-10-22
ac_pkg_cython.m4 ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ AC_DEFUN([AC_PROG_CYTHON],[
3
+ AC_PATH_PROGS([CYTHON],[cython cython3])
4
+ if test -z "$CYTHON" ; then
5
+ AC_MSG_WARN([Unable to find 'cython' or 'cython3' program. You should look at https://cython.org or install your distribution specific cython package.])
6
+ CYTHON=false
7
+ elif test -n "$1" ; then
8
+ AC_MSG_CHECKING([for Cython version])
9
+ [cython_version=`$CYTHON --version 2>&1 | sed 's/Cython version \(.*\)$/\1/g'`]
10
+ AC_MSG_RESULT([$cython_version])
11
+
12
+ # Setup extra version string for parsing
13
+ [cython_version_stripped=`echo $cython_version | sed 's/\([0-9]\+\)\.\([0-9]\+\)[^\.]*\(\.\([0-9]\+\)\)\?.*/0\1.0\2.0\4/g'`]
14
+ if test -n "$cython_version" ; then
15
+ # Calculate the required version number components
16
+ [required=$1]
17
+ [required_major=`echo $required | sed 's/[^0-9].*//'`]
18
+ if test -z "$required_major" ; then
19
+ [required_major=0]
20
+ fi
21
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
22
+ [required_minor=`echo $required | sed 's/[^0-9].*//'`]
23
+ if test -z "$required_minor" ; then
24
+ [required_minor=0]
25
+ fi
26
+ [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
27
+ [required_patch=`echo $required | sed 's/[^0-9].*//'`]
28
+ if test -z "$required_patch" ; then
29
+ [required_patch=0]
30
+ fi
31
+
32
+ # Calculate the available version number components
33
+ [available=$cython_version_stripped]
34
+ [available_major=`echo $available | sed 's/[^0-9].*//'`]
35
+ if test -z "$available_major" ; then
36
+ [available_major=0]
37
+ fi
38
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
39
+ [available_minor=`echo $available | sed 's/[^0-9].*//'`]
40
+ if test -z "$available_minor" ; then
41
+ [available_minor=0]
42
+ fi
43
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
44
+ [available_patch=`echo $available | sed 's/[^0-9].*//'`]
45
+ if test -z "$available_patch" ; then
46
+ [available_patch=0]
47
+ fi
48
+
49
+ if test $available_major -gt $required_major || \
50
+ ( test $available_major -eq $required_major && \
51
+ test $available_minor -gt $required_minor ) || \
52
+ ( test $available_major -eq $required_major && \
53
+ test $available_minor -eq $required_minor && \
54
+ test $available_patch -ge $required_patch ) ; then
55
+
56
+ AC_MSG_NOTICE([Cython executable is '$CYTHON'])
57
+ else
58
+ AC_MSG_WARN([Cython version >= $1 is required. You have $cython_version. You should look at http://www.cython.org])
59
+ CYTHON='echo "Error: Cython version >= $1 is required. You have '"$cython_version"'. You should look at http://www.cython.org" ; false'
60
+ fi
61
+ else
62
+ AC_MSG_WARN([Unable to determine Cython version])
63
+ CYTHON=false
64
+ fi
65
+ fi
66
+ AC_SUBST([CYTHON_LIB])
67
+ ])
afc.c ADDED
@@ -0,0 +1,1314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * afc.c
3
+ * Contains functions for the built-in AFC client.
4
+ *
5
+ * Copyright (c) 2014 Martin Szulecki All Rights Reserved.
6
+ * Copyright (c) 2009-2014 Nikias Bassen. All Rights Reserved.
7
+ * Copyright (c) 2008 Zach C. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifdef HAVE_CONFIG_H
25
+ #include <config.h>
26
+ #endif
27
+ #include <stdio.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+
31
+ #ifndef _MSC_VER
32
+ #include <unistd.h>
33
+ #endif
34
+
35
+ #include "idevice.h"
36
+ #include "afc.h"
37
+ #include "common/debug.h"
38
+ #include "endianness.h"
39
+
40
+ /**
41
+ * Locks an AFC client, done for thread safety stuff
42
+ *
43
+ * @param client The AFC client connection to lock
44
+ */
45
+ static void afc_lock(afc_client_t client)
46
+ {
47
+ debug_info("Locked");
48
+ mutex_lock(&client->mutex);
49
+ }
50
+
51
+ /**
52
+ * Unlocks an AFC client, done for thread safety stuff.
53
+ *
54
+ * @param client The AFC
55
+ */
56
+ static void afc_unlock(afc_client_t client)
57
+ {
58
+ debug_info("Unlocked");
59
+ mutex_unlock(&client->mutex);
60
+ }
61
+
62
+ /**
63
+ * Makes a connection to the AFC service on the device using the given
64
+ * connection.
65
+ *
66
+ * @param service_client A connected service client
67
+ * @param client Pointer that will be set to a newly allocated afc_client_t
68
+ * upon successful return.
69
+ *
70
+ * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARG if connection is
71
+ * invalid, or AFC_E_NO_MEM if there is a memory allocation problem.
72
+ */
73
+
74
+ afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client)
75
+ {
76
+ if (!service_client)
77
+ return AFC_E_INVALID_ARG;
78
+
79
+ afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_private));
80
+ client_loc->parent = service_client;
81
+ client_loc->free_parent = 0;
82
+
83
+ /* allocate a packet */
84
+ client_loc->packet_extra = 1024;
85
+ client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket) + client_loc->packet_extra);
86
+ if (!client_loc->afc_packet) {
87
+ free(client_loc);
88
+ return AFC_E_NO_MEM;
89
+ }
90
+ client_loc->afc_packet->packet_num = 0;
91
+ client_loc->afc_packet->entire_length = 0;
92
+ client_loc->afc_packet->this_length = 0;
93
+ memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN);
94
+ mutex_init(&client_loc->mutex);
95
+
96
+ *client = client_loc;
97
+ return AFC_E_SUCCESS;
98
+ }
99
+
100
+ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client)
101
+ {
102
+ if (!device || !service || service->port == 0)
103
+ return AFC_E_INVALID_ARG;
104
+
105
+ service_client_t parent = NULL;
106
+ if (service_client_new(device, service, &parent) != SERVICE_E_SUCCESS) {
107
+ return AFC_E_MUX_ERROR;
108
+ }
109
+
110
+ afc_error_t err = afc_client_new_with_service_client(parent, client);
111
+ if (err != AFC_E_SUCCESS) {
112
+ service_client_free(parent);
113
+ } else {
114
+ (*client)->free_parent = 1;
115
+ }
116
+ return err;
117
+ }
118
+
119
+ afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
120
+ {
121
+ int32_t err = AFC_E_UNKNOWN_ERROR;
122
+ service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err);
123
+ return err;
124
+ }
125
+
126
+ afc_error_t afc_client_free(afc_client_t client)
127
+ {
128
+ if (!client || !client->afc_packet)
129
+ return AFC_E_INVALID_ARG;
130
+
131
+ if (client->free_parent && client->parent) {
132
+ service_client_free(client->parent);
133
+ client->parent = NULL;
134
+ }
135
+ free(client->afc_packet);
136
+ mutex_destroy(&client->mutex);
137
+ free(client);
138
+ return AFC_E_SUCCESS;
139
+ }
140
+
141
+ /**
142
+ * Dispatches an AFC packet over a client.
143
+ *
144
+ * @param client The client to send data through.
145
+ * @param operation The operation to perform.
146
+ * @param data The data to send together with the header.
147
+ * @param data_length The length of the data to send with the header.
148
+ * @param payload The data to send after the header has been sent.
149
+ * @param payload_length The length of data to send after the header.
150
+ * @param bytes_sent The total number of bytes actually sent.
151
+ *
152
+ * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
153
+ */
154
+ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent)
155
+ {
156
+ uint32_t sent = 0;
157
+
158
+ if (!client || !client->parent || !client->afc_packet)
159
+ return AFC_E_INVALID_ARG;
160
+
161
+ *bytes_sent = 0;
162
+
163
+ if (!payload || !payload_length)
164
+ payload_length = 0;
165
+
166
+ client->afc_packet->packet_num++;
167
+ client->afc_packet->operation = operation;
168
+ client->afc_packet->entire_length = sizeof(AFCPacket) + data_length + payload_length;
169
+ client->afc_packet->this_length = sizeof(AFCPacket) + data_length;
170
+
171
+ debug_info("packet length = %i", client->afc_packet->this_length);
172
+
173
+ /* send AFC packet header and data */
174
+ AFCPacket_to_LE(client->afc_packet);
175
+ debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length);
176
+ sent = 0;
177
+ service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent);
178
+ AFCPacket_from_LE(client->afc_packet);
179
+ *bytes_sent += sent;
180
+ if (sent < sizeof(AFCPacket) + data_length) {
181
+ return AFC_E_SUCCESS;
182
+ }
183
+
184
+ sent = 0;
185
+ if (payload_length > 0) {
186
+ if (payload_length > 256) {
187
+ debug_info("packet payload follows (256/%u)", payload_length);
188
+ debug_buffer(payload, 256);
189
+ } else {
190
+ debug_info("packet payload follows");
191
+ debug_buffer(payload, payload_length);
192
+ }
193
+ service_send(client->parent, payload, payload_length, &sent);
194
+ }
195
+ *bytes_sent += sent;
196
+ if (sent < payload_length) {
197
+ return AFC_E_SUCCESS;
198
+ }
199
+
200
+ return AFC_E_SUCCESS;
201
+ }
202
+
203
+ /**
204
+ * Receives data through an AFC client and sets a variable to the received data.
205
+ *
206
+ * @param client The client to receive data on.
207
+ * @param bytes The char* to point to the newly-received data.
208
+ * @param bytes_recv How much data was received.
209
+ *
210
+ * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
211
+ */
212
+ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t *bytes_recv)
213
+ {
214
+ AFCPacket header;
215
+ uint32_t entire_len = 0;
216
+ uint32_t this_len = 0;
217
+ uint32_t current_count = 0;
218
+ uint64_t param1 = -1;
219
+ char *buf = NULL;
220
+ uint32_t recv_len = 0;
221
+
222
+ if (bytes_recv) {
223
+ *bytes_recv = 0;
224
+ }
225
+ if (bytes) {
226
+ *bytes = NULL;
227
+ }
228
+
229
+ /* first, read the AFC header */
230
+ service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len);
231
+ AFCPacket_from_LE(&header);
232
+ if (recv_len == 0) {
233
+ debug_info("Just didn't get enough.");
234
+ return AFC_E_MUX_ERROR;
235
+ }
236
+
237
+ if (recv_len < sizeof(AFCPacket)) {
238
+ debug_info("Did not even get the AFCPacket header");
239
+ return AFC_E_MUX_ERROR;
240
+ }
241
+
242
+ /* check if it's a valid AFC header */
243
+ if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) {
244
+ debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
245
+ }
246
+
247
+ /* check if it has the correct packet number */
248
+ if (header.packet_num != client->afc_packet->packet_num) {
249
+ /* otherwise print a warning but do not abort */
250
+ debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num);
251
+ return AFC_E_OP_HEADER_INVALID;
252
+ }
253
+
254
+ /* then, read the attached packet */
255
+ if (header.this_length < sizeof(AFCPacket)) {
256
+ debug_info("Invalid AFCPacket header received!");
257
+ return AFC_E_OP_HEADER_INVALID;
258
+ }
259
+ if ((header.this_length == header.entire_length)
260
+ && header.entire_length == sizeof(AFCPacket)) {
261
+ debug_info("Empty AFCPacket received!");
262
+ if (header.operation == AFC_OP_DATA) {
263
+ return AFC_E_SUCCESS;
264
+ }
265
+ return AFC_E_IO_ERROR;
266
+ }
267
+
268
+ debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);
269
+
270
+ entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
271
+ this_len = (uint32_t)header.this_length - sizeof(AFCPacket);
272
+
273
+ buf = (char*)malloc(entire_len);
274
+ if (this_len > 0) {
275
+ recv_len = 0;
276
+ service_receive(client->parent, buf, this_len, &recv_len);
277
+ if (recv_len <= 0) {
278
+ free(buf);
279
+ debug_info("Did not get packet contents!");
280
+ return AFC_E_NOT_ENOUGH_DATA;
281
+ }
282
+ if (recv_len < this_len) {
283
+ free(buf);
284
+ debug_info("Could not receive this_len=%d bytes", this_len);
285
+ return AFC_E_NOT_ENOUGH_DATA;
286
+ }
287
+ }
288
+
289
+ current_count = this_len;
290
+
291
+ if (entire_len > this_len) {
292
+ while (current_count < entire_len) {
293
+ recv_len = 0;
294
+ service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len);
295
+ if (recv_len <= 0) {
296
+ debug_info("Error receiving data (recv returned %d)", recv_len);
297
+ break;
298
+ }
299
+ current_count += recv_len;
300
+ }
301
+ if (current_count < entire_len) {
302
+ debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);
303
+ }
304
+ }
305
+
306
+ if (current_count >= sizeof(uint64_t)) {
307
+ param1 = le64toh(*(uint64_t*)(buf));
308
+ }
309
+
310
+ debug_info("packet data size = %i", current_count);
311
+ if (current_count > 256) {
312
+ debug_info("packet data follows (256/%u)", current_count);
313
+ debug_buffer(buf, 256);
314
+ } else {
315
+ debug_info("packet data follows");
316
+ debug_buffer(buf, current_count);
317
+ }
318
+
319
+ /* check operation types */
320
+ if (header.operation == AFC_OP_STATUS) {
321
+ /* status response */
322
+ debug_info("got a status response, code=%lld", param1);
323
+
324
+ if (param1 != AFC_E_SUCCESS) {
325
+ /* error status */
326
+ /* free buffer */
327
+ free(buf);
328
+ return (afc_error_t)param1;
329
+ }
330
+ } else if (header.operation == AFC_OP_DATA) {
331
+ /* data response */
332
+ debug_info("got a data response");
333
+ } else if (header.operation == AFC_OP_FILE_OPEN_RES) {
334
+ /* file handle response */
335
+ debug_info("got a file handle response, handle=%lld", param1);
336
+ } else if (header.operation == AFC_OP_FILE_TELL_RES) {
337
+ /* tell response */
338
+ debug_info("got a tell response, position=%lld", param1);
339
+ } else {
340
+ /* unknown operation code received */
341
+ free(buf);
342
+
343
+ debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
344
+ #ifndef _WIN32
345
+ fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
346
+ #endif
347
+
348
+ return AFC_E_OP_NOT_SUPPORTED;
349
+ }
350
+
351
+ if (bytes) {
352
+ *bytes = buf;
353
+ } else {
354
+ free(buf);
355
+ }
356
+
357
+ *bytes_recv = current_count;
358
+ return AFC_E_SUCCESS;
359
+ }
360
+
361
+ /**
362
+ * Returns counts of null characters within a string.
363
+ */
364
+ static uint32_t count_nullspaces(const char *string, uint32_t number)
365
+ {
366
+ uint32_t i = 0, nulls = 0;
367
+
368
+ for (i = 0; i < number; i++) {
369
+ if (string[i] == '\0')
370
+ nulls++;
371
+ }
372
+
373
+ return nulls;
374
+ }
375
+
376
+ /**
377
+ * Splits a string of tokens by null characters and returns each token in a
378
+ * char array/list.
379
+ *
380
+ * @param tokens The characters to split into a list.
381
+ * @param length The length of the tokens string.
382
+ *
383
+ * @return A char ** list with each token found in the string. The caller is
384
+ * responsible for freeing the memory.
385
+ */
386
+ static char **make_strings_list(char *tokens, uint32_t length)
387
+ {
388
+ uint32_t nulls = 0, i = 0, j = 0;
389
+ char **list = NULL;
390
+
391
+ if (!tokens || !length)
392
+ return NULL;
393
+
394
+ nulls = count_nullspaces(tokens, length);
395
+ list = (char **) malloc(sizeof(char *) * (nulls + 1));
396
+ for (i = 0; i < nulls; i++) {
397
+ list[i] = strdup(tokens + j);
398
+ j += strlen(list[i]) + 1;
399
+ }
400
+ list[i] = NULL;
401
+
402
+ return list;
403
+ }
404
+
405
+ static plist_t *make_dictionary(char *tokens, size_t length)
406
+ {
407
+ size_t j = 0;
408
+ plist_t dict = NULL;
409
+
410
+ if (!tokens || !length)
411
+ return NULL;
412
+
413
+ dict = plist_new_dict();
414
+
415
+ while (j < length) {
416
+ size_t key_len = strnlen(tokens + j, length - j);
417
+ if (j + key_len >= length) {
418
+ plist_free(dict);
419
+ return NULL;
420
+ }
421
+ char* key = tokens + j;
422
+ j += key_len + 1;
423
+
424
+ if (j >= length) {
425
+ plist_free(dict);
426
+ return NULL;
427
+ }
428
+
429
+ size_t val_len = strnlen(tokens + j, length - j);
430
+ if (j + val_len >= length) {
431
+ plist_free(dict);
432
+ return NULL;
433
+ }
434
+ char* val = tokens + j;
435
+ j += val_len + 1;
436
+
437
+ char* endp = NULL;
438
+ unsigned long long u64val = strtoull(val, &endp, 10);
439
+ if (endp && *endp == '\0') {
440
+ plist_dict_set_item(dict, key, plist_new_uint(u64val));
441
+ } else {
442
+ plist_dict_set_item(dict, key, plist_new_string(val));
443
+ }
444
+ }
445
+
446
+ return dict;
447
+ }
448
+
449
+ static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
450
+ {
451
+ if (data_len > client->packet_extra) {
452
+ client->packet_extra = (data_len & ~8) + 8;
453
+ AFCPacket* newpkt = (AFCPacket*)realloc(client->afc_packet, sizeof(AFCPacket) + client->packet_extra);
454
+ if (!newpkt) {
455
+ return -1;
456
+ }
457
+ client->afc_packet = newpkt;
458
+ }
459
+ return 0;
460
+ }
461
+
462
+ #define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket))
463
+
464
+ afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information)
465
+ {
466
+ uint32_t bytes = 0;
467
+ char *data = NULL, **list_loc = NULL;
468
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
469
+
470
+ if (!client || !path || !directory_information || (directory_information && *directory_information))
471
+ return AFC_E_INVALID_ARG;
472
+
473
+ afc_lock(client);
474
+
475
+ uint32_t data_len = (uint32_t)strlen(path)+1;
476
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
477
+ afc_unlock(client);
478
+ debug_info("Failed to realloc packet buffer");
479
+ return AFC_E_NO_MEM;
480
+ }
481
+
482
+ /* Send the command */
483
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
484
+ ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, data_len, NULL, 0, &bytes);
485
+ if (ret != AFC_E_SUCCESS) {
486
+ afc_unlock(client);
487
+ return AFC_E_NOT_ENOUGH_DATA;
488
+ }
489
+ /* Receive the data */
490
+ ret = afc_receive_data(client, &data, &bytes);
491
+ if (ret != AFC_E_SUCCESS) {
492
+ if (data)
493
+ free(data);
494
+ afc_unlock(client);
495
+ return ret;
496
+ }
497
+ /* Parse the data */
498
+ list_loc = make_strings_list(data, bytes);
499
+ if (data)
500
+ free(data);
501
+
502
+ afc_unlock(client);
503
+ *directory_information = list_loc;
504
+
505
+ return ret;
506
+ }
507
+
508
+ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
509
+ {
510
+ uint32_t bytes = 0;
511
+ char *data = NULL, **list = NULL;
512
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
513
+
514
+ if (!client || !device_information)
515
+ return AFC_E_INVALID_ARG;
516
+
517
+ afc_lock(client);
518
+
519
+ /* Send the command */
520
+ ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
521
+ if (ret != AFC_E_SUCCESS) {
522
+ afc_unlock(client);
523
+ return AFC_E_NOT_ENOUGH_DATA;
524
+ }
525
+ /* Receive the data */
526
+ ret = afc_receive_data(client, &data, &bytes);
527
+ if (ret != AFC_E_SUCCESS) {
528
+ if (data)
529
+ free(data);
530
+ afc_unlock(client);
531
+ return ret;
532
+ }
533
+ /* Parse the data */
534
+ list = make_strings_list(data, bytes);
535
+ if (data)
536
+ free(data);
537
+
538
+ afc_unlock(client);
539
+
540
+ *device_information = list;
541
+
542
+ return ret;
543
+ }
544
+
545
+ afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information)
546
+ {
547
+ uint32_t bytes = 0;
548
+ char *data = NULL;
549
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
550
+
551
+ if (!client || !device_information)
552
+ return AFC_E_INVALID_ARG;
553
+
554
+ afc_lock(client);
555
+
556
+ /* Send the command */
557
+ ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
558
+ if (ret != AFC_E_SUCCESS) {
559
+ afc_unlock(client);
560
+ return AFC_E_NOT_ENOUGH_DATA;
561
+ }
562
+ /* Receive the data */
563
+ ret = afc_receive_data(client, &data, &bytes);
564
+ if (ret != AFC_E_SUCCESS) {
565
+ if (data)
566
+ free(data);
567
+ afc_unlock(client);
568
+ return ret;
569
+ }
570
+ /* Parse the data */
571
+ *device_information = make_dictionary(data, bytes);
572
+ free(data);
573
+
574
+ afc_unlock(client);
575
+
576
+ return ret;
577
+ }
578
+
579
+ afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
580
+ {
581
+ afc_error_t ret = AFC_E_INTERNAL_ERROR;
582
+ char **kvps, **ptr;
583
+
584
+ *value = NULL;
585
+ if (key == NULL)
586
+ return AFC_E_INVALID_ARG;
587
+
588
+ ret = afc_get_device_info(client, &kvps);
589
+ if (ret != AFC_E_SUCCESS)
590
+ return ret;
591
+
592
+ for (ptr = kvps; *ptr; ptr++) {
593
+ if (!strcmp(*ptr, key)) {
594
+ *value = strdup(*(ptr+1));
595
+ break;
596
+ }
597
+ }
598
+ for (ptr = kvps; *ptr; ptr++) {
599
+ free(*ptr);
600
+ }
601
+ free(kvps);
602
+
603
+ return ret;
604
+ }
605
+
606
+ afc_error_t afc_remove_path(afc_client_t client, const char *path)
607
+ {
608
+ uint32_t bytes = 0;
609
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
610
+
611
+ if (!client || !path || !client->afc_packet || !client->parent)
612
+ return AFC_E_INVALID_ARG;
613
+
614
+ afc_lock(client);
615
+
616
+ uint32_t data_len = (uint32_t)strlen(path)+1;
617
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
618
+ afc_unlock(client);
619
+ debug_info("Failed to realloc packet buffer");
620
+ return AFC_E_NO_MEM;
621
+ }
622
+
623
+ /* Send command */
624
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
625
+ ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, data_len, NULL, 0, &bytes);
626
+ if (ret != AFC_E_SUCCESS) {
627
+ afc_unlock(client);
628
+ return AFC_E_NOT_ENOUGH_DATA;
629
+ }
630
+ /* Receive response */
631
+ ret = afc_receive_data(client, NULL, &bytes);
632
+
633
+ /* special case; unknown error actually means directory not empty */
634
+ if (ret == AFC_E_UNKNOWN_ERROR)
635
+ ret = AFC_E_DIR_NOT_EMPTY;
636
+
637
+ afc_unlock(client);
638
+
639
+ return ret;
640
+ }
641
+
642
+ afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to)
643
+ {
644
+ if (!client || !from || !to || !client->afc_packet || !client->parent)
645
+ return AFC_E_INVALID_ARG;
646
+
647
+ uint32_t bytes = 0;
648
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
649
+
650
+ size_t from_len = strlen(from);
651
+ size_t to_len = strlen(to);
652
+
653
+ afc_lock(client);
654
+
655
+ uint32_t data_len = (uint32_t)(from_len+1 + to_len+1);
656
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
657
+ afc_unlock(client);
658
+ debug_info("Failed to realloc packet buffer");
659
+ return AFC_E_NO_MEM;
660
+ }
661
+
662
+ /* Send command */
663
+ memcpy(AFC_PACKET_DATA_PTR, from, from_len+1);
664
+ memcpy(AFC_PACKET_DATA_PTR + from_len+1, to, to_len+1);
665
+ ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, data_len, NULL, 0, &bytes);
666
+ if (ret != AFC_E_SUCCESS) {
667
+ afc_unlock(client);
668
+ return AFC_E_NOT_ENOUGH_DATA;
669
+ }
670
+ /* Receive response */
671
+ ret = afc_receive_data(client, NULL, &bytes);
672
+
673
+ afc_unlock(client);
674
+
675
+ return ret;
676
+ }
677
+
678
+ afc_error_t afc_make_directory(afc_client_t client, const char *path)
679
+ {
680
+ uint32_t bytes = 0;
681
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
682
+
683
+ if (!client)
684
+ return AFC_E_INVALID_ARG;
685
+
686
+ afc_lock(client);
687
+
688
+ uint32_t data_len = (uint32_t)strlen(path)+1;
689
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
690
+ afc_unlock(client);
691
+ debug_info("Failed to realloc packet buffer");
692
+ return AFC_E_NO_MEM;
693
+ }
694
+
695
+ /* Send command */
696
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
697
+ ret = afc_dispatch_packet(client, AFC_OP_MAKE_DIR, data_len, NULL, 0, &bytes);
698
+ if (ret != AFC_E_SUCCESS) {
699
+ afc_unlock(client);
700
+ return AFC_E_NOT_ENOUGH_DATA;
701
+ }
702
+ /* Receive response */
703
+ ret = afc_receive_data(client, NULL, &bytes);
704
+
705
+ afc_unlock(client);
706
+
707
+ return ret;
708
+ }
709
+
710
+ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information)
711
+ {
712
+ char *received = NULL;
713
+ uint32_t bytes = 0;
714
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
715
+
716
+ if (!client || !path || !file_information)
717
+ return AFC_E_INVALID_ARG;
718
+
719
+ afc_lock(client);
720
+
721
+ uint32_t data_len = (uint32_t)strlen(path)+1;
722
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
723
+ afc_unlock(client);
724
+ debug_info("Failed to realloc packet buffer");
725
+ return AFC_E_NO_MEM;
726
+ }
727
+
728
+ /* Send command */
729
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
730
+ ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
731
+ if (ret != AFC_E_SUCCESS) {
732
+ afc_unlock(client);
733
+ return AFC_E_NOT_ENOUGH_DATA;
734
+ }
735
+
736
+ /* Receive data */
737
+ ret = afc_receive_data(client, &received, &bytes);
738
+ if (received) {
739
+ *file_information = make_strings_list(received, bytes);
740
+ free(received);
741
+ }
742
+
743
+ afc_unlock(client);
744
+
745
+ return ret;
746
+ }
747
+
748
+ afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information)
749
+ {
750
+ char *received = NULL;
751
+ uint32_t bytes = 0;
752
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
753
+
754
+ if (!client || !path || !file_information)
755
+ return AFC_E_INVALID_ARG;
756
+
757
+ afc_lock(client);
758
+
759
+ uint32_t data_len = (uint32_t)strlen(path)+1;
760
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
761
+ afc_unlock(client);
762
+ debug_info("Failed to realloc packet buffer");
763
+ return AFC_E_NO_MEM;
764
+ }
765
+
766
+ /* Send command */
767
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
768
+ ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
769
+ if (ret != AFC_E_SUCCESS) {
770
+ afc_unlock(client);
771
+ return AFC_E_NOT_ENOUGH_DATA;
772
+ }
773
+
774
+ /* Receive data */
775
+ ret = afc_receive_data(client, &received, &bytes);
776
+ if (received) {
777
+ *file_information = make_dictionary(received, bytes);
778
+ free(received);
779
+ }
780
+
781
+ afc_unlock(client);
782
+
783
+ return ret;
784
+ }
785
+
786
+ afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
787
+ {
788
+ if (!client || !client->parent || !client->afc_packet)
789
+ return AFC_E_INVALID_ARG;
790
+
791
+ //uint64_t file_mode_loc = htole64(file_mode);
792
+ uint32_t bytes = 0;
793
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
794
+
795
+ /* set handle to 0 so in case an error occurs, the handle is invalid */
796
+ *handle = 0;
797
+
798
+ afc_lock(client);
799
+
800
+ uint32_t data_len = (uint32_t)(strlen(filename)+1 + 8);
801
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
802
+ afc_unlock(client);
803
+ debug_info("Failed to realloc packet buffer");
804
+ return AFC_E_NO_MEM;
805
+ }
806
+
807
+ /* Send command */
808
+ //memcpy(AFC_PACKET_DATA_PTR, &file_mode_loc, 8);
809
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(file_mode);
810
+ memcpy(AFC_PACKET_DATA_PTR + 8, filename, data_len-8);
811
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data_len, NULL, 0, &bytes);
812
+ if (ret != AFC_E_SUCCESS) {
813
+ debug_info("Didn't receive a response to the command");
814
+ afc_unlock(client);
815
+ return AFC_E_NOT_ENOUGH_DATA;
816
+ }
817
+ /* Receive the data */
818
+ char* data = NULL;
819
+ ret = afc_receive_data(client, &data, &bytes);
820
+ if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) {
821
+ afc_unlock(client);
822
+
823
+ /* Get the file handle */
824
+ memcpy(handle, data, sizeof(uint64_t));
825
+ free(data);
826
+ return ret;
827
+ }
828
+ /* in case memory was allocated but no data received or an error occurred */
829
+ free(data);
830
+
831
+ debug_info("Didn't get any further data");
832
+
833
+ afc_unlock(client);
834
+
835
+ return ret;
836
+ }
837
+
838
+ afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
839
+ {
840
+ char *input = NULL;
841
+ uint32_t current_count = 0, bytes_loc = 0;
842
+ struct readinfo {
843
+ uint64_t handle;
844
+ uint64_t size;
845
+ };
846
+ afc_error_t ret = AFC_E_SUCCESS;
847
+
848
+ if (!client || !client->afc_packet || !client->parent || handle == 0)
849
+ return AFC_E_INVALID_ARG;
850
+ debug_info("called for length %i", length);
851
+
852
+ //uint32_t data_len = 8 + 8;
853
+
854
+ afc_lock(client);
855
+
856
+ /* Send the read command */
857
+ struct readinfo* readinfo = (struct readinfo*)(AFC_PACKET_DATA_PTR);
858
+ readinfo->handle = handle;
859
+ readinfo->size = htole64(length);
860
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_READ, sizeof(struct readinfo), NULL, 0, &bytes_loc);
861
+ if (ret != AFC_E_SUCCESS) {
862
+ afc_unlock(client);
863
+ return AFC_E_NOT_ENOUGH_DATA;
864
+ }
865
+ /* Receive the data */
866
+ ret = afc_receive_data(client, &input, &bytes_loc);
867
+ debug_info("afc_receive_data returned error: %d", ret);
868
+ debug_info("bytes returned: %i", bytes_loc);
869
+ if (ret != AFC_E_SUCCESS) {
870
+ afc_unlock(client);
871
+ return ret;
872
+ }
873
+ if (bytes_loc == 0) {
874
+ if (input)
875
+ free(input);
876
+ afc_unlock(client);
877
+ *bytes_read = current_count;
878
+ /* FIXME: check that's actually a success */
879
+ return ret;
880
+ }
881
+ if (input) {
882
+ debug_info("%d", bytes_loc);
883
+ memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
884
+ free(input);
885
+ input = NULL;
886
+ current_count += (bytes_loc > length) ? length : bytes_loc;
887
+ }
888
+
889
+ afc_unlock(client);
890
+ *bytes_read = current_count;
891
+ return ret;
892
+ }
893
+
894
+ afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written)
895
+ {
896
+ uint32_t current_count = 0;
897
+ uint32_t bytes_loc = 0;
898
+ afc_error_t ret = AFC_E_SUCCESS;
899
+
900
+ if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0))
901
+ return AFC_E_INVALID_ARG;
902
+
903
+ uint32_t data_len = 8;
904
+
905
+ afc_lock(client);
906
+
907
+ debug_info("Write length: %i", length);
908
+
909
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
910
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_WRITE, data_len, data, length, &bytes_loc);
911
+
912
+ current_count += bytes_loc - (sizeof(AFCPacket) + 8);
913
+
914
+ if (ret != AFC_E_SUCCESS) {
915
+ afc_unlock(client);
916
+ *bytes_written = current_count;
917
+ return AFC_E_SUCCESS;
918
+ }
919
+
920
+ ret = afc_receive_data(client, NULL, &bytes_loc);
921
+ afc_unlock(client);
922
+ if (ret != AFC_E_SUCCESS) {
923
+ debug_info("Failed to receive reply (%d)", ret);
924
+ }
925
+ *bytes_written = current_count;
926
+ return ret;
927
+ }
928
+
929
+ afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
930
+ {
931
+ uint32_t bytes = 0;
932
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
933
+
934
+ if (!client || (handle == 0))
935
+ return AFC_E_INVALID_ARG;
936
+
937
+ uint32_t data_len = 8;
938
+
939
+ afc_lock(client);
940
+
941
+ debug_info("File handle %i", handle);
942
+
943
+ /* Send command */
944
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
945
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, data_len, NULL, 0, &bytes);
946
+
947
+ if (ret != AFC_E_SUCCESS) {
948
+ afc_unlock(client);
949
+ return AFC_E_UNKNOWN_ERROR;
950
+ }
951
+
952
+ /* Receive the response */
953
+ ret = afc_receive_data(client, NULL, &bytes);
954
+
955
+ afc_unlock(client);
956
+
957
+ return ret;
958
+ }
959
+
960
+ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
961
+ {
962
+ uint32_t bytes = 0;
963
+ struct lockinfo {
964
+ uint64_t handle;
965
+ uint64_t op;
966
+ };
967
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
968
+
969
+ if (!client || (handle == 0))
970
+ return AFC_E_INVALID_ARG;
971
+
972
+ afc_lock(client);
973
+
974
+ debug_info("file handle %i", handle);
975
+
976
+ /* Send command */
977
+ struct lockinfo* lockinfo = (struct lockinfo*)(AFC_PACKET_DATA_PTR);
978
+ lockinfo->handle = handle;
979
+ lockinfo->op = htole64(operation);
980
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, sizeof(struct lockinfo), NULL, 0, &bytes);
981
+ if (ret != AFC_E_SUCCESS) {
982
+ afc_unlock(client);
983
+ debug_info("could not send lock command");
984
+ return AFC_E_UNKNOWN_ERROR;
985
+ }
986
+ /* Receive the response */
987
+ ret = afc_receive_data(client, NULL, &bytes);
988
+
989
+ afc_unlock(client);
990
+
991
+ return ret;
992
+ }
993
+
994
+ afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
995
+ {
996
+ uint32_t bytes = 0;
997
+ struct seekinfo {
998
+ uint64_t handle;
999
+ uint64_t whence;
1000
+ int64_t offset;
1001
+ };
1002
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1003
+
1004
+ if (!client || (handle == 0))
1005
+ return AFC_E_INVALID_ARG;
1006
+
1007
+ afc_lock(client);
1008
+
1009
+ /* Send the command */
1010
+ struct seekinfo* seekinfo = (struct seekinfo*)(AFC_PACKET_DATA_PTR);
1011
+ seekinfo->handle = handle;
1012
+ seekinfo->whence = htole64(whence);
1013
+ seekinfo->offset = (int64_t)htole64(offset);
1014
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, sizeof(struct seekinfo), NULL, 0, &bytes);
1015
+
1016
+ if (ret != AFC_E_SUCCESS) {
1017
+ afc_unlock(client);
1018
+ return AFC_E_NOT_ENOUGH_DATA;
1019
+ }
1020
+ /* Receive response */
1021
+ ret = afc_receive_data(client, NULL, &bytes);
1022
+
1023
+ afc_unlock(client);
1024
+
1025
+ return ret;
1026
+ }
1027
+
1028
+ afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
1029
+ {
1030
+ char *buffer = NULL;
1031
+ uint32_t bytes = 0;
1032
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1033
+
1034
+ if (!client || (handle == 0))
1035
+ return AFC_E_INVALID_ARG;
1036
+
1037
+ uint32_t data_len = 8;
1038
+
1039
+ afc_lock(client);
1040
+
1041
+ /* Send the command */
1042
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
1043
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, data_len, NULL, 0, &bytes);
1044
+ if (ret != AFC_E_SUCCESS) {
1045
+ afc_unlock(client);
1046
+ return AFC_E_NOT_ENOUGH_DATA;
1047
+ }
1048
+
1049
+ /* Receive the data */
1050
+ ret = afc_receive_data(client, &buffer, &bytes);
1051
+ if (bytes > 0 && buffer) {
1052
+ /* Get the position */
1053
+ memcpy(position, buffer, sizeof(uint64_t));
1054
+ *position = le64toh(*position);
1055
+ }
1056
+ free(buffer);
1057
+
1058
+ afc_unlock(client);
1059
+
1060
+ return ret;
1061
+ }
1062
+
1063
+ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
1064
+ {
1065
+ uint32_t bytes = 0;
1066
+ struct truncinfo {
1067
+ uint64_t handle;
1068
+ uint64_t newsize;
1069
+ };
1070
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1071
+
1072
+ if (!client || (handle == 0))
1073
+ return AFC_E_INVALID_ARG;
1074
+
1075
+ afc_lock(client);
1076
+
1077
+ /* Send command */
1078
+ struct truncinfo* truncinfo = (struct truncinfo*)(AFC_PACKET_DATA_PTR);
1079
+ truncinfo->handle = handle;
1080
+ truncinfo->newsize = htole64(newsize);
1081
+ ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, sizeof(struct truncinfo), NULL, 0, &bytes);
1082
+
1083
+ if (ret != AFC_E_SUCCESS) {
1084
+ afc_unlock(client);
1085
+ return AFC_E_NOT_ENOUGH_DATA;
1086
+ }
1087
+ /* Receive response */
1088
+ ret = afc_receive_data(client, NULL, &bytes);
1089
+
1090
+ afc_unlock(client);
1091
+
1092
+ return ret;
1093
+ }
1094
+
1095
+ afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize)
1096
+ {
1097
+ if (!client || !path || !client->afc_packet || !client->parent)
1098
+ return AFC_E_INVALID_ARG;
1099
+
1100
+ uint32_t bytes = 0;
1101
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1102
+
1103
+ afc_lock(client);
1104
+
1105
+ uint32_t data_len = 8 + (uint32_t)(strlen(path)+1);
1106
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
1107
+ afc_unlock(client);
1108
+ debug_info("Failed to realloc packet buffer");
1109
+ return AFC_E_NO_MEM;
1110
+ }
1111
+
1112
+ /* Send command */
1113
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(newsize);
1114
+ memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
1115
+ ret = afc_dispatch_packet(client, AFC_OP_TRUNCATE, data_len, NULL, 0, &bytes);
1116
+ if (ret != AFC_E_SUCCESS) {
1117
+ afc_unlock(client);
1118
+ return AFC_E_NOT_ENOUGH_DATA;
1119
+ }
1120
+ /* Receive response */
1121
+ ret = afc_receive_data(client, NULL, &bytes);
1122
+
1123
+ afc_unlock(client);
1124
+
1125
+ return ret;
1126
+ }
1127
+
1128
+ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname)
1129
+ {
1130
+ if (!client || !target || !linkname || !client->afc_packet || !client->parent)
1131
+ return AFC_E_INVALID_ARG;
1132
+
1133
+ uint32_t bytes = 0;
1134
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1135
+
1136
+ size_t target_len = strlen(target);
1137
+ size_t link_len = strlen(linkname);
1138
+
1139
+ afc_lock(client);
1140
+
1141
+ uint32_t data_len = 8 + target_len + 1 + link_len + 1;
1142
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
1143
+ afc_unlock(client);
1144
+ debug_info("Failed to realloc packet buffer");
1145
+ return AFC_E_NO_MEM;
1146
+ }
1147
+
1148
+ debug_info("link type: %lld", htole64(linktype));
1149
+ debug_info("target: %s, length:%d", target, target_len);
1150
+ debug_info("linkname: %s, length:%d", linkname, link_len);
1151
+
1152
+ /* Send command */
1153
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(linktype);
1154
+ memcpy(AFC_PACKET_DATA_PTR + 8, target, target_len + 1);
1155
+ memcpy(AFC_PACKET_DATA_PTR + 8 + target_len + 1, linkname, link_len + 1);
1156
+ ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, data_len, NULL, 0, &bytes);
1157
+ if (ret != AFC_E_SUCCESS) {
1158
+ afc_unlock(client);
1159
+ return AFC_E_NOT_ENOUGH_DATA;
1160
+ }
1161
+ /* Receive response */
1162
+ ret = afc_receive_data(client, NULL, &bytes);
1163
+
1164
+ afc_unlock(client);
1165
+
1166
+ return ret;
1167
+ }
1168
+
1169
+ afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime)
1170
+ {
1171
+ if (!client || !path || !client->afc_packet || !client->parent)
1172
+ return AFC_E_INVALID_ARG;
1173
+
1174
+ uint32_t bytes = 0;
1175
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1176
+
1177
+ afc_lock(client);
1178
+
1179
+ uint32_t data_len = 8 + strlen(path) + 1;
1180
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
1181
+ afc_unlock(client);
1182
+ debug_info("Failed to realloc packet buffer");
1183
+ return AFC_E_NO_MEM;
1184
+ }
1185
+
1186
+ /* Send command */
1187
+ *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(mtime);
1188
+ memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
1189
+ ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_MOD_TIME, data_len, NULL, 0, &bytes);
1190
+ if (ret != AFC_E_SUCCESS) {
1191
+ afc_unlock(client);
1192
+ return AFC_E_NOT_ENOUGH_DATA;
1193
+ }
1194
+ /* Receive response */
1195
+ ret = afc_receive_data(client, NULL, &bytes);
1196
+
1197
+ afc_unlock(client);
1198
+
1199
+ return ret;
1200
+ }
1201
+
1202
+ afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path)
1203
+ {
1204
+ uint32_t bytes = 0;
1205
+ afc_error_t ret = AFC_E_UNKNOWN_ERROR;
1206
+
1207
+ if (!client || !path || !client->afc_packet || !client->parent)
1208
+ return AFC_E_INVALID_ARG;
1209
+
1210
+ afc_lock(client);
1211
+
1212
+ uint32_t data_len = strlen(path) + 1;
1213
+ if (_afc_check_packet_buffer(client, data_len) < 0) {
1214
+ afc_unlock(client);
1215
+ debug_info("Failed to realloc packet buffer");
1216
+ return AFC_E_NO_MEM;
1217
+ }
1218
+
1219
+ /* Send command */
1220
+ memcpy(AFC_PACKET_DATA_PTR, path, data_len);
1221
+ ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH_AND_CONTENTS, data_len, NULL, 0, &bytes);
1222
+ if (ret != AFC_E_SUCCESS) {
1223
+ afc_unlock(client);
1224
+ return AFC_E_NOT_ENOUGH_DATA;
1225
+ }
1226
+ /* Receive response */
1227
+ ret = afc_receive_data(client, NULL, &bytes);
1228
+
1229
+ afc_unlock(client);
1230
+
1231
+ return ret;
1232
+ }
1233
+
1234
+ afc_error_t afc_dictionary_free(char **dictionary)
1235
+ {
1236
+ int i = 0;
1237
+
1238
+ if (!dictionary)
1239
+ return AFC_E_INVALID_ARG;
1240
+
1241
+ for (i = 0; dictionary[i]; i++) {
1242
+ free(dictionary[i]);
1243
+ }
1244
+ free(dictionary);
1245
+
1246
+ return AFC_E_SUCCESS;
1247
+ }
1248
+
1249
+ const char* afc_strerror(afc_error_t err)
1250
+ {
1251
+ switch (err) {
1252
+ case AFC_E_SUCCESS:
1253
+ return "Success";
1254
+ case AFC_E_UNKNOWN_ERROR:
1255
+ return "Unknown Error";
1256
+ case AFC_E_OP_HEADER_INVALID:
1257
+ return "Operation header invalid";
1258
+ case AFC_E_NO_RESOURCES:
1259
+ return "No resources";
1260
+ case AFC_E_READ_ERROR:
1261
+ return "Read error";
1262
+ case AFC_E_WRITE_ERROR:
1263
+ return "Write error";
1264
+ case AFC_E_UNKNOWN_PACKET_TYPE:
1265
+ return "Unknown packet type";
1266
+ case AFC_E_INVALID_ARG:
1267
+ return "Invalid argument";
1268
+ case AFC_E_OBJECT_NOT_FOUND:
1269
+ return "Not found";
1270
+ case AFC_E_OBJECT_IS_DIR:
1271
+ return "Object is a directory";
1272
+ case AFC_E_PERM_DENIED:
1273
+ return "Permission denied";
1274
+ case AFC_E_SERVICE_NOT_CONNECTED:
1275
+ return "Service not connected";
1276
+ case AFC_E_OP_TIMEOUT:
1277
+ return "Timeout";
1278
+ case AFC_E_TOO_MUCH_DATA:
1279
+ return "Too much data";
1280
+ case AFC_E_END_OF_DATA:
1281
+ return "End of data";
1282
+ case AFC_E_OP_NOT_SUPPORTED:
1283
+ return "Operation not supported";
1284
+ case AFC_E_OBJECT_EXISTS:
1285
+ return "Object exists";
1286
+ case AFC_E_OBJECT_BUSY:
1287
+ return "Object busy";
1288
+ case AFC_E_NO_SPACE_LEFT:
1289
+ return "No space left on device";
1290
+ case AFC_E_OP_WOULD_BLOCK:
1291
+ return "Operation would block";
1292
+ case AFC_E_IO_ERROR:
1293
+ return "I/O error";
1294
+ case AFC_E_OP_INTERRUPTED:
1295
+ return "Operation interrupted";
1296
+ case AFC_E_OP_IN_PROGRESS:
1297
+ return "Operation on progress";
1298
+ case AFC_E_INTERNAL_ERROR:
1299
+ return "Internal error";
1300
+ case AFC_E_MUX_ERROR:
1301
+ return "MUX error";
1302
+ case AFC_E_NO_MEM:
1303
+ return "Out of memory";
1304
+ case AFC_E_NOT_ENOUGH_DATA:
1305
+ return "Not enough data";
1306
+ case AFC_E_DIR_NOT_EMPTY:
1307
+ return "Directory not empty";
1308
+ case AFC_E_FORCE_SIGNED_TYPE:
1309
+ return "Force signed type";
1310
+ default:
1311
+ break;
1312
+ }
1313
+ return "Unknown Error";
1314
+ }
afc.h ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * afc.h
3
+ * Defines and structs and the like for the built-in AFC client
4
+ *
5
+ * Copyright (c) 2014 Martin Szulecki All Rights Reserved.
6
+ * Copyright (c) 2008 Zach C. All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+ #ifndef __AFC_H
24
+ #define __AFC_H
25
+
26
+ #include <stdint.h>
27
+
28
+ #include "libimobiledevice/afc.h"
29
+ #include "service.h"
30
+ #include "endianness.h"
31
+ #include <libimobiledevice-glue/thread.h>
32
+
33
+ #define AFC_MAGIC "CFA6LPAA"
34
+ #define AFC_MAGIC_LEN (8)
35
+
36
+ typedef struct {
37
+ char magic[AFC_MAGIC_LEN];
38
+ uint64_t entire_length, this_length, packet_num, operation;
39
+ } AFCPacket;
40
+
41
+ #define AFCPacket_to_LE(x) \
42
+ (x)->entire_length = htole64((x)->entire_length); \
43
+ (x)->this_length = htole64((x)->this_length); \
44
+ (x)->packet_num = htole64((x)->packet_num); \
45
+ (x)->operation = htole64((x)->operation);
46
+
47
+ #define AFCPacket_from_LE(x) \
48
+ (x)->entire_length = le64toh((x)->entire_length); \
49
+ (x)->this_length = le64toh((x)->this_length); \
50
+ (x)->packet_num = le64toh((x)->packet_num); \
51
+ (x)->operation = le64toh((x)->operation);
52
+
53
+ struct afc_client_private {
54
+ service_client_t parent;
55
+ AFCPacket *afc_packet;
56
+ uint32_t packet_extra;
57
+ mutex_t mutex;
58
+ int free_parent;
59
+ };
60
+
61
+ /* AFC Operations */
62
+ enum {
63
+ AFC_OP_INVALID = 0x00000000, /* Invalid */
64
+ AFC_OP_STATUS = 0x00000001, /* Status */
65
+ AFC_OP_DATA = 0x00000002, /* Data */
66
+ AFC_OP_READ_DIR = 0x00000003, /* ReadDir */
67
+ AFC_OP_READ_FILE = 0x00000004, /* ReadFile */
68
+ AFC_OP_WRITE_FILE = 0x00000005, /* WriteFile */
69
+ AFC_OP_WRITE_PART = 0x00000006, /* WritePart */
70
+ AFC_OP_TRUNCATE = 0x00000007, /* TruncateFile */
71
+ AFC_OP_REMOVE_PATH = 0x00000008, /* RemovePath */
72
+ AFC_OP_MAKE_DIR = 0x00000009, /* MakeDir */
73
+ AFC_OP_GET_FILE_INFO = 0x0000000A, /* GetFileInfo */
74
+ AFC_OP_GET_DEVINFO = 0x0000000B, /* GetDeviceInfo */
75
+ AFC_OP_WRITE_FILE_ATOM = 0x0000000C, /* WriteFileAtomic (tmp file+rename) */
76
+ AFC_OP_FILE_OPEN = 0x0000000D, /* FileRefOpen */
77
+ AFC_OP_FILE_OPEN_RES = 0x0000000E, /* FileRefOpenResult */
78
+ AFC_OP_FILE_READ = 0x0000000F, /* FileRefRead */
79
+ AFC_OP_FILE_WRITE = 0x00000010, /* FileRefWrite */
80
+ AFC_OP_FILE_SEEK = 0x00000011, /* FileRefSeek */
81
+ AFC_OP_FILE_TELL = 0x00000012, /* FileRefTell */
82
+ AFC_OP_FILE_TELL_RES = 0x00000013, /* FileRefTellResult */
83
+ AFC_OP_FILE_CLOSE = 0x00000014, /* FileRefClose */
84
+ AFC_OP_FILE_SET_SIZE = 0x00000015, /* FileRefSetFileSize (ftruncate) */
85
+ AFC_OP_GET_CON_INFO = 0x00000016, /* GetConnectionInfo */
86
+ AFC_OP_SET_CON_OPTIONS = 0x00000017, /* SetConnectionOptions */
87
+ AFC_OP_RENAME_PATH = 0x00000018, /* RenamePath */
88
+ AFC_OP_SET_FS_BS = 0x00000019, /* SetFSBlockSize (0x800000) */
89
+ AFC_OP_SET_SOCKET_BS = 0x0000001A, /* SetSocketBlockSize (0x800000) */
90
+ AFC_OP_FILE_LOCK = 0x0000001B, /* FileRefLock */
91
+ AFC_OP_MAKE_LINK = 0x0000001C, /* MakeLink */
92
+ AFC_OP_GET_FILE_HASH = 0x0000001D, /* GetFileHash */
93
+ AFC_OP_SET_FILE_MOD_TIME = 0x0000001E, /* SetModTime */
94
+ AFC_OP_GET_FILE_HASH_RANGE = 0x0000001F, /* GetFileHashWithRange */
95
+ /* iOS 6+ */
96
+ AFC_OP_FILE_SET_IMMUTABLE_HINT = 0x00000020, /* FileRefSetImmutableHint */
97
+ AFC_OP_GET_SIZE_OF_PATH_CONTENTS = 0x00000021, /* GetSizeOfPathContents */
98
+ AFC_OP_REMOVE_PATH_AND_CONTENTS = 0x00000022, /* RemovePathAndContents */
99
+ AFC_OP_DIR_OPEN = 0x00000023, /* DirectoryEnumeratorRefOpen */
100
+ AFC_OP_DIR_OPEN_RESULT = 0x00000024, /* DirectoryEnumeratorRefOpenResult */
101
+ AFC_OP_DIR_READ = 0x00000025, /* DirectoryEnumeratorRefRead */
102
+ AFC_OP_DIR_CLOSE = 0x00000026, /* DirectoryEnumeratorRefClose */
103
+ /* iOS 7+ */
104
+ AFC_OP_FILE_READ_OFFSET = 0x00000027, /* FileRefReadWithOffset */
105
+ AFC_OP_FILE_WRITE_OFFSET = 0x00000028 /* FileRefWriteWithOffset */
106
+ };
107
+
108
+ afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client);
109
+
110
+ #endif
afc.pxi ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from "libimobiledevice/afc.h":
2
+ cdef struct afc_client_private:
3
+ pass
4
+ ctypedef afc_client_private *afc_client_t
5
+ ctypedef enum afc_error_t:
6
+ AFC_E_SUCCESS = 0
7
+ AFC_E_UNKNOWN_ERROR = 1
8
+ AFC_E_OP_HEADER_INVALID = 2
9
+ AFC_E_NO_RESOURCES = 3
10
+ AFC_E_READ_ERROR = 4
11
+ AFC_E_WRITE_ERROR = 5
12
+ AFC_E_UNKNOWN_PACKET_TYPE = 6
13
+ AFC_E_INVALID_ARG = 7
14
+ AFC_E_OBJECT_NOT_FOUND = 8
15
+ AFC_E_OBJECT_IS_DIR = 9
16
+ AFC_E_PERM_DENIED = 10
17
+ AFC_E_SERVICE_NOT_CONNECTED = 11
18
+ AFC_E_OP_TIMEOUT = 12
19
+ AFC_E_TOO_MUCH_DATA = 13
20
+ AFC_E_END_OF_DATA = 14
21
+ AFC_E_OP_NOT_SUPPORTED = 15
22
+ AFC_E_OBJECT_EXISTS = 16
23
+ AFC_E_OBJECT_BUSY = 17
24
+ AFC_E_NO_SPACE_LEFT = 18
25
+ AFC_E_OP_WOULD_BLOCK = 19
26
+ AFC_E_IO_ERROR = 20
27
+ AFC_E_OP_INTERRUPTED = 21
28
+ AFC_E_OP_IN_PROGRESS = 22
29
+ AFC_E_INTERNAL_ERROR = 23
30
+ AFC_E_MUX_ERROR = 30
31
+ AFC_E_NO_MEM = 31
32
+ AFC_E_NOT_ENOUGH_DATA = 32
33
+ AFC_E_DIR_NOT_EMPTY = 33
34
+ ctypedef enum afc_file_mode_t:
35
+ AFC_FOPEN_RDONLY = 0x00000001
36
+ AFC_FOPEN_RW = 0x00000002
37
+ AFC_FOPEN_WRONLY = 0x00000003
38
+ AFC_FOPEN_WR = 0x00000004
39
+ AFC_FOPEN_APPEND = 0x00000005
40
+ AFC_FOPEN_RDAPPEND = 0x00000006
41
+ ctypedef enum afc_link_type_t:
42
+ AFC_HARDLINK = 1
43
+ AFC_SYMLINK = 2
44
+ ctypedef enum afc_lock_op_t:
45
+ AFC_LOCK_SH = 1 | 4
46
+ AFC_LOCK_EX = 2 | 4
47
+ AFC_LOCK_UN = 8 | 4
48
+
49
+ afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, afc_client_t *client)
50
+ afc_error_t afc_client_free(afc_client_t client)
51
+ afc_error_t afc_get_device_info(afc_client_t client, char ***infos)
52
+ afc_error_t afc_read_directory(afc_client_t client, char *dir, char ***list)
53
+ afc_error_t afc_get_file_info(afc_client_t client, char *filename, char ***infolist)
54
+ afc_error_t afc_remove_path(afc_client_t client, char *path)
55
+ afc_error_t afc_remove_path_and_contents(afc_client_t client, char *path)
56
+ afc_error_t afc_rename_path(afc_client_t client, char *f, char *to)
57
+ afc_error_t afc_make_directory(afc_client_t client, char *dir)
58
+ afc_error_t afc_truncate(afc_client_t client, char *path, uint64_t newsize)
59
+ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, char *target, char *linkname)
60
+ afc_error_t afc_set_file_time(afc_client_t client, char *path, uint64_t mtime)
61
+
62
+ afc_error_t afc_file_open(afc_client_t client, char *filename, afc_file_mode_t file_mode, uint64_t *handle)
63
+ afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
64
+ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
65
+ afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
66
+ afc_error_t afc_file_write(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_written)
67
+ afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
68
+ afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
69
+ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
70
+
71
+ LOCK_SH = AFC_LOCK_SH
72
+ LOCK_EX = AFC_LOCK_EX
73
+ LOCK_UN = AFC_LOCK_UN
74
+
75
+ cdef class AfcError(BaseError):
76
+ def __init__(self, *args, **kwargs):
77
+ self._lookup_table = {
78
+ AFC_E_SUCCESS: "Success",
79
+ AFC_E_UNKNOWN_ERROR: "Unknown error",
80
+ AFC_E_OP_HEADER_INVALID: "OP header invalid",
81
+ AFC_E_NO_RESOURCES: "No resources",
82
+ AFC_E_READ_ERROR: "Read error",
83
+ AFC_E_WRITE_ERROR: "Write error",
84
+ AFC_E_UNKNOWN_PACKET_TYPE: "Unknown packet type",
85
+ AFC_E_INVALID_ARG: "Invalid argument",
86
+ AFC_E_OBJECT_NOT_FOUND: "Object not found",
87
+ AFC_E_OBJECT_IS_DIR: "Object is directory",
88
+ AFC_E_PERM_DENIED: "Permission denied",
89
+ AFC_E_SERVICE_NOT_CONNECTED: "Service not connected",
90
+ AFC_E_OP_TIMEOUT: "OP timeout",
91
+ AFC_E_TOO_MUCH_DATA: "Too much data",
92
+ AFC_E_END_OF_DATA: "End of data",
93
+ AFC_E_OP_NOT_SUPPORTED: "OP not supported",
94
+ AFC_E_OBJECT_EXISTS: "Object exists",
95
+ AFC_E_OBJECT_BUSY: "Object busy",
96
+ AFC_E_NO_SPACE_LEFT: "No space left",
97
+ AFC_E_OP_WOULD_BLOCK: "OP would block",
98
+ AFC_E_IO_ERROR: "IO error",
99
+ AFC_E_OP_INTERRUPTED: "OP interrupted",
100
+ AFC_E_OP_IN_PROGRESS: "OP in progress",
101
+ AFC_E_INTERNAL_ERROR: "Internal error",
102
+ AFC_E_MUX_ERROR: "MUX error",
103
+ AFC_E_NO_MEM: "No memory",
104
+ AFC_E_NOT_ENOUGH_DATA: "Not enough data",
105
+ AFC_E_DIR_NOT_EMPTY: "Directory not empty"
106
+ }
107
+ BaseError.__init__(self, *args, **kwargs)
108
+
109
+ # forward declaration of AfcClient
110
+ cdef class AfcClient(BaseService)
111
+
112
+ cdef class AfcFile(Base):
113
+ cdef uint64_t _c_handle
114
+ cdef AfcClient _client
115
+ cdef bytes _filename
116
+
117
+ def __init__(self, *args, **kwargs):
118
+ raise TypeError("AfcFile cannot be instantiated")
119
+
120
+ def __enter__(self):
121
+ return self
122
+
123
+ def __exit__(self, type, value, traceback):
124
+ self.close()
125
+
126
+ cpdef close(self):
127
+ self.handle_error(afc_file_close(self._client._c_client, self._c_handle))
128
+
129
+ cpdef lock(self, int operation):
130
+ self.handle_error(afc_file_lock(self._client._c_client, self._c_handle, <afc_lock_op_t>operation))
131
+
132
+ cpdef seek(self, int64_t offset, int whence):
133
+ self.handle_error(afc_file_seek(self._client._c_client, self._c_handle, offset, whence))
134
+
135
+ cpdef uint64_t tell(self):
136
+ cdef uint64_t position
137
+ self.handle_error(afc_file_tell(self._client._c_client, self._c_handle, &position))
138
+ return position
139
+
140
+ cpdef truncate(self, uint64_t newsize):
141
+ self.handle_error(afc_file_truncate(self._client._c_client, self._c_handle, newsize))
142
+
143
+ cpdef bytes read(self, uint32_t size):
144
+ cdef:
145
+ uint32_t bytes_read
146
+ char* c_data = <char *>malloc(size)
147
+ bytes result
148
+ try:
149
+ self.handle_error(afc_file_read(self._client._c_client, self._c_handle, c_data, size, &bytes_read))
150
+ result = c_data[:bytes_read]
151
+ return result
152
+ except BaseError, e:
153
+ raise
154
+ finally:
155
+ free(c_data)
156
+
157
+ cpdef uint32_t write(self, bytes data):
158
+ cdef:
159
+ uint32_t bytes_written
160
+ char* c_data = data
161
+ try:
162
+ self.handle_error(afc_file_write(self._client._c_client, self._c_handle, c_data, len(data), &bytes_written))
163
+ except BaseError, e:
164
+ raise
165
+
166
+ return bytes_written
167
+
168
+ cdef inline BaseError _error(self, int16_t ret):
169
+ return AfcError(ret)
170
+
171
+ cdef class AfcClient(BaseService):
172
+ __service_name__ = "com.apple.afc"
173
+ cdef afc_client_t _c_client
174
+
175
+ def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs):
176
+ if (device is not None and descriptor is not None):
177
+ self.handle_error(afc_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client)))
178
+
179
+ def __dealloc__(self):
180
+ cdef afc_error_t err
181
+ if self._c_client is not NULL:
182
+ err = afc_client_free(self._c_client)
183
+ self.handle_error(err)
184
+
185
+ cdef BaseError _error(self, int16_t ret):
186
+ return AfcError(ret)
187
+
188
+ cpdef list get_device_info(self):
189
+ cdef:
190
+ afc_error_t err
191
+ char** infos = NULL
192
+ bytes info
193
+ int i = 0
194
+ list result = []
195
+ err = afc_get_device_info(self._c_client, &infos)
196
+ try:
197
+ self.handle_error(err)
198
+ except BaseError, e:
199
+ raise
200
+ finally:
201
+ if infos != NULL:
202
+ while infos[i]:
203
+ info = infos[i]
204
+ result.append(info)
205
+ free(infos[i])
206
+ i = i + 1
207
+ free(infos)
208
+
209
+ return result
210
+
211
+ cpdef list read_directory(self, bytes directory):
212
+ cdef:
213
+ afc_error_t err
214
+ char** dir_list = NULL
215
+ bytes f
216
+ int i = 0
217
+ list result = []
218
+ err = afc_read_directory(self._c_client, directory, &dir_list)
219
+ try:
220
+ self.handle_error(err)
221
+ except BaseError, e:
222
+ raise
223
+ finally:
224
+ if dir_list != NULL:
225
+ while dir_list[i]:
226
+ f = dir_list[i]
227
+ result.append(f)
228
+ free(dir_list[i])
229
+ i = i + 1
230
+ free(dir_list)
231
+
232
+ return result
233
+
234
+ cpdef AfcFile open(self, bytes filename, bytes mode=b'r'):
235
+ cdef:
236
+ afc_file_mode_t c_mode
237
+ uint64_t handle
238
+ AfcFile f
239
+ if mode == b'r':
240
+ c_mode = AFC_FOPEN_RDONLY
241
+ elif mode == b'r+':
242
+ c_mode = AFC_FOPEN_RW
243
+ elif mode == b'w':
244
+ c_mode = AFC_FOPEN_WRONLY
245
+ elif mode == b'w+':
246
+ c_mode = AFC_FOPEN_WR
247
+ elif mode == b'a':
248
+ c_mode = AFC_FOPEN_APPEND
249
+ elif mode == b'a+':
250
+ c_mode = AFC_FOPEN_RDAPPEND
251
+ else:
252
+ raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
253
+
254
+ self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle))
255
+ f = AfcFile.__new__(AfcFile)
256
+ f._c_handle = handle
257
+ f._client = self
258
+ f._filename = filename
259
+
260
+ return f
261
+
262
+ cpdef list get_file_info(self, bytes path):
263
+ cdef:
264
+ list result = []
265
+ char** c_result = NULL
266
+ int i = 0
267
+ bytes info
268
+ try:
269
+ self.handle_error(afc_get_file_info(self._c_client, path, &c_result))
270
+ except BaseError, e:
271
+ raise
272
+ finally:
273
+ if c_result != NULL:
274
+ while c_result[i]:
275
+ info = c_result[i]
276
+ result.append(info)
277
+ free(c_result[i])
278
+ i = i + 1
279
+ free(c_result)
280
+
281
+ return result
282
+
283
+ cpdef remove_path(self, bytes path):
284
+ self.handle_error(afc_remove_path(self._c_client, path))
285
+
286
+ cpdef remove_path_and_contents(self, bytes path):
287
+ self.handle_error(afc_remove_path_and_contents(self._c_client, path))
288
+
289
+ cpdef rename_path(self, bytes f, bytes t):
290
+ self.handle_error(afc_rename_path(self._c_client, f, t))
291
+
292
+ cpdef make_directory(self, bytes d):
293
+ self.handle_error(afc_make_directory(self._c_client, d))
294
+
295
+ cpdef truncate(self, bytes path, uint64_t newsize):
296
+ self.handle_error(afc_truncate(self._c_client, path, newsize))
297
+
298
+ cpdef link(self, bytes source, bytes link_name):
299
+ self.handle_error(afc_make_link(self._c_client, AFC_HARDLINK, source, link_name))
300
+
301
+ cpdef symlink(self, bytes source, bytes link_name):
302
+ self.handle_error(afc_make_link(self._c_client, AFC_SYMLINK, source, link_name))
303
+
304
+ cpdef set_file_time(self, bytes path, uint64_t mtime):
305
+ self.handle_error(afc_set_file_time(self._c_client, path, mtime))
306
+
307
+ cdef class Afc2Client(AfcClient):
308
+ __service_name__ = "com.apple.afc2"
309
+
310
+ cpdef AfcFile open(self, bytes filename, bytes mode=b'r'):
311
+ cdef:
312
+ afc_file_mode_t c_mode
313
+ uint64_t handle
314
+ AfcFile f
315
+ if mode == b'r':
316
+ c_mode = AFC_FOPEN_RDONLY
317
+ elif mode == b'r+':
318
+ c_mode = AFC_FOPEN_RW
319
+ elif mode == b'w':
320
+ c_mode = AFC_FOPEN_WRONLY
321
+ elif mode == b'w+':
322
+ c_mode = AFC_FOPEN_WR
323
+ elif mode == b'a':
324
+ c_mode = AFC_FOPEN_APPEND
325
+ elif mode == b'a+':
326
+ c_mode = AFC_FOPEN_RDAPPEND
327
+ else:
328
+ raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
329
+
330
+ self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle))
331
+ f = AfcFile.__new__(AfcFile)
332
+ f._c_handle = handle
333
+ f._client = <AfcClient>self
334
+ f._filename = filename
335
+
336
+ return f
337
+
afcclient.c ADDED
@@ -0,0 +1,1630 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * afcclient.c
3
+ * Utility to interact with AFC/HoustArrest service on the device
4
+ *
5
+ * Inspired by https://github.com/emonti/afcclient
6
+ * But entirely rewritten from scratch.
7
+ *
8
+ * Copyright (c) 2023 Nikias Bassen, All Rights Reserved.
9
+ *
10
+ * This library is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU Lesser General Public
12
+ * License as published by the Free Software Foundation; either
13
+ * version 2.1 of the License, or (at your option) any later version.
14
+ *
15
+ * This library is distributed in the hope that it will be useful,
16
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
+ * Lesser General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU Lesser General Public
21
+ * License along with this library; if not, write to the Free Software
22
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
+ */
24
+
25
+ #ifdef HAVE_CONFIG_H
26
+ #include <config.h>
27
+ #endif
28
+
29
+ #define TOOL_NAME "afcclient"
30
+
31
+ #include <stdio.h>
32
+ #include <string.h>
33
+ #include <errno.h>
34
+ #include <stdlib.h>
35
+ #include <getopt.h>
36
+ #include <signal.h>
37
+ #include <ctype.h>
38
+ #include <unistd.h>
39
+ #include <dirent.h>
40
+ #include <time.h>
41
+ #include <sys/stat.h>
42
+
43
+ #ifdef _WIN32
44
+ #include <windows.h>
45
+ #include <sys/time.h>
46
+ #include <conio.h>
47
+ #define sleep(x) Sleep(x*1000)
48
+ #define S_IFMT 0170000 /* [XSI] type of file mask */
49
+ #define S_IFIFO 0010000 /* [XSI] named pipe (fifo) */
50
+ #define S_IFCHR 0020000 /* [XSI] character special */
51
+ #define S_IFBLK 0060000 /* [XSI] block special */
52
+ #define S_IFLNK 0120000 /* [XSI] symbolic link */
53
+ #define S_IFSOCK 0140000 /* [XSI] socket */
54
+ #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */
55
+ #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */
56
+ #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */
57
+ #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* symbolic link */
58
+ #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* socket */
59
+ #else
60
+ #include <sys/time.h>
61
+ #include <termios.h>
62
+ #endif
63
+
64
+ #ifdef HAVE_READLINE
65
+ #include <readline/readline.h>
66
+ #include <readline/history.h>
67
+ #endif
68
+
69
+ #include <libimobiledevice/libimobiledevice.h>
70
+ #include <libimobiledevice/lockdown.h>
71
+ #include <libimobiledevice/house_arrest.h>
72
+ #include <libimobiledevice/afc.h>
73
+ #include <plist/plist.h>
74
+
75
+ #include <libimobiledevice-glue/termcolors.h>
76
+ #include <libimobiledevice-glue/utils.h>
77
+
78
+ #undef st_mtime
79
+ #undef st_birthtime
80
+ struct afc_file_stat {
81
+ uint16_t st_mode;
82
+ uint16_t st_nlink;
83
+ uint64_t st_size;
84
+ uint64_t st_mtime;
85
+ uint64_t st_birthtime;
86
+ uint32_t st_blocks;
87
+ };
88
+
89
+ static char* udid = NULL;
90
+ static int connected = 0;
91
+ static int use_network = 0;
92
+ static idevice_subscription_context_t context = NULL;
93
+ static char* curdir = NULL;
94
+ static size_t curdir_len = 0;
95
+
96
+ static int file_exists(const char* path)
97
+ {
98
+ struct stat tst;
99
+ #ifdef _WIN32
100
+ return (stat(path, &tst) == 0);
101
+ #else
102
+ return (lstat(path, &tst) == 0);
103
+ #endif
104
+ }
105
+
106
+ static int is_directory(const char* path)
107
+ {
108
+ struct stat tst;
109
+ #ifdef _WIN32
110
+ return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
111
+ #else
112
+ return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
113
+ #endif
114
+ }
115
+
116
+ static void print_usage(int argc, char **argv, int is_error)
117
+ {
118
+ char *name = strrchr(argv[0], '/');
119
+ fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
120
+ fprintf(is_error ? stderr : stdout,
121
+ "\n"
122
+ "Interact with AFC/HouseArrest service on a connected device.\n"
123
+ "\n"
124
+ "OPTIONS:\n"
125
+ " -u, --udid UDID target specific device by UDID\n"
126
+ " -n, --network connect to network device (not recommended!)\n"
127
+ " --container <appid> Access container of given app\n"
128
+ " --documents <appid> Access Documents directory of given app\n"
129
+ " -h, --help prints usage information\n" \
130
+ " -d, --debug enable communication debugging\n" \
131
+ " -v, --version prints version information\n" \
132
+ "\n"
133
+ );
134
+ fprintf(is_error ? stderr : stdout,
135
+ "\n" \
136
+ "Homepage: <" PACKAGE_URL ">\n"
137
+ "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
138
+ );
139
+ }
140
+
141
+ #ifndef HAVE_READLINE
142
+ #ifdef _WIN32
143
+ #define BS_CC '\b'
144
+ #else
145
+ #define BS_CC 0x7f
146
+ #define getch getchar
147
+ #endif
148
+ static void get_input(char *buf, int maxlen)
149
+ {
150
+ int len = 0;
151
+ int c;
152
+
153
+ while ((c = getch())) {
154
+ if ((c == '\r') || (c == '\n')) {
155
+ break;
156
+ }
157
+ if (isprint(c)) {
158
+ if (len < maxlen-1)
159
+ buf[len++] = c;
160
+ } else if (c == BS_CC) {
161
+ if (len > 0) {
162
+ fputs("\b \b", stdout);
163
+ len--;
164
+ }
165
+ }
166
+ }
167
+ buf[len] = 0;
168
+ }
169
+ #endif
170
+
171
+ #define OPT_DOCUMENTS 1
172
+ #define OPT_CONTAINER 2
173
+
174
+ int stop_requested = 0;
175
+
176
+ static void handle_signal(int sig)
177
+ {
178
+ stop_requested++;
179
+ #ifdef _WIN32
180
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
181
+ #else
182
+ kill(getpid(), SIGINT);
183
+ #endif
184
+ }
185
+
186
+ static void handle_help(afc_client_t afc, int argc, char** argv)
187
+ {
188
+ printf("Available commands:\n");
189
+ printf("help - print list of available commands\n");
190
+ printf("devinfo - print device information\n");
191
+ printf("info PATH - print file attributes of file at PATH\n");
192
+ printf("ls [-l] PATH - print directory contents of PATH\n");
193
+ printf("mv OLD NEW - rename file OLD to NEW\n");
194
+ printf("mkdir PATH - create directory at PATH\n");
195
+ printf("ln [-s] FILE [LINK] - create a (symbolic) link to file named LINKNAME\n");
196
+ printf(" NOTE: This feature has been disabled in newer versions of iOS.\n");
197
+ printf("rm PATH - remove item at PATH\n");
198
+ printf("get [-rf] PATH [LOCALPATH] - transfer file at PATH from device to LOCALPATH\n");
199
+ printf("put [-rf] LOCALPATH [PATH] - transfer local file at LOCALPATH to device at PATH\n");
200
+ printf("\n");
201
+ }
202
+
203
+ static const char* path_get_basename(const char* path)
204
+ {
205
+ const char *p = strrchr(path, '/');
206
+ return p ? p + 1 : path;
207
+ }
208
+
209
+ static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
210
+ {
211
+ /* Perform the carry for the later subtraction by updating y. */
212
+ if (x->tv_usec < y->tv_usec) {
213
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
214
+ y->tv_usec -= 1000000 * nsec;
215
+ y->tv_sec += nsec;
216
+ }
217
+ if (x->tv_usec - y->tv_usec > 1000000) {
218
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
219
+ y->tv_usec += 1000000 * nsec;
220
+ y->tv_sec -= nsec;
221
+ }
222
+ /* Compute the time remaining to wait.
223
+ tv_usec is certainly positive. */
224
+ result->tv_sec = x->tv_sec - y->tv_sec;
225
+ result->tv_usec = x->tv_usec - y->tv_usec;
226
+ /* Return 1 if result is negative. */
227
+ return x->tv_sec < y->tv_sec;
228
+ }
229
+
230
+ struct str_item {
231
+ size_t len;
232
+ char* str;
233
+ };
234
+
235
+ static char* get_absolute_path(const char *path)
236
+ {
237
+ if (*path == '/') {
238
+ return strdup(path);
239
+ } else {
240
+ size_t len = curdir_len + 1 + strlen(path) + 1;
241
+ char* result = (char*)malloc(len);
242
+ if (!strcmp(curdir, "/")) {
243
+ snprintf(result, len, "/%s", path);
244
+ } else {
245
+ snprintf(result, len, "%s/%s", curdir, path);
246
+ }
247
+ return result;
248
+ }
249
+ }
250
+
251
+ static char* get_realpath(const char* path)
252
+ {
253
+ if (!path) return NULL;
254
+
255
+ int is_absolute = 0;
256
+ if (*path == '/') {
257
+ is_absolute = 1;
258
+ }
259
+
260
+ const char* p = path;
261
+ if (is_absolute) {
262
+ while (*p == '/') p++;
263
+ }
264
+ if (*p == '\0') {
265
+ return strdup("/");
266
+ }
267
+
268
+ int c_count = 1;
269
+ const char* start = p;
270
+ const char* end = p;
271
+ struct str_item* comps = NULL;
272
+
273
+ while (*p) {
274
+ if (*p == '/') {
275
+ p++;
276
+ end = p-1;
277
+ while (*p == '/') p++;
278
+ if (*p == '\0') break;
279
+ struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count);
280
+ if (!newcomps) {
281
+ free(comps);
282
+ printf("%s: out of memory?!\n", __func__);
283
+ return NULL;
284
+ }
285
+ comps = newcomps;
286
+ char *comp = (char*)malloc(end-start+1);
287
+ strncpy(comp, start, end-start);
288
+ comp[end-start] = '\0';
289
+ comps[c_count-1].len = end-start;
290
+ comps[c_count-1].str = comp;
291
+ c_count++;
292
+ start = p;
293
+ end = p;
294
+ }
295
+ p++;
296
+ }
297
+ if (p > start) {
298
+ if (start == end) {
299
+ end = p;
300
+ }
301
+ struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count);
302
+ if (!newcomps) {
303
+ free(comps);
304
+ printf("%s: out of memory?!\n", __func__);
305
+ return NULL;
306
+ }
307
+ comps = newcomps;
308
+ char *comp = (char*)malloc(end-start+1);
309
+ strncpy(comp, start, end-start);
310
+ comp[end-start] = '\0';
311
+ comps[c_count-1].len = end-start;
312
+ comps[c_count-1].str = comp;
313
+ }
314
+
315
+ struct str_item* comps_final = (struct str_item*)malloc(sizeof(struct str_item)*(c_count+1));
316
+ int o = 1;
317
+ if (is_absolute) {
318
+ comps_final[0].len = 1;
319
+ comps_final[0].str = (char*)"/";
320
+ } else {
321
+ comps_final[0].len = curdir_len;
322
+ comps_final[0].str = curdir;
323
+ }
324
+ size_t o_len = comps_final[0].len;
325
+
326
+ for (int i = 0; i < c_count; i++) {
327
+ if (!strcmp(comps[i].str, "..")) {
328
+ o--;
329
+ continue;
330
+ } else if (!strcmp(comps[i].str, ".")) {
331
+ continue;
332
+ }
333
+ o_len += comps[i].len;
334
+ comps_final[o].str = comps[i].str;
335
+ comps_final[o].len = comps[i].len;
336
+ o++;
337
+ }
338
+
339
+ o_len += o;
340
+ char* result = (char*)malloc(o_len);
341
+ char* presult = result;
342
+ for (int i = 0; i < o; i++) {
343
+ if (i > 0 && strcmp(comps_final[i-1].str, "/") != 0) {
344
+ *presult = '/';
345
+ presult++;
346
+ }
347
+ strncpy(presult, comps_final[i].str, comps_final[i].len);
348
+ presult+=comps_final[i].len;
349
+ *presult = '\0';
350
+ }
351
+ if (presult == result) {
352
+ *presult = '/';
353
+ presult++;
354
+ *presult = 0;
355
+ }
356
+
357
+ for (int i = 0; i < c_count; i++) {
358
+ free(comps[i].str);
359
+ }
360
+ free(comps);
361
+ free(comps_final);
362
+
363
+ return result;
364
+ }
365
+
366
+ static void handle_devinfo(afc_client_t afc, int argc, char** argv)
367
+ {
368
+ plist_t info = NULL;
369
+ afc_error_t err = afc_get_device_info_plist(afc, &info);
370
+ if (err == AFC_E_SUCCESS && info) {
371
+ if (argc > 0 && !strcmp(argv[0], "--plain")) {
372
+ plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
373
+ } else {
374
+ plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
375
+ }
376
+ } else {
377
+ printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err);
378
+ }
379
+ plist_free(info);
380
+ }
381
+
382
+ static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf)
383
+ {
384
+ plist_t info = NULL;
385
+ afc_error_t ret = afc_get_file_info_plist(afc, path, &info);
386
+ memset(stbuf, 0, sizeof(struct afc_file_stat));
387
+ if (ret != AFC_E_SUCCESS) {
388
+ return -1;
389
+ } else if (!info) {
390
+ return -1;
391
+ }
392
+ stbuf->st_size = plist_dict_get_uint(info, "st_size");
393
+ stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks");
394
+ const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
395
+ if (s_ifmt) {
396
+ if (!strcmp(s_ifmt, "S_IFREG")) {
397
+ stbuf->st_mode = S_IFREG;
398
+ } else if (!strcmp(s_ifmt, "S_IFDIR")) {
399
+ stbuf->st_mode = S_IFDIR;
400
+ } else if (!strcmp(s_ifmt, "S_IFLNK")) {
401
+ stbuf->st_mode = S_IFLNK;
402
+ } else if (!strcmp(s_ifmt, "S_IFBLK")) {
403
+ stbuf->st_mode = S_IFBLK;
404
+ } else if (!strcmp(s_ifmt, "S_IFCHR")) {
405
+ stbuf->st_mode = S_IFCHR;
406
+ } else if (!strcmp(s_ifmt, "S_IFIFO")) {
407
+ stbuf->st_mode = S_IFIFO;
408
+ } else if (!strcmp(s_ifmt, "S_IFSOCK")) {
409
+ stbuf->st_mode = S_IFSOCK;
410
+ }
411
+ }
412
+ stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink");
413
+ stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000);
414
+ /* available on iOS 7+ */
415
+ stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000);
416
+ plist_free(info);
417
+ return 0;
418
+ }
419
+
420
+ static void handle_file_info(afc_client_t afc, int argc, char** argv)
421
+ {
422
+ if (argc < 1) {
423
+ printf("Error: Missing PATH.\n");
424
+ return;
425
+ }
426
+
427
+ plist_t info = NULL;
428
+ char* abspath = get_absolute_path(argv[0]);
429
+ if (!abspath) {
430
+ printf("Error: Invalid argument\n");
431
+ return;
432
+ }
433
+ afc_error_t err = afc_get_file_info_plist(afc, abspath, &info);
434
+ if (err == AFC_E_SUCCESS && info) {
435
+ if (argc > 1 && !strcmp(argv[1], "--plain")) {
436
+ plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
437
+ } else {
438
+ plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
439
+ }
440
+ } else {
441
+ printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err);
442
+ }
443
+ plist_free(info);
444
+ free(abspath);
445
+ }
446
+
447
+ static void print_file_info(afc_client_t afc, const char* path, int list_verbose)
448
+ {
449
+ struct afc_file_stat st;
450
+ get_file_info_stat(afc, path, &st);
451
+ if (list_verbose) {
452
+ char timebuf[64];
453
+ time_t t = st.st_mtime;
454
+ if (S_ISDIR(st.st_mode)) {
455
+ printf("drwxr-xr-x");
456
+ } else if (S_ISLNK(st.st_mode)) {
457
+ printf("lrwxrwxrwx");
458
+ } else {
459
+ if (S_ISFIFO(st.st_mode)) {
460
+ printf("f");
461
+ } else if (S_ISBLK(st.st_mode)) {
462
+ printf("b");
463
+ } else if (S_ISCHR(st.st_mode)) {
464
+ printf("c");
465
+ } else if (S_ISSOCK(st.st_mode)) {
466
+ printf("s");
467
+ } else {
468
+ printf("-");
469
+ }
470
+ printf("rw-r--r--");
471
+ }
472
+ printf(" ");
473
+ printf("%4d", st.st_nlink);
474
+ printf(" ");
475
+ printf("mobile");
476
+ printf(" ");
477
+ printf("mobile");
478
+ printf(" ");
479
+ printf("%10lld", (long long)st.st_size);
480
+ printf(" ");
481
+ #ifdef _WIN32
482
+ strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t));
483
+ #else
484
+ strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t));
485
+ #endif
486
+ printf("%s", timebuf);
487
+ printf(" ");
488
+ }
489
+ if (S_ISDIR(st.st_mode)) {
490
+ cprintf(FG_CYAN);
491
+ } else if (S_ISLNK(st.st_mode)) {
492
+ cprintf(FG_MAGENTA);
493
+ } else if (S_ISREG(st.st_mode)) {
494
+ cprintf(FG_DEFAULT);
495
+ } else {
496
+ cprintf(FG_YELLOW);
497
+ }
498
+ cprintf("%s" COLOR_RESET "\n", path_get_basename(path));
499
+ }
500
+
501
+ static void handle_list(afc_client_t afc, int argc, char** argv)
502
+ {
503
+ const char* path = NULL;
504
+ int list_verbose = 0;
505
+ if (argc < 1) {
506
+ path = curdir;
507
+ } else {
508
+ if (!strcmp(argv[0], "-l")) {
509
+ list_verbose = 1;
510
+ if (argc == 2) {
511
+ path = argv[1];
512
+ } else {
513
+ path = curdir;
514
+ }
515
+ } else {
516
+ path = argv[0];
517
+ }
518
+ }
519
+ char* abspath = get_absolute_path(path);
520
+ if (!abspath) {
521
+ printf("Error: Invalid argument\n");
522
+ return;
523
+ }
524
+ int abspath_is_root = strcmp(abspath, "/") == 0;
525
+ size_t abspath_len = (abspath_is_root) ? 0 : strlen(abspath);
526
+ char** entries = NULL;
527
+ afc_error_t err = afc_read_directory(afc, abspath, &entries);
528
+ if (err == AFC_E_READ_ERROR) {
529
+ print_file_info(afc, abspath, list_verbose);
530
+ return;
531
+ } else if (err != AFC_E_SUCCESS) {
532
+ printf("Error: Failed to list '%s': %s (%d)\n", path, afc_strerror(err), err);
533
+ free(abspath);
534
+ return;
535
+ }
536
+
537
+ char** p = entries;
538
+ while (p && *p) {
539
+ if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) {
540
+ p++;
541
+ continue;
542
+ }
543
+ size_t len = abspath_len + 1 + strlen(*p) + 1;
544
+ char* testpath = (char*)malloc(len);
545
+ if (abspath_is_root) {
546
+ snprintf(testpath, len, "/%s", *p);
547
+ } else {
548
+ snprintf(testpath, len, "%s/%s", abspath, *p);
549
+ }
550
+ print_file_info(afc, testpath, list_verbose);
551
+ free(testpath);
552
+ p++;
553
+ }
554
+ afc_dictionary_free(entries);
555
+ free(abspath);
556
+ }
557
+
558
+ static void handle_rename(afc_client_t afc, int argc, char** argv)
559
+ {
560
+ if (argc != 2) {
561
+ printf("Error: Invalid number of arguments\n");
562
+ return;
563
+ }
564
+ char* srcpath = get_absolute_path(argv[0]);
565
+ if (!srcpath) {
566
+ printf("Error: Invalid argument\n");
567
+ return;
568
+ }
569
+ char* dstpath = get_absolute_path(argv[1]);
570
+ if (!dstpath) {
571
+ free(srcpath);
572
+ printf("Error: Invalid argument\n");
573
+ return;
574
+ }
575
+ afc_error_t err = afc_rename_path(afc, srcpath, dstpath);
576
+ if (err != AFC_E_SUCCESS) {
577
+ printf("Error: Failed to rename '%s' -> '%s': %s (%d)\n", argv[0], argv[1], afc_strerror(err), err);
578
+ }
579
+ free(srcpath);
580
+ free(dstpath);
581
+ }
582
+
583
+ static void handle_mkdir(afc_client_t afc, int argc, char** argv)
584
+ {
585
+ for (int i = 0; i < argc; i++) {
586
+ char* abspath = get_absolute_path(argv[i]);
587
+ if (!abspath) {
588
+ printf("Error: Invalid argument '%s'\n", argv[i]);
589
+ continue;
590
+ }
591
+ afc_error_t err = afc_make_directory(afc, abspath);
592
+ if (err != AFC_E_SUCCESS) {
593
+ printf("Error: Failed to create directory '%s': %s (%d)\n", argv[i], afc_strerror(err), err);
594
+ }
595
+ free(abspath);
596
+ }
597
+ }
598
+
599
+ static void handle_link(afc_client_t afc, int argc, char** argv)
600
+ {
601
+ if (argc < 2) {
602
+ printf("Error: Invalid number of arguments\n");
603
+ return;
604
+ }
605
+ afc_link_type_t link_type = AFC_HARDLINK;
606
+ if (!strcmp(argv[0], "-s")) {
607
+ argc--;
608
+ argv++;
609
+ link_type = AFC_SYMLINK;
610
+ }
611
+ if (argc < 1 || argc > 2) {
612
+ printf("Error: Invalid number of arguments\n");
613
+ return;
614
+ }
615
+ const char *link_name = (argc == 1) ? path_get_basename(argv[0]) : argv[1];
616
+ char* abs_link_name = get_absolute_path(link_name);
617
+ if (!abs_link_name) {
618
+ printf("Error: Invalid argument\n");
619
+ return;
620
+ }
621
+ afc_error_t err = afc_make_link(afc, link_type, argv[0], link_name);
622
+ if (err != AFC_E_SUCCESS) {
623
+ printf("Error: Failed to create %s link for '%s' at '%s': %s (%d)\n", (link_type == AFC_HARDLINK) ? "hard" : "symbolic", argv[0], link_name, afc_strerror(err), err);
624
+ }
625
+ }
626
+
627
+ static int ask_yesno(const char* prompt)
628
+ {
629
+ int ret = 0;
630
+ #ifdef HAVE_READLINE
631
+ char* result = readline(prompt);
632
+ if (result && result[0] == 'y') {
633
+ ret = 1;
634
+ }
635
+ #else
636
+ char cmdbuf[2] = {0, };
637
+ printf("%s", prompt);
638
+ fflush(stdout);
639
+ get_input(cmdbuf, sizeof(cmdbuf));
640
+ if (cmdbuf[0] == 'y') {
641
+ ret = 1;
642
+ }
643
+ #endif
644
+ #ifdef HAVE_READLINE
645
+ free(result);
646
+ #endif
647
+ return ret;
648
+ }
649
+
650
+ static void handle_remove(afc_client_t afc, int argc, char** argv)
651
+ {
652
+ int recursive = 0;
653
+ int force = 0;
654
+ int i = 0;
655
+ for (i = 0; i < argc; i++) {
656
+ if (!strcmp(argv[i], "--")) {
657
+ i++;
658
+ break;
659
+ } else if (!strcmp(argv[i], "-r")) {
660
+ recursive = 1;
661
+ } else if (!strcmp(argv[i], "-f")) {
662
+ force = 1;
663
+ } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
664
+ recursive = 1;
665
+ force = 1;
666
+ } else {
667
+ break;
668
+ }
669
+ }
670
+ if (recursive && !force) {
671
+ if (!ask_yesno("WARNING: This operation will remove all contents of the given path(s). Continue? [y/N] ")) {
672
+ printf("Aborted.\n");
673
+ return;
674
+ }
675
+ }
676
+ for ( ; i < argc; i++) {
677
+ char* abspath = get_absolute_path(argv[i]);
678
+ if (!abspath) {
679
+ printf("Error: Invalid argument '%s'\n", argv[i]);
680
+ continue;
681
+ }
682
+ afc_error_t err;
683
+ if (recursive) {
684
+ err = afc_remove_path_and_contents(afc, abspath);
685
+ } else {
686
+ err = afc_remove_path(afc, abspath);
687
+ }
688
+ if (err != AFC_E_SUCCESS) {
689
+ printf("Error: Failed to remove '%s': %s (%d)\n", argv[i], afc_strerror(err), err);
690
+ }
691
+ free(abspath);
692
+ }
693
+ }
694
+
695
+ static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint64_t file_size, uint8_t force_overwrite)
696
+ {
697
+ uint64_t fh = 0;
698
+ afc_error_t err = afc_file_open(afc, srcpath, AFC_FOPEN_RDONLY, &fh);
699
+ if (err != AFC_E_SUCCESS) {
700
+ printf("Error: Failed to open file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
701
+ return 0;
702
+ }
703
+ if (file_exists(dstpath) && !force_overwrite) {
704
+ printf("Error: Failed to overwrite existing file without '-f' option: %s\n", dstpath);
705
+ return 0;
706
+ }
707
+ FILE *f = fopen(dstpath, "wb");
708
+ if (!f) {
709
+ printf("Error: Failed to open local file '%s': %s\n", dstpath, strerror(errno));
710
+ return 0;
711
+ }
712
+ struct timeval t1;
713
+ struct timeval t2;
714
+ struct timeval tdiff;
715
+ size_t bufsize = 0x100000;
716
+ char *buf = malloc(bufsize);
717
+ size_t total = 0;
718
+ int progress = 0;
719
+ int lastprog = 0;
720
+ if (file_size > 0x400000) {
721
+ progress = 1;
722
+ gettimeofday(&t1, NULL);
723
+ }
724
+ uint8_t succeed = 1;
725
+ while (err == AFC_E_SUCCESS) {
726
+ uint32_t bytes_read = 0;
727
+ size_t chunk = 0;
728
+ err = afc_file_read(afc, fh, buf, bufsize, &bytes_read);
729
+ if (bytes_read == 0) {
730
+ break;
731
+ }
732
+ while (chunk < bytes_read) {
733
+ size_t wr = fwrite(buf + chunk, 1, bytes_read - chunk, f);
734
+ if (wr == 0) {
735
+ if (progress) {
736
+ printf("\n");
737
+ }
738
+ printf("Error: Failed to write to local file\n");
739
+ succeed = 0;
740
+ break;
741
+ }
742
+ chunk += wr;
743
+ }
744
+ total += chunk;
745
+ if (progress) {
746
+ int prog = (int) ((double) total / (double) file_size * 100.0f);
747
+ if (prog > lastprog) {
748
+ gettimeofday(&t2, NULL);
749
+ timeval_subtract(&tdiff, &t2, &t1);
750
+ double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000;
751
+ printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec);
752
+ fflush(stdout);
753
+ lastprog = prog;
754
+ }
755
+ }
756
+ }
757
+ if (progress) {
758
+ printf("\n");
759
+ }
760
+ if (err != AFC_E_SUCCESS) {
761
+ printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
762
+ succeed = 0;
763
+ }
764
+ free(buf);
765
+ fclose(f);
766
+ afc_file_close(afc, fh);
767
+ return succeed;
768
+ }
769
+
770
+ static int __mkdir(const char* path)
771
+ {
772
+ #ifdef _WIN32
773
+ return mkdir(path);
774
+ #else
775
+ return mkdir(path, 0755);
776
+ #endif
777
+ }
778
+
779
+ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get)
780
+ {
781
+ plist_t info = NULL;
782
+ uint64_t file_size = 0;
783
+ afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info);
784
+ if (err == AFC_E_OBJECT_NOT_FOUND) {
785
+ printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
786
+ return 0;
787
+ }
788
+ uint8_t is_dir = 0;
789
+ if (info) {
790
+ file_size = plist_dict_get_uint(info, "st_size");
791
+ const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
792
+ is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
793
+ plist_free(info);
794
+ }
795
+ uint8_t succeed = 1;
796
+ if (is_dir) {
797
+ if (!recursive_get) {
798
+ printf("Error: Failed to get a directory without '-r' option: %s\n", srcpath);
799
+ return 0;
800
+ }
801
+ char **entries = NULL;
802
+ err = afc_read_directory(afc, srcpath, &entries);
803
+ if (err != AFC_E_SUCCESS) {
804
+ printf("Error: Failed to list '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
805
+ return 0;
806
+ }
807
+ char **p = entries;
808
+ size_t srcpath_len = strlen(srcpath);
809
+ uint8_t srcpath_is_root = strcmp(srcpath, "/") == 0;
810
+ // if directory exists, check force_overwrite flag
811
+ if (is_directory(dstpath)) {
812
+ if (!force_overwrite) {
813
+ printf("Error: Failed to write into existing directory without '-f': %s\n", dstpath);
814
+ return 0;
815
+ }
816
+ } else if (__mkdir(dstpath) != 0) {
817
+ printf("Error: Failed to create directory '%s': %s\n", dstpath, strerror(errno));
818
+ afc_dictionary_free(entries);
819
+ return 0;
820
+ }
821
+ while (p && *p) {
822
+ if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) {
823
+ p++;
824
+ continue;
825
+ }
826
+ size_t len = srcpath_is_root ? (strlen(*p) + 2) : (srcpath_len + 1 + strlen(*p) + 1);
827
+ char *testpath = (char *) malloc(len);
828
+ if (srcpath_is_root) {
829
+ snprintf(testpath, len, "/%s", *p);
830
+ } else {
831
+ snprintf(testpath, len, "%s/%s", srcpath, *p);
832
+ }
833
+ uint8_t dst_is_root = strcmp(srcpath, "/") == 0;
834
+ size_t dst_len = dst_is_root ? (strlen(*p) + 2) : (strlen(dstpath) + 1 + strlen(*p) + 1);
835
+ char *newdst = (char *) malloc(dst_len);
836
+ if (dst_is_root) {
837
+ snprintf(newdst, dst_len, "/%s", *p);
838
+ } else {
839
+ snprintf(newdst, dst_len, "%s/%s", dstpath, *p);
840
+ }
841
+ if (!get_file(afc, testpath, newdst, force_overwrite, recursive_get)) {
842
+ succeed = 0;
843
+ break;
844
+ }
845
+ free(testpath);
846
+ free(newdst);
847
+ p++;
848
+ }
849
+ afc_dictionary_free(entries);
850
+ } else {
851
+ succeed = get_single_file(afc, srcpath, dstpath, file_size, force_overwrite);
852
+ }
853
+ return succeed;
854
+ }
855
+
856
+ static void handle_get(afc_client_t afc, int argc, char **argv)
857
+ {
858
+ if (argc < 1) {
859
+ printf("Error: Invalid number of arguments\n");
860
+ return;
861
+ }
862
+ uint8_t force_overwrite = 0, recursive_get = 0;
863
+ char *srcpath = NULL;
864
+ char *dstpath = NULL;
865
+ int i = 0;
866
+ for ( ; i < argc; i++) {
867
+ if (!strcmp(argv[i], "--")) {
868
+ i++;
869
+ break;
870
+ } else if (!strcmp(argv[i], "-r")) {
871
+ recursive_get = 1;
872
+ } else if (!strcmp(argv[i], "-f")) {
873
+ force_overwrite = 1;
874
+ } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
875
+ recursive_get = 1;
876
+ force_overwrite = 1;
877
+ } else {
878
+ break;
879
+ }
880
+ }
881
+ if (argc - i == 1) {
882
+ char *tmp = strdup(argv[i]);
883
+ size_t src_len = strlen(tmp);
884
+ if (src_len > 1 && tmp[src_len - 1] == '/') {
885
+ tmp[src_len - 1] = '\0';
886
+ }
887
+ srcpath = get_absolute_path(tmp);
888
+ dstpath = strdup(path_get_basename(tmp));
889
+ free(tmp);
890
+ } else if (argc - i == 2) {
891
+ char *tmp = strdup(argv[i]);
892
+ size_t src_len = strlen(tmp);
893
+ if (src_len > 1 && tmp[src_len - 1] == '/') {
894
+ tmp[src_len - 1] = '\0';
895
+ }
896
+ srcpath = get_absolute_path(tmp);
897
+ dstpath = strdup(argv[i + 1]);
898
+ size_t dst_len = strlen(dstpath);
899
+ if (dst_len > 1 && dstpath[dst_len - 1] == '/') {
900
+ dstpath[dst_len - 1] = '\0';
901
+ }
902
+ free(tmp);
903
+ } else {
904
+ printf("Error: Invalid number of arguments\n");
905
+ return;
906
+ }
907
+
908
+ // target is a directory, put file under this target
909
+ if (is_directory(dstpath)) {
910
+ const char *basen = path_get_basename(srcpath);
911
+ uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
912
+ size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
913
+ char *newdst = (char *) malloc(len);
914
+ if (dst_is_root) {
915
+ snprintf(newdst, len, "/%s", basen);
916
+ } else {
917
+ snprintf(newdst, len, "%s/%s", dstpath, basen);
918
+ }
919
+ get_file(afc, srcpath, newdst, force_overwrite, recursive_get);
920
+ free(srcpath);
921
+ free(newdst);
922
+ free(dstpath);
923
+ } else {
924
+ // target is not a dir or does not exist, just try to create or rewrite it
925
+ get_file(afc, srcpath, dstpath, force_overwrite, recursive_get);
926
+ free(srcpath);
927
+ free(dstpath);
928
+ }
929
+ }
930
+
931
+ static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite)
932
+ {
933
+ plist_t info = NULL;
934
+ afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info);
935
+ // file exists, only overwrite with '-f' option was set
936
+ if (ret == AFC_E_SUCCESS && info) {
937
+ plist_free(info);
938
+ if (!force_overwrite) {
939
+ printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath);
940
+ return 0;
941
+ }
942
+ }
943
+ FILE *f = fopen(srcpath, "rb");
944
+ if (!f) {
945
+ printf("Error: Failed to open local file '%s': %s\n", srcpath, strerror(errno));
946
+ return 0;
947
+ }
948
+ struct timeval t1;
949
+ struct timeval t2;
950
+ struct timeval tdiff;
951
+ struct stat fst;
952
+ int progress = 0;
953
+ size_t bufsize = 0x100000;
954
+ char *buf = malloc(bufsize);
955
+
956
+ fstat(fileno(f), &fst);
957
+ if (fst.st_size >= 0x400000) {
958
+ progress = 1;
959
+ gettimeofday(&t1, NULL);
960
+ }
961
+ size_t total = 0;
962
+ int lastprog = 0;
963
+ uint64_t fh = 0;
964
+ afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh);
965
+ uint8_t succeed = 1;
966
+ while (err == AFC_E_SUCCESS) {
967
+ uint32_t bytes_read = fread(buf, 1, bufsize, f);
968
+ if (bytes_read == 0) {
969
+ if (!feof(f)) {
970
+ if (progress) {
971
+ printf("\n");
972
+ }
973
+ printf("Error: Failed to read from local file\n");
974
+ succeed = 0;
975
+ }
976
+ break;
977
+ }
978
+ uint32_t chunk = 0;
979
+ while (chunk < bytes_read) {
980
+ uint32_t bytes_written = 0;
981
+ err = afc_file_write(afc, fh, buf + chunk, bytes_read - chunk, &bytes_written);
982
+ if (err != AFC_E_SUCCESS) {
983
+ if (progress) {
984
+ printf("\n");
985
+ }
986
+ printf("Error: Failed to write to device file\n");
987
+ succeed = 0;
988
+ break;
989
+ }
990
+ chunk += bytes_written;
991
+ }
992
+ total += chunk;
993
+ if (progress) {
994
+ int prog = (int) ((double) total / (double) fst.st_size * 100.0f);
995
+ if (prog > lastprog) {
996
+ gettimeofday(&t2, NULL);
997
+ timeval_subtract(&tdiff, &t2, &t1);
998
+ double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000;
999
+ printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec);
1000
+ fflush(stdout);
1001
+ lastprog = prog;
1002
+ }
1003
+ }
1004
+ }
1005
+ free(buf);
1006
+ afc_file_close(afc, fh);
1007
+ fclose(f);
1008
+ return succeed;
1009
+ }
1010
+
1011
+ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_put)
1012
+ {
1013
+ if (is_directory(srcpath)) {
1014
+ if (!recursive_put) {
1015
+ printf("Error: Failed to put directory without '-r' option: %s\n", srcpath);
1016
+ return 0;
1017
+ }
1018
+ plist_t info = NULL;
1019
+ afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
1020
+ //create if target directory does not exist
1021
+ plist_free(info);
1022
+ info = NULL;
1023
+ if (err == AFC_E_OBJECT_NOT_FOUND) {
1024
+ err = afc_make_directory(afc, dstpath);
1025
+ if (err != AFC_E_SUCCESS) {
1026
+ printf("Error: Failed to create directory '%s': %s (%d)\n", dstpath, afc_strerror(err), err);
1027
+ return 0;
1028
+ }
1029
+ } else if (!force_overwrite) {
1030
+ printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath);
1031
+ return 0;
1032
+ }
1033
+ afc_get_file_info_plist(afc, dstpath, &info);
1034
+ uint8_t is_dir = 0;
1035
+ if (info) {
1036
+ const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1037
+ is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1038
+ plist_free(info);
1039
+ }
1040
+ if (!is_dir) {
1041
+ printf("Error: Failed to create or access directory: '%s'\n", dstpath);
1042
+ return 0;
1043
+ }
1044
+
1045
+ // walk dir recursively to put files
1046
+ DIR *cur_dir = opendir(srcpath);
1047
+ if (cur_dir) {
1048
+ struct dirent *ep;
1049
+ while ((ep = readdir(cur_dir))) {
1050
+ if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
1051
+ continue;
1052
+ }
1053
+ char *fpath = string_build_path(srcpath, ep->d_name, NULL);
1054
+ if (fpath) {
1055
+ uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
1056
+ size_t len = dst_is_root ? (strlen(ep->d_name) + 2) : (strlen(dstpath) + 1 + strlen(ep->d_name) + 1);
1057
+ char *newdst = (char *) malloc(len);
1058
+ if (dst_is_root) {
1059
+ snprintf(newdst, len, "/%s", ep->d_name);
1060
+ } else {
1061
+ snprintf(newdst, len, "%s/%s", dstpath, ep->d_name);
1062
+ }
1063
+ if (!put_file(afc, fpath, newdst, force_overwrite, recursive_put)) {
1064
+ free(newdst);
1065
+ free(fpath);
1066
+ return 0;
1067
+ }
1068
+ free(newdst);
1069
+ free(fpath);
1070
+ }
1071
+ }
1072
+ closedir(cur_dir);
1073
+ } else {
1074
+ printf("Error: Failed to visit directory: '%s': %s\n", srcpath, strerror(errno));
1075
+ return 0;
1076
+ }
1077
+ } else {
1078
+ return put_single_file(afc, srcpath, dstpath, force_overwrite);
1079
+ }
1080
+ return 1;
1081
+ }
1082
+
1083
+ static void handle_put(afc_client_t afc, int argc, char **argv)
1084
+ {
1085
+ if (argc < 1) {
1086
+ printf("Error: Invalid number of arguments\n");
1087
+ return;
1088
+ }
1089
+ int i = 0;
1090
+ uint8_t force_overwrite = 0, recursive_put = 0;
1091
+ for ( ; i < argc; i++) {
1092
+ if (!strcmp(argv[i], "--")) {
1093
+ i++;
1094
+ break;
1095
+ } else if (!strcmp(argv[i], "-r")) {
1096
+ recursive_put = 1;
1097
+ } else if (!strcmp(argv[i], "-f")) {
1098
+ force_overwrite = 1;
1099
+ } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
1100
+ recursive_put = 1;
1101
+ force_overwrite = 1;
1102
+ } else {
1103
+ break;
1104
+ }
1105
+ }
1106
+ if (i >= argc) {
1107
+ printf("Error: Invalid number of arguments\n");
1108
+ return;
1109
+ }
1110
+ char *srcpath = strdup(argv[i]);
1111
+ size_t src_len = strlen(srcpath);
1112
+ if (src_len > 1 && srcpath[src_len - 1] == '/') {
1113
+ srcpath[src_len - 1] = '\0';
1114
+ }
1115
+ char *dstpath = NULL;
1116
+ if (argc - i == 1) {
1117
+ dstpath = get_absolute_path(path_get_basename(srcpath));
1118
+ } else if (argc - i == 2) {
1119
+ char *tmp = strdup(argv[i + 1]);
1120
+ size_t dst_len = strlen(tmp);
1121
+ if (dst_len > 1 && tmp[dst_len - 1] == '/') {
1122
+ tmp[dst_len - 1] = '\0';
1123
+ }
1124
+ dstpath = get_absolute_path(tmp);
1125
+ free(tmp);
1126
+ } else {
1127
+ printf("Error: Invalid number of arguments\n");
1128
+ return;
1129
+ }
1130
+ plist_t info = NULL;
1131
+ afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
1132
+ // target does not exist, put directly
1133
+ if (err == AFC_E_OBJECT_NOT_FOUND) {
1134
+ put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
1135
+ free(srcpath);
1136
+ free(dstpath);
1137
+ } else {
1138
+ uint8_t is_dir = 0;
1139
+ if (info) {
1140
+ const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1141
+ is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1142
+ plist_free(info);
1143
+ }
1144
+ // target is a directory, try to put under this directory
1145
+ if (is_dir) {
1146
+ const char *basen = path_get_basename(srcpath);
1147
+ uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
1148
+ size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
1149
+ char *newdst = (char *) malloc(len);
1150
+ if (dst_is_root) {
1151
+ snprintf(newdst, len, "/%s", basen);
1152
+ } else {
1153
+ snprintf(newdst, len, "%s/%s", dstpath, basen);
1154
+ }
1155
+ free(dstpath);
1156
+ dstpath = get_absolute_path(newdst);
1157
+ free(newdst);
1158
+ put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
1159
+ } else {
1160
+ //target is common file, rewrite it
1161
+ put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
1162
+ }
1163
+ free(srcpath);
1164
+ free(dstpath);
1165
+ }
1166
+ }
1167
+
1168
+ static void handle_pwd(afc_client_t afc, int argc, char** argv)
1169
+ {
1170
+ printf("%s\n", curdir);
1171
+ }
1172
+
1173
+ static void handle_cd(afc_client_t afc, int argc, char** argv)
1174
+ {
1175
+ if (argc != 1) {
1176
+ printf("Error: Invalid number of arguments\n");
1177
+ return;
1178
+ }
1179
+
1180
+ if (!strcmp(argv[0], ".")) {
1181
+ return;
1182
+ }
1183
+
1184
+ if (!strcmp(argv[0], "..")) {
1185
+ if (!strcmp(curdir, "/")) {
1186
+ return;
1187
+ }
1188
+ char *p = strrchr(curdir, '/');
1189
+ if (!p) {
1190
+ strcpy(curdir, "/");
1191
+ return;
1192
+ }
1193
+ if (p == curdir) {
1194
+ *(p+1) = '\0';
1195
+ } else {
1196
+ *p = '\0';
1197
+ }
1198
+ return;
1199
+ }
1200
+
1201
+ char* path = get_realpath(argv[0]);
1202
+ int is_dir = 0;
1203
+ plist_t info = NULL;
1204
+ afc_error_t err = afc_get_file_info_plist(afc, path, &info);
1205
+ if (err == AFC_E_SUCCESS && info) {
1206
+ const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
1207
+ is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
1208
+ plist_free(info);
1209
+ } else {
1210
+ printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err);
1211
+ free(path);
1212
+ return;
1213
+ }
1214
+
1215
+ if (!is_dir) {
1216
+ printf("Error: '%s' is not a valid directory\n", path);
1217
+ free(path);
1218
+ return;
1219
+ }
1220
+
1221
+ free(curdir);
1222
+ curdir = path;
1223
+ curdir_len = strlen(curdir);
1224
+ }
1225
+
1226
+ static void parse_cmdline(int* p_argc, char*** p_argv, const char* cmdline)
1227
+ {
1228
+ char **argv = NULL;
1229
+ int argc = 0;
1230
+ size_t maxlen = strlen(cmdline);
1231
+ const char* pos = cmdline;
1232
+ const char* qpos = NULL;
1233
+ char *tmpbuf = NULL;
1234
+ int tmplen = 0;
1235
+ int is_error = 0;
1236
+
1237
+ /* skip initial whitespace */
1238
+ while (isspace(*pos)) pos++;
1239
+ maxlen -= (pos - cmdline);
1240
+
1241
+ tmpbuf = (char*)malloc(maxlen+1);
1242
+
1243
+ while (!is_error) {
1244
+ if (*pos == '\\') {
1245
+ pos++;
1246
+ switch (*pos) {
1247
+ case '"':
1248
+ case '\'':
1249
+ case '\\':
1250
+ case ' ':
1251
+ tmpbuf[tmplen++] = *pos;
1252
+ pos++;
1253
+ break;
1254
+ default:
1255
+ printf("Error: Invalid escape sequence\n");
1256
+ is_error++;
1257
+ break;
1258
+ }
1259
+ } else if (*pos == '"' || *pos == '\'') {
1260
+ if (!qpos) {
1261
+ qpos = pos;
1262
+ } else {
1263
+ qpos = NULL;
1264
+ }
1265
+ pos++;
1266
+ } else if (*pos == '\0' || (!qpos && isspace(*pos))) {
1267
+ tmpbuf[tmplen] = '\0';
1268
+ if (*pos == '\0' && qpos) {
1269
+ printf("Error: Unmatched `%c`\n", *qpos);
1270
+ is_error++;
1271
+ break;
1272
+ }
1273
+ char** new_argv = (char**)realloc(argv, (argc+1)*sizeof(char*));
1274
+ if (new_argv == NULL) {
1275
+ printf("Error: Out of memory?!\n");
1276
+ is_error++;
1277
+ break;
1278
+ }
1279
+ argv = new_argv;
1280
+ /* shrink buffer to actual argument size */
1281
+ argv[argc] = (char*)realloc(tmpbuf, tmplen+1);
1282
+ if (!argv[argc]) {
1283
+ printf("Error: Out of memory?!\n");
1284
+ is_error++;
1285
+ break;
1286
+ }
1287
+ argc++;
1288
+ tmpbuf = NULL;
1289
+ if (*pos == '\0') {
1290
+ break;
1291
+ }
1292
+ maxlen -= tmplen;
1293
+ tmpbuf = (char*)malloc(maxlen+1);
1294
+ tmplen = 0;
1295
+ while (isspace(*pos)) pos++;
1296
+ } else {
1297
+ tmpbuf[tmplen++] = *pos;
1298
+ pos++;
1299
+ }
1300
+ }
1301
+ if (tmpbuf) {
1302
+ free(tmpbuf);
1303
+ }
1304
+ if (is_error) {
1305
+ int i;
1306
+ for (i = 0; argv && i < argc; i++) free(argv[i]);
1307
+ free(argv);
1308
+ return;
1309
+ }
1310
+
1311
+ *p_argv = argv;
1312
+ *p_argc = argc;
1313
+ }
1314
+
1315
+ static int process_args(afc_client_t afc, int argc, char** argv)
1316
+ {
1317
+ if (!strcmp(argv[0], "q") || !strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
1318
+ return -1;
1319
+ }
1320
+ else if (!strcmp(argv[0], "help")) {
1321
+ handle_help(afc, argc, argv);
1322
+ }
1323
+ else if (!strcmp(argv[0], "devinfo") || !strcmp(argv[0], "deviceinfo")) {
1324
+ handle_devinfo(afc, argc-1, argv+1);
1325
+ }
1326
+ else if (!strcmp(argv[0], "info")) {
1327
+ handle_file_info(afc, argc-1, argv+1);
1328
+ }
1329
+ else if (!strcmp(argv[0], "ls") || !strcmp(argv[0], "list")) {
1330
+ handle_list(afc, argc-1, argv+1);
1331
+ }
1332
+ else if (!strcmp(argv[0], "mv") || !strcmp(argv[0], "rename")) {
1333
+ handle_rename(afc, argc-1, argv+1);
1334
+ }
1335
+ else if (!strcmp(argv[0], "mkdir")) {
1336
+ handle_mkdir(afc, argc-1, argv+1);
1337
+ }
1338
+ else if (!strcmp(argv[0], "ln")) {
1339
+ handle_link(afc, argc-1, argv+1);
1340
+ }
1341
+ else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove")) {
1342
+ handle_remove(afc, argc-1, argv+1);
1343
+ }
1344
+ else if (!strcmp(argv[0], "get")) {
1345
+ handle_get(afc, argc-1, argv+1);
1346
+ }
1347
+ else if (!strcmp(argv[0], "put")) {
1348
+ handle_put(afc, argc-1, argv+1);
1349
+ }
1350
+ else if (!strcmp(argv[0], "pwd")) {
1351
+ handle_pwd(afc, argc-1, argv+1);
1352
+ }
1353
+ else if (!strcmp(argv[0], "cd")) {
1354
+ handle_cd(afc, argc-1, argv+1);
1355
+ }
1356
+ else {
1357
+ printf("Unknown command '%s'. Type 'help' to get a list of available commands.\n", argv[0]);
1358
+ }
1359
+ return 0;
1360
+ }
1361
+
1362
+ static void start_cmdline(afc_client_t afc)
1363
+ {
1364
+ while (!stop_requested) {
1365
+ int argc = 0;
1366
+ char **argv = NULL;
1367
+ char prompt[128];
1368
+ int plen = curdir_len;
1369
+ char *ppath = curdir;
1370
+ int plim = (int)(sizeof(prompt)/2)-8;
1371
+ if (plen > plim) {
1372
+ ppath = curdir + (plen - plim);
1373
+ plen = plim;
1374
+ }
1375
+ snprintf(prompt, 128, FG_BLACK BG_LIGHT_GRAY "afc:" COLOR_RESET FG_BRIGHT_YELLOW BG_BLUE "%.*s" COLOR_RESET " > ", plen, ppath);
1376
+ #ifdef HAVE_READLINE
1377
+ char* cmd = readline(prompt);
1378
+ if (!cmd || !*cmd) {
1379
+ free(cmd);
1380
+ continue;
1381
+ }
1382
+ add_history(cmd);
1383
+ parse_cmdline(&argc, &argv, cmd);
1384
+ #else
1385
+ char cmdbuf[4096];
1386
+ printf("%s", prompt);
1387
+ fflush(stdout);
1388
+ get_input(cmdbuf, sizeof(cmdbuf));
1389
+ parse_cmdline(&argc, &argv, cmdbuf);
1390
+ #endif
1391
+ #ifdef HAVE_READLINE
1392
+ free(cmd);
1393
+ #endif
1394
+ /* process arguments */
1395
+ if (argv && argv[0]) {
1396
+ if (process_args(afc, argc, argv) < 0) {
1397
+ break;
1398
+ }
1399
+ }
1400
+ }
1401
+ }
1402
+
1403
+ static void device_event_cb(const idevice_event_t* event, void* userdata)
1404
+ {
1405
+ if (use_network && event->conn_type != CONNECTION_NETWORK) {
1406
+ return;
1407
+ } else if (!use_network && event->conn_type != CONNECTION_USBMUXD) {
1408
+ return;
1409
+ }
1410
+ if (event->event == IDEVICE_DEVICE_ADD) {
1411
+ if (!udid) {
1412
+ udid = strdup(event->udid);
1413
+ }
1414
+ if (strcmp(udid, event->udid) == 0) {
1415
+ connected = 1;
1416
+ }
1417
+ } else if (event->event == IDEVICE_DEVICE_REMOVE) {
1418
+ if (strcmp(udid, event->udid) == 0) {
1419
+ connected = 0;
1420
+ printf("\n[disconnected]\n");
1421
+ handle_signal(SIGINT);
1422
+ }
1423
+ }
1424
+ }
1425
+
1426
+ int main(int argc, char** argv)
1427
+ {
1428
+ const char* appid = NULL;
1429
+ int ret = 0;
1430
+ idevice_t device = NULL;
1431
+ lockdownd_client_t lockdown = NULL;
1432
+ lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
1433
+ lockdownd_service_descriptor_t service = NULL;
1434
+ afc_client_t afc = NULL;
1435
+ house_arrest_client_t house_arrest = NULL;
1436
+ const char* service_name = AFC_SERVICE_NAME;
1437
+ int use_container = 0;
1438
+
1439
+ int c = 0;
1440
+ const struct option longopts[] = {
1441
+ { "udid", required_argument, NULL, 'u' },
1442
+ { "network", no_argument, NULL, 'n' },
1443
+ { "help", no_argument, NULL, 'h' },
1444
+ { "debug", no_argument, NULL, 'd' },
1445
+ { "version", no_argument, NULL, 'v' },
1446
+ { "documents", required_argument, NULL, OPT_DOCUMENTS },
1447
+ { "container", required_argument, NULL, OPT_CONTAINER },
1448
+ { NULL, 0, NULL, 0}
1449
+ };
1450
+
1451
+ signal(SIGTERM, handle_signal);
1452
+ #ifndef _WIN32
1453
+ signal(SIGQUIT, handle_signal);
1454
+ signal(SIGPIPE, SIG_IGN);
1455
+ #endif
1456
+
1457
+ while ((c = getopt_long(argc, argv, "du:nhv", longopts, NULL)) != -1) {
1458
+ switch (c) {
1459
+ case 'd':
1460
+ idevice_set_debug_level(1);
1461
+ break;
1462
+ case 'u':
1463
+ if (!*optarg) {
1464
+ fprintf(stderr, "ERROR: UDID must not be empty!\n");
1465
+ print_usage(argc, argv, 1);
1466
+ return 2;
1467
+ }
1468
+ udid = strdup(optarg);
1469
+ break;
1470
+ case 'n':
1471
+ use_network = 1;
1472
+ break;
1473
+ case 'h':
1474
+ print_usage(argc, argv, 0);
1475
+ return 0;
1476
+ case 'v':
1477
+ printf("%s %s", TOOL_NAME, PACKAGE_VERSION);
1478
+ #ifdef HAVE_READLINE
1479
+ printf(" (readline)");
1480
+ #endif
1481
+ printf("\n");
1482
+ return 0;
1483
+ case OPT_DOCUMENTS:
1484
+ if (!*optarg) {
1485
+ fprintf(stderr, "ERROR: '--documents' requires a non-empty app ID!\n");
1486
+ print_usage(argc, argv, 1);
1487
+ return 2;
1488
+ }
1489
+ appid = optarg;
1490
+ use_container = 0;
1491
+ break;
1492
+ case OPT_CONTAINER:
1493
+ if (!*optarg) {
1494
+ fprintf(stderr, "ERROR: '--container' requires a not-empty app ID!\n");
1495
+ print_usage(argc, argv, 1);
1496
+ return 2;
1497
+ }
1498
+ appid = optarg;
1499
+ use_container = 1;
1500
+ break;
1501
+ default:
1502
+ print_usage(argc, argv, 1);
1503
+ return 2;
1504
+ }
1505
+ }
1506
+
1507
+ argc -= optind;
1508
+ argv += optind;
1509
+
1510
+ int num = 0;
1511
+ idevice_info_t *devices = NULL;
1512
+ idevice_get_device_list_extended(&devices, &num);
1513
+ int count = 0;
1514
+ for (int i = 0; i < num; i++) {
1515
+ if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) {
1516
+ count++;
1517
+ } else if (devices[i]->conn_type == CONNECTION_USBMUXD) {
1518
+ count++;
1519
+ }
1520
+ }
1521
+ idevice_device_list_extended_free(devices);
1522
+ if (count == 0) {
1523
+ fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n");
1524
+ return 1;
1525
+ }
1526
+
1527
+ idevice_events_subscribe(&context, device_event_cb, NULL);
1528
+
1529
+ while (!connected && !stop_requested) {
1530
+ #ifdef _WIN32
1531
+ Sleep(100);
1532
+ #else
1533
+ usleep(100000);
1534
+ #endif
1535
+ }
1536
+ if (stop_requested) {
1537
+ return 0;
1538
+ }
1539
+
1540
+ ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
1541
+ if (ret != IDEVICE_E_SUCCESS) {
1542
+ if (udid) {
1543
+ fprintf(stderr, "ERROR: Device %s not found!\n", udid);
1544
+ } else {
1545
+ fprintf(stderr, "ERROR: No device found!\n");
1546
+ }
1547
+ return 1;
1548
+ }
1549
+
1550
+ do {
1551
+ if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) {
1552
+ fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret);
1553
+ ret = 1;
1554
+ break;
1555
+ }
1556
+
1557
+ if (appid) {
1558
+ service_name = HOUSE_ARREST_SERVICE_NAME;
1559
+ }
1560
+
1561
+ ldret = lockdownd_start_service(lockdown, service_name, &service);
1562
+ if (ldret != LOCKDOWN_E_SUCCESS) {
1563
+ fprintf(stderr, "ERROR: Failed to start service %s: %s (%d)\n", service_name, lockdownd_strerror(ldret), ldret);
1564
+ ret = 1;
1565
+ break;
1566
+ }
1567
+
1568
+ if (appid) {
1569
+ house_arrest_client_new(device, service, &house_arrest);
1570
+ if (!house_arrest) {
1571
+ fprintf(stderr, "Could not start document sharing service!\n");
1572
+ ret = 1;
1573
+ break;
1574
+ }
1575
+
1576
+ if (house_arrest_send_command(house_arrest, use_container ? "VendContainer": "VendDocuments", appid) != HOUSE_ARREST_E_SUCCESS) {
1577
+ fprintf(stderr, "Could not send house_arrest command!\n");
1578
+ ret = 1;
1579
+ break;
1580
+ }
1581
+
1582
+ plist_t dict = NULL;
1583
+ if (house_arrest_get_result(house_arrest, &dict) != HOUSE_ARREST_E_SUCCESS) {
1584
+ fprintf(stderr, "Could not get result from document sharing service!\n");
1585
+ break;
1586
+ }
1587
+ plist_t node = plist_dict_get_item(dict, "Error");
1588
+ if (node) {
1589
+ char *str = NULL;
1590
+ plist_get_string_val(node, &str);
1591
+ fprintf(stderr, "ERROR: %s\n", str);
1592
+ if (str && !strcmp(str, "InstallationLookupFailed")) {
1593
+ fprintf(stderr, "The App '%s' is either not present on the device, or the 'UIFileSharingEnabled' key is not set in its Info.plist. Starting with iOS 8.3 this key is mandatory to allow access to an app's Documents folder.\n", appid);
1594
+ }
1595
+ free(str);
1596
+ plist_free(dict);
1597
+ break;
1598
+ }
1599
+ plist_free(dict);
1600
+ afc_client_new_from_house_arrest_client(house_arrest, &afc);
1601
+ } else {
1602
+ afc_client_new(device, service, &afc);
1603
+ }
1604
+ lockdownd_service_descriptor_free(service);
1605
+ lockdownd_client_free(lockdown);
1606
+ lockdown = NULL;
1607
+
1608
+ curdir = strdup("/");
1609
+ curdir_len = 1;
1610
+
1611
+ if (argc > 0) {
1612
+ // command line mode
1613
+ process_args(afc, argc, argv);
1614
+ } else {
1615
+ // interactive mode
1616
+ start_cmdline(afc);
1617
+ }
1618
+
1619
+ } while (0);
1620
+
1621
+ if (afc) {
1622
+ afc_client_free(afc);
1623
+ }
1624
+ if (lockdown) {
1625
+ lockdownd_client_free(lockdown);
1626
+ }
1627
+ idevice_free(device);
1628
+
1629
+ return ret;
1630
+ }
as-compiler-flag.m4 ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dnl as-compiler-flag.m4 0.1.0
2
+
3
+ dnl autostars m4 macro for detection of compiler flags
4
+
5
+ dnl David Schleef <ds@schleef.org>
6
+
7
+ dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
8
+
9
+ dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
10
+ dnl Tries to compile with the given CFLAGS.
11
+ dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
12
+ dnl and ACTION-IF-NOT-ACCEPTED otherwise.
13
+
14
+ AC_DEFUN([AS_COMPILER_FLAG],
15
+ [
16
+ AC_MSG_CHECKING([to see if compiler understands $1])
17
+
18
+ save_CFLAGS="$CFLAGS"
19
+ CFLAGS="$CFLAGS $1"
20
+
21
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
22
+ CFLAGS="$save_CFLAGS"
23
+
24
+ if test "X$flag_ok" = Xyes ; then
25
+ m4_ifvaln([$2],[$2])
26
+ true
27
+ else
28
+ m4_ifvaln([$3],[$3])
29
+ true
30
+ fi
31
+ AC_MSG_RESULT([$flag_ok])
32
+ ])
33
+
34
+ dnl AS_COMPILER_FLAGS(VAR, FLAGS)
35
+ dnl Tries to compile with the given CFLAGS.
36
+
37
+ AC_DEFUN([AS_COMPILER_FLAGS],
38
+ [
39
+ list=$2
40
+ flags_supported=""
41
+ flags_unsupported=""
42
+ AC_MSG_CHECKING([for supported compiler flags])
43
+ for each in $list
44
+ do
45
+ save_CFLAGS="$CFLAGS"
46
+ CFLAGS="$CFLAGS $each"
47
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
48
+ CFLAGS="$save_CFLAGS"
49
+
50
+ if test "X$flag_ok" = Xyes ; then
51
+ flags_supported="$flags_supported $each"
52
+ else
53
+ flags_unsupported="$flags_unsupported $each"
54
+ fi
55
+ done
56
+ AC_MSG_RESULT([$flags_supported])
57
+ if test "X$flags_unsupported" != X ; then
58
+ AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
59
+ fi
60
+ $1="$$1 $flags_supported"
61
+ ])
62
+
asprintf.h ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef __ASPRINTF_H
2
+ #define __ASPRINTF_H
3
+
4
+ #ifdef HAVE_CONFIG_H
5
+ #include <config.h>
6
+ #endif
7
+
8
+ #include <stdio.h>
9
+
10
+ #ifndef HAVE_VASPRINTF
11
+ static inline int vasprintf(char **PTR, const char *TEMPLATE, va_list AP)
12
+ {
13
+ int res;
14
+ char buf[16];
15
+ res = vsnprintf(buf, 16, TEMPLATE, AP);
16
+ if (res > 0) {
17
+ *PTR = (char*)malloc(res+1);
18
+ res = vsnprintf(*PTR, res+1, TEMPLATE, AP);
19
+ }
20
+ return res;
21
+ }
22
+ #endif
23
+
24
+ #ifndef HAVE_ASPRINTF
25
+ static inline int asprintf(char **PTR, const char *TEMPLATE, ...)
26
+ {
27
+ int res;
28
+ va_list AP;
29
+ va_start(AP, TEMPLATE);
30
+ res = vasprintf(PTR, TEMPLATE, AP);
31
+ va_end(AP);
32
+ return res;
33
+ }
34
+ #endif
35
+
36
+ #endif /* ASPRINTF_H */
asr.c ADDED
@@ -0,0 +1,461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * asr.c
3
+ * Functions for handling asr connections
4
+ *
5
+ * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved.
6
+ * Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifdef HAVE_CONFIG_H
25
+ #include <config.h>
26
+ #endif
27
+ #include <stdio.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <unistd.h>
31
+ #include <errno.h>
32
+ #include <libimobiledevice/libimobiledevice.h>
33
+ #ifdef HAVE_OPENSSL
34
+ #include <openssl/sha.h>
35
+ #else
36
+ #include "sha1.h"
37
+ #define SHA_CTX SHA1_CTX
38
+ #define SHA1_Init SHA1Init
39
+ #define SHA1_Update SHA1Update
40
+ #define SHA1_Final SHA1Final
41
+ #endif
42
+
43
+ #include "asr.h"
44
+ #include "idevicerestore.h"
45
+ #include "common.h"
46
+
47
+ #define ASR_VERSION 1
48
+ #define ASR_STREAM_ID 1
49
+ #define ASR_PORT 12345
50
+ #define ASR_BUFFER_SIZE 65536
51
+ #define ASR_FEC_SLICE_STRIDE 40
52
+ #define ASR_PACKETS_PER_FEC 25
53
+ #define ASR_PAYLOAD_PACKET_SIZE 1450
54
+ #define ASR_PAYLOAD_CHUNK_SIZE 131072
55
+ #define ASR_CHECKSUM_CHUNK_SIZE 131072
56
+
57
+ int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
58
+ {
59
+ int i = 0;
60
+ int attempts = 10;
61
+ idevice_connection_t connection = NULL;
62
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
63
+
64
+ *asr = NULL;
65
+
66
+ if (device == NULL) {
67
+ return -1;
68
+ }
69
+
70
+ debug("Connecting to ASR\n");
71
+ for (i = 1; i <= attempts; i++) {
72
+ device_error = idevice_connect(device, ASR_PORT, &connection);
73
+ if (device_error == IDEVICE_E_SUCCESS) {
74
+ break;
75
+ }
76
+
77
+ if (i >= attempts) {
78
+ error("ERROR: Unable to connect to ASR client\n");
79
+ return -1;
80
+ }
81
+
82
+ sleep(2);
83
+ debug("Retrying connection...\n");
84
+ }
85
+
86
+ asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client));
87
+ memset(asr_loc, '\0', sizeof(struct asr_client));
88
+ asr_loc->connection = connection;
89
+
90
+ /* receive Initiate command message */
91
+ plist_t data = NULL;
92
+ asr_loc->checksum_chunks = 0;
93
+ if (asr_receive(asr_loc, &data) < 0) {
94
+ error("ERROR: Unable to receive data from ASR\n");
95
+ asr_free(asr_loc);
96
+ plist_free(data);
97
+ return -1;
98
+ }
99
+ plist_t node;
100
+ node = plist_dict_get_item(data, "Command");
101
+ if (node && (plist_get_node_type(node) == PLIST_STRING)) {
102
+ char* strval = NULL;
103
+ plist_get_string_val(node, &strval);
104
+ if (strval && (strcmp(strval, "Initiate") != 0)) {
105
+ error("ERROR: unexpected ASR plist received:\n");
106
+ debug_plist(data);
107
+ plist_free(data);
108
+ asr_free(asr_loc);
109
+ return -1;
110
+ }
111
+ }
112
+
113
+ node = plist_dict_get_item(data, "Checksum Chunks");
114
+ if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
115
+ plist_get_bool_val(node, &(asr_loc->checksum_chunks));
116
+ }
117
+ plist_free(data);
118
+
119
+ *asr = asr_loc;
120
+
121
+ return 0;
122
+ }
123
+
124
+ void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t cbfunc, void* userdata)
125
+ {
126
+ if (!asr) {
127
+ return;
128
+ }
129
+ asr->progress_cb = cbfunc;
130
+ asr->progress_cb_data = userdata;
131
+ }
132
+
133
+ int asr_receive(asr_client_t asr, plist_t* data)
134
+ {
135
+ uint32_t size = 0;
136
+ char* buffer = NULL;
137
+ plist_t request = NULL;
138
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
139
+
140
+ *data = NULL;
141
+
142
+ buffer = (char*)malloc(ASR_BUFFER_SIZE);
143
+ if (buffer == NULL) {
144
+ error("ERROR: Unable to allocate memory for ASR receive buffer\n");
145
+ return -1;
146
+ }
147
+
148
+ device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size);
149
+ if (device_error != IDEVICE_E_SUCCESS) {
150
+ error("ERROR: Unable to receive data from ASR\n");
151
+ free(buffer);
152
+ return -1;
153
+ }
154
+ plist_from_xml(buffer, size, &request);
155
+
156
+ *data = request;
157
+
158
+ debug("Received %d bytes:\n", size);
159
+ if (idevicerestore_debug)
160
+ debug_plist(request);
161
+ free(buffer);
162
+ return 0;
163
+ }
164
+
165
+ int asr_send(asr_client_t asr, plist_t data)
166
+ {
167
+ uint32_t size = 0;
168
+ char* buffer = NULL;
169
+
170
+ plist_to_xml(data, &buffer, &size);
171
+ if (asr_send_buffer(asr, buffer, size) < 0) {
172
+ error("ERROR: Unable to send plist to ASR\n");
173
+ free(buffer);
174
+ return -1;
175
+ }
176
+
177
+ if (buffer)
178
+ free(buffer);
179
+ return 0;
180
+ }
181
+
182
+ int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size)
183
+ {
184
+ uint32_t bytes = 0;
185
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
186
+
187
+ device_error = idevice_connection_send(asr->connection, data, size, &bytes);
188
+ if (device_error != IDEVICE_E_SUCCESS || bytes != size) {
189
+ error("ERROR: Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size);
190
+ return -1;
191
+ }
192
+
193
+ return 0;
194
+ }
195
+
196
+ void asr_free(asr_client_t asr)
197
+ {
198
+ if (asr != NULL) {
199
+ if (asr->connection != NULL) {
200
+ idevice_disconnect(asr->connection);
201
+ asr->connection = NULL;
202
+ }
203
+ free(asr);
204
+ asr = NULL;
205
+ }
206
+ }
207
+
208
+ int asr_perform_validation(asr_client_t asr, const char* filesystem)
209
+ {
210
+ FILE* file = NULL;
211
+ uint64_t length = 0;
212
+ char* command = NULL;
213
+ plist_t node = NULL;
214
+ plist_t packet = NULL;
215
+ plist_t packet_info = NULL;
216
+ plist_t payload_info = NULL;
217
+ int attempts = 0;
218
+
219
+ file = fopen(filesystem, "rb");
220
+ if (file == NULL) {
221
+ return -1;
222
+ }
223
+
224
+ #ifdef WIN32
225
+ length = _lseeki64(fileno(file), 0, SEEK_END);
226
+ _lseeki64(fileno(file), 0, SEEK_SET);
227
+ rewind(file);
228
+ #else
229
+ fseeko(file, 0, SEEK_END);
230
+ length = ftello(file);
231
+ fseeko(file, 0, SEEK_SET);
232
+ #endif
233
+
234
+ payload_info = plist_new_dict();
235
+ plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
236
+ plist_dict_set_item(payload_info, "Size", plist_new_uint(length));
237
+
238
+ packet_info = plist_new_dict();
239
+ if (asr->checksum_chunks) {
240
+ plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE));
241
+ }
242
+ plist_dict_set_item(packet_info, "FEC Slice Stride", plist_new_uint(ASR_FEC_SLICE_STRIDE));
243
+ plist_dict_set_item(packet_info, "Packet Payload Size", plist_new_uint(ASR_PAYLOAD_PACKET_SIZE));
244
+ plist_dict_set_item(packet_info, "Packets Per FEC", plist_new_uint(ASR_PACKETS_PER_FEC));
245
+ plist_dict_set_item(packet_info, "Payload", payload_info);
246
+ plist_dict_set_item(packet_info, "Stream ID", plist_new_uint(ASR_STREAM_ID));
247
+ plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION));
248
+
249
+ if (asr_send(asr, packet_info)) {
250
+ error("ERROR: Unable to sent packet information to ASR\n");
251
+ plist_free(packet_info);
252
+ return -1;
253
+ }
254
+ plist_free(packet_info);
255
+
256
+ while (1) {
257
+ if (asr_receive(asr, &packet) < 0) {
258
+ error("ERROR: Unable to receive validation packet\n");
259
+ return -1;
260
+ }
261
+
262
+ if (packet == NULL) {
263
+ if (attempts < 5) {
264
+ info("Retrying to receive validation packet... %d\n", attempts);
265
+ attempts++;
266
+ sleep(1);
267
+ continue;
268
+ }
269
+ }
270
+
271
+ attempts = 0;
272
+
273
+ node = plist_dict_get_item(packet, "Command");
274
+ if (!node || plist_get_node_type(node) != PLIST_STRING) {
275
+ error("ERROR: Unable to find command node in validation request\n");
276
+ return -1;
277
+ }
278
+ plist_get_string_val(node, &command);
279
+
280
+ if (!strcmp(command, "OOBData")) {
281
+ int ret = asr_handle_oob_data_request(asr, packet, file);
282
+ plist_free(packet);
283
+ if (ret < 0)
284
+ return ret;
285
+ } else if(!strcmp(command, "Payload")) {
286
+ plist_free(packet);
287
+ break;
288
+
289
+ } else {
290
+ error("ERROR: Unknown command received from ASR\n");
291
+ plist_free(packet);
292
+ return -1;
293
+ }
294
+ }
295
+
296
+ return 0;
297
+ }
298
+
299
+ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file)
300
+ {
301
+ char* oob_data = NULL;
302
+ uint64_t oob_offset = 0;
303
+ uint64_t oob_length = 0;
304
+ plist_t oob_length_node = NULL;
305
+ plist_t oob_offset_node = NULL;
306
+
307
+ oob_length_node = plist_dict_get_item(packet, "OOB Length");
308
+ if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
309
+ error("ERROR: Unable to find OOB data length\n");
310
+ return -1;
311
+ }
312
+ plist_get_uint_val(oob_length_node, &oob_length);
313
+
314
+ oob_offset_node = plist_dict_get_item(packet, "OOB Offset");
315
+ if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
316
+ error("ERROR: Unable to find OOB data offset\n");
317
+ return -1;
318
+ }
319
+ plist_get_uint_val(oob_offset_node, &oob_offset);
320
+
321
+ oob_data = (char*) malloc(oob_length);
322
+ if (oob_data == NULL) {
323
+ error("ERROR: Out of memory\n");
324
+ return -1;
325
+ }
326
+
327
+ #ifdef WIN32
328
+ rewind(file);
329
+ _lseeki64(fileno(file), oob_offset, SEEK_SET);
330
+ #else
331
+ fseeko(file, oob_offset, SEEK_SET);
332
+ #endif
333
+ if (fread(oob_data, 1, oob_length, file) != oob_length) {
334
+ error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno));
335
+ free(oob_data);
336
+ return -1;
337
+ }
338
+
339
+ if (asr_send_buffer(asr, oob_data, oob_length) < 0) {
340
+ error("ERROR: Unable to send OOB data to ASR\n");
341
+ free(oob_data);
342
+ return -1;
343
+ }
344
+ free(oob_data);
345
+ return 0;
346
+ }
347
+
348
+ int asr_send_payload(asr_client_t asr, const char* filesystem)
349
+ {
350
+ char *data = NULL;
351
+ FILE* file = NULL;
352
+ uint64_t i, length, bytes = 0;
353
+ double progress = 0;
354
+
355
+ file = fopen(filesystem, "rb");
356
+ if (file == NULL) {
357
+ error("ERROR: Unable to open filesystem image %s: %s\n", filesystem, strerror(errno));
358
+ return -1;
359
+ }
360
+
361
+ #ifdef WIN32
362
+ length = _lseeki64(fileno(file), 0, SEEK_END);
363
+ _lseeki64(fileno(file), 0, SEEK_SET);
364
+ rewind(file);
365
+ #else
366
+ fseeko(file, 0, SEEK_END);
367
+ length = ftello(file);
368
+ fseeko(file, 0, SEEK_SET);
369
+ #endif
370
+
371
+ int chunk = 0;
372
+ int add_checksum = 0;
373
+ data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE);
374
+
375
+ SHA_CTX sha1;
376
+
377
+ if (asr->checksum_chunks) {
378
+ SHA1_Init(&sha1);
379
+ }
380
+
381
+ int size = 0;
382
+ for (i = length; i > 0; i -= size) {
383
+ size = ASR_PAYLOAD_CHUNK_SIZE;
384
+ if (i < ASR_PAYLOAD_CHUNK_SIZE) {
385
+ size = i;
386
+ }
387
+
388
+ if (add_checksum) {
389
+ add_checksum = 0;
390
+ }
391
+
392
+ if (asr->checksum_chunks && ((chunk + size) >= ASR_CHECKSUM_CHUNK_SIZE)) {
393
+ // reduce packet size to match checksum chunk size
394
+ size -= ((chunk + size) - ASR_CHECKSUM_CHUNK_SIZE);
395
+ add_checksum = 1;
396
+ }
397
+
398
+ if (fread(data, 1, size, file) != (size_t)size) {
399
+ error("Error reading filesystem\n");
400
+ free(data);
401
+ fclose(file);
402
+ return -1;
403
+ }
404
+
405
+ if (asr_send_buffer(asr, data, size) < 0) {
406
+ error("ERROR: Unable to send filesystem payload\n");
407
+ free(data);
408
+ fclose(file);
409
+ return -1;
410
+ }
411
+
412
+ if (asr->checksum_chunks) {
413
+ SHA1_Update(&sha1, (unsigned char*)data, size);
414
+ chunk += size;
415
+
416
+ if (add_checksum) {
417
+ // get sha1 of last chunk
418
+ SHA1_Final((unsigned char*)data, &sha1);
419
+
420
+ // send checksum
421
+ if (asr_send_buffer(asr, data, 20) < 0) {
422
+ error("ERROR: Unable to send chunk checksum\n");
423
+ free(data);
424
+ fclose(file);
425
+ return -1;
426
+ }
427
+
428
+ // reset SHA1 context
429
+ SHA1_Init(&sha1);
430
+
431
+ // reset chunk byte counter
432
+ chunk = 0;
433
+ }
434
+ }
435
+
436
+ bytes += size;
437
+ progress = ((double)bytes / (double)length);
438
+ if (asr->progress_cb && ((int)(progress*100) > asr->lastprogress)) {
439
+ asr->progress_cb(progress, asr->progress_cb_data);
440
+ asr->lastprogress = (int)(progress*100);
441
+ }
442
+ }
443
+
444
+ // if last chunk wasn't terminated with a checksum we do it here
445
+ if (asr->checksum_chunks && !add_checksum) {
446
+ // get sha1 of last chunk
447
+ SHA1_Final((unsigned char*)data, &sha1);
448
+
449
+ // send checksum
450
+ if (asr_send_buffer(asr, data, 20) < 0) {
451
+ error("ERROR: Unable to send chunk checksum\n");
452
+ free(data);
453
+ fclose(file);
454
+ return -1;
455
+ }
456
+ }
457
+
458
+ free(data);
459
+ fclose(file);
460
+ return 0;
461
+ }
asr.h ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * asr.h
3
+ * Functions for handling asr connections
4
+ *
5
+ * Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
6
+ * Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifndef IDEVICERESTORE_ASR_H
25
+ #define IDEVICERESTORE_ASR_H
26
+
27
+ #ifdef __cplusplus
28
+ extern "C" {
29
+ #endif
30
+
31
+ #include <libimobiledevice/libimobiledevice.h>
32
+
33
+ typedef void (*asr_progress_cb_t)(double, void*);
34
+
35
+ struct asr_client {
36
+ idevice_connection_t connection;
37
+ uint8_t checksum_chunks;
38
+ int lastprogress;
39
+ asr_progress_cb_t progress_cb;
40
+ void* progress_cb_data;
41
+ };
42
+ typedef struct asr_client *asr_client_t;
43
+
44
+ int asr_open_with_timeout(idevice_t device, asr_client_t* asr);
45
+ void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata);
46
+ int asr_send(asr_client_t asr, plist_t data);
47
+ int asr_receive(asr_client_t asr, plist_t* data);
48
+ int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size);
49
+ void asr_free(asr_client_t asr);
50
+ int asr_perform_validation(asr_client_t asr, const char* filesystem);
51
+ int asr_send_payload(asr_client_t asr, const char* filesystem);
52
+ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file);
53
+
54
+
55
+ #ifdef __cplusplus
56
+ }
57
+ #endif
58
+
59
+ #endif
autogen.sh ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ olddir=`pwd`
4
+ srcdir=`dirname $0`
5
+ test -z "$srcdir" && srcdir=.
6
+
7
+ (
8
+ cd "$srcdir"
9
+
10
+ gprefix=`which glibtoolize 2>&1 >/dev/null`
11
+ if [ $? -eq 0 ]; then
12
+ glibtoolize --force
13
+ else
14
+ libtoolize --force
15
+ fi
16
+ aclocal -I m4
17
+ autoheader
18
+ automake --add-missing
19
+ autoconf
20
+
21
+ cd "$olddir"
22
+ )
23
+
24
+ if [ -z "$NOCONFIGURE" ]; then
25
+ $srcdir/configure "$@"
26
+ fi
ax_pthread.m4 ADDED
@@ -0,0 +1,522 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ===========================================================================
2
+ # https://www.gnu.org/software/autoconf-archive/ax_pthread.html
3
+ # ===========================================================================
4
+ #
5
+ # SYNOPSIS
6
+ #
7
+ # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
8
+ #
9
+ # DESCRIPTION
10
+ #
11
+ # This macro figures out how to build C programs using POSIX threads. It
12
+ # sets the PTHREAD_LIBS output variable to the threads library and linker
13
+ # flags, and the PTHREAD_CFLAGS output variable to any special C compiler
14
+ # flags that are needed. (The user can also force certain compiler
15
+ # flags/libs to be tested by setting these environment variables.)
16
+ #
17
+ # Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
18
+ # needed for multi-threaded programs (defaults to the value of CC
19
+ # respectively CXX otherwise). (This is necessary on e.g. AIX to use the
20
+ # special cc_r/CC_r compiler alias.)
21
+ #
22
+ # NOTE: You are assumed to not only compile your program with these flags,
23
+ # but also to link with them as well. For example, you might link with
24
+ # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
25
+ # $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
26
+ #
27
+ # If you are only building threaded programs, you may wish to use these
28
+ # variables in your default LIBS, CFLAGS, and CC:
29
+ #
30
+ # LIBS="$PTHREAD_LIBS $LIBS"
31
+ # CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
32
+ # CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
33
+ # CC="$PTHREAD_CC"
34
+ # CXX="$PTHREAD_CXX"
35
+ #
36
+ # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
37
+ # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
38
+ # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
39
+ #
40
+ # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
41
+ # PTHREAD_PRIO_INHERIT symbol is defined when compiling with
42
+ # PTHREAD_CFLAGS.
43
+ #
44
+ # ACTION-IF-FOUND is a list of shell commands to run if a threads library
45
+ # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
46
+ # is not found. If ACTION-IF-FOUND is not specified, the default action
47
+ # will define HAVE_PTHREAD.
48
+ #
49
+ # Please let the authors know if this macro fails on any platform, or if
50
+ # you have any other suggestions or comments. This macro was based on work
51
+ # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
52
+ # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
53
+ # Alejandro Forero Cuervo to the autoconf macro repository. We are also
54
+ # grateful for the helpful feedback of numerous users.
55
+ #
56
+ # Updated for Autoconf 2.68 by Daniel Richard G.
57
+ #
58
+ # LICENSE
59
+ #
60
+ # Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
61
+ # Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
62
+ # Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
63
+ #
64
+ # This program is free software: you can redistribute it and/or modify it
65
+ # under the terms of the GNU General Public License as published by the
66
+ # Free Software Foundation, either version 3 of the License, or (at your
67
+ # option) any later version.
68
+ #
69
+ # This program is distributed in the hope that it will be useful, but
70
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
71
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
72
+ # Public License for more details.
73
+ #
74
+ # You should have received a copy of the GNU General Public License along
75
+ # with this program. If not, see <https://www.gnu.org/licenses/>.
76
+ #
77
+ # As a special exception, the respective Autoconf Macro's copyright owner
78
+ # gives unlimited permission to copy, distribute and modify the configure
79
+ # scripts that are the output of Autoconf when processing the Macro. You
80
+ # need not follow the terms of the GNU General Public License when using
81
+ # or distributing such scripts, even though portions of the text of the
82
+ # Macro appear in them. The GNU General Public License (GPL) does govern
83
+ # all other use of the material that constitutes the Autoconf Macro.
84
+ #
85
+ # This special exception to the GPL applies to versions of the Autoconf
86
+ # Macro released by the Autoconf Archive. When you make and distribute a
87
+ # modified version of the Autoconf Macro, you may extend this special
88
+ # exception to the GPL to apply to your modified version as well.
89
+
90
+ #serial 31
91
+
92
+ AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
93
+ AC_DEFUN([AX_PTHREAD], [
94
+ AC_REQUIRE([AC_CANONICAL_HOST])
95
+ AC_REQUIRE([AC_PROG_CC])
96
+ AC_REQUIRE([AC_PROG_SED])
97
+ AC_LANG_PUSH([C])
98
+ ax_pthread_ok=no
99
+
100
+ # We used to check for pthread.h first, but this fails if pthread.h
101
+ # requires special compiler flags (e.g. on Tru64 or Sequent).
102
+ # It gets checked for in the link test anyway.
103
+
104
+ # First of all, check if the user has set any of the PTHREAD_LIBS,
105
+ # etcetera environment variables, and if threads linking works using
106
+ # them:
107
+ if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
108
+ ax_pthread_save_CC="$CC"
109
+ ax_pthread_save_CFLAGS="$CFLAGS"
110
+ ax_pthread_save_LIBS="$LIBS"
111
+ AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
112
+ AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
113
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
114
+ LIBS="$PTHREAD_LIBS $LIBS"
115
+ AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
116
+ AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
117
+ AC_MSG_RESULT([$ax_pthread_ok])
118
+ if test "x$ax_pthread_ok" = "xno"; then
119
+ PTHREAD_LIBS=""
120
+ PTHREAD_CFLAGS=""
121
+ fi
122
+ CC="$ax_pthread_save_CC"
123
+ CFLAGS="$ax_pthread_save_CFLAGS"
124
+ LIBS="$ax_pthread_save_LIBS"
125
+ fi
126
+
127
+ # We must check for the threads library under a number of different
128
+ # names; the ordering is very important because some systems
129
+ # (e.g. DEC) have both -lpthread and -lpthreads, where one of the
130
+ # libraries is broken (non-POSIX).
131
+
132
+ # Create a list of thread flags to try. Items with a "," contain both
133
+ # C compiler flags (before ",") and linker flags (after ","). Other items
134
+ # starting with a "-" are C compiler flags, and remaining items are
135
+ # library names, except for "none" which indicates that we try without
136
+ # any flags at all, and "pthread-config" which is a program returning
137
+ # the flags for the Pth emulation library.
138
+
139
+ ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
140
+
141
+ # The ordering *is* (sometimes) important. Some notes on the
142
+ # individual items follow:
143
+
144
+ # pthreads: AIX (must check this before -lpthread)
145
+ # none: in case threads are in libc; should be tried before -Kthread and
146
+ # other compiler flags to prevent continual compiler warnings
147
+ # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
148
+ # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
149
+ # (Note: HP C rejects this with "bad form for `-t' option")
150
+ # -pthreads: Solaris/gcc (Note: HP C also rejects)
151
+ # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
152
+ # doesn't hurt to check since this sometimes defines pthreads and
153
+ # -D_REENTRANT too), HP C (must be checked before -lpthread, which
154
+ # is present but should not be used directly; and before -mthreads,
155
+ # because the compiler interprets this as "-mt" + "-hreads")
156
+ # -mthreads: Mingw32/gcc, Lynx/gcc
157
+ # pthread: Linux, etcetera
158
+ # --thread-safe: KAI C++
159
+ # pthread-config: use pthread-config program (for GNU Pth library)
160
+
161
+ case $host_os in
162
+
163
+ freebsd*)
164
+
165
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
166
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
167
+
168
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
169
+ ;;
170
+
171
+ hpux*)
172
+
173
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
174
+ # multi-threading and also sets -lpthread."
175
+
176
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
177
+ ;;
178
+
179
+ openedition*)
180
+
181
+ # IBM z/OS requires a feature-test macro to be defined in order to
182
+ # enable POSIX threads at all, so give the user a hint if this is
183
+ # not set. (We don't define these ourselves, as they can affect
184
+ # other portions of the system API in unpredictable ways.)
185
+
186
+ AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
187
+ [
188
+ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
189
+ AX_PTHREAD_ZOS_MISSING
190
+ # endif
191
+ ],
192
+ [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
193
+ ;;
194
+
195
+ solaris*)
196
+
197
+ # On Solaris (at least, for some versions), libc contains stubbed
198
+ # (non-functional) versions of the pthreads routines, so link-based
199
+ # tests will erroneously succeed. (N.B.: The stubs are missing
200
+ # pthread_cleanup_push, or rather a function called by this macro,
201
+ # so we could check for that, but who knows whether they'll stub
202
+ # that too in a future libc.) So we'll check first for the
203
+ # standard Solaris way of linking pthreads (-mt -lpthread).
204
+
205
+ ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
206
+ ;;
207
+ esac
208
+
209
+ # Are we compiling with Clang?
210
+
211
+ AC_CACHE_CHECK([whether $CC is Clang],
212
+ [ax_cv_PTHREAD_CLANG],
213
+ [ax_cv_PTHREAD_CLANG=no
214
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
215
+ if test "x$GCC" = "xyes"; then
216
+ AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
217
+ [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
218
+ # if defined(__clang__) && defined(__llvm__)
219
+ AX_PTHREAD_CC_IS_CLANG
220
+ # endif
221
+ ],
222
+ [ax_cv_PTHREAD_CLANG=yes])
223
+ fi
224
+ ])
225
+ ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
226
+
227
+
228
+ # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
229
+
230
+ # Note that for GCC and Clang -pthread generally implies -lpthread,
231
+ # except when -nostdlib is passed.
232
+ # This is problematic using libtool to build C++ shared libraries with pthread:
233
+ # [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
234
+ # [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
235
+ # [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
236
+ # To solve this, first try -pthread together with -lpthread for GCC
237
+
238
+ AS_IF([test "x$GCC" = "xyes"],
239
+ [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
240
+
241
+ # Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
242
+
243
+ AS_IF([test "x$ax_pthread_clang" = "xyes"],
244
+ [ax_pthread_flags="-pthread,-lpthread -pthread"])
245
+
246
+
247
+ # The presence of a feature test macro requesting re-entrant function
248
+ # definitions is, on some systems, a strong hint that pthreads support is
249
+ # correctly enabled
250
+
251
+ case $host_os in
252
+ darwin* | hpux* | linux* | osf* | solaris*)
253
+ ax_pthread_check_macro="_REENTRANT"
254
+ ;;
255
+
256
+ aix*)
257
+ ax_pthread_check_macro="_THREAD_SAFE"
258
+ ;;
259
+
260
+ *)
261
+ ax_pthread_check_macro="--"
262
+ ;;
263
+ esac
264
+ AS_IF([test "x$ax_pthread_check_macro" = "x--"],
265
+ [ax_pthread_check_cond=0],
266
+ [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
267
+
268
+
269
+ if test "x$ax_pthread_ok" = "xno"; then
270
+ for ax_pthread_try_flag in $ax_pthread_flags; do
271
+
272
+ case $ax_pthread_try_flag in
273
+ none)
274
+ AC_MSG_CHECKING([whether pthreads work without any flags])
275
+ ;;
276
+
277
+ *,*)
278
+ PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
279
+ PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
280
+ AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
281
+ ;;
282
+
283
+ -*)
284
+ AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
285
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
286
+ ;;
287
+
288
+ pthread-config)
289
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
290
+ AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
291
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
292
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
293
+ ;;
294
+
295
+ *)
296
+ AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
297
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
298
+ ;;
299
+ esac
300
+
301
+ ax_pthread_save_CFLAGS="$CFLAGS"
302
+ ax_pthread_save_LIBS="$LIBS"
303
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
304
+ LIBS="$PTHREAD_LIBS $LIBS"
305
+
306
+ # Check for various functions. We must include pthread.h,
307
+ # since some functions may be macros. (On the Sequent, we
308
+ # need a special flag -Kthread to make this header compile.)
309
+ # We check for pthread_join because it is in -lpthread on IRIX
310
+ # while pthread_create is in libc. We check for pthread_attr_init
311
+ # due to DEC craziness with -lpthreads. We check for
312
+ # pthread_cleanup_push because it is one of the few pthread
313
+ # functions on Solaris that doesn't have a non-functional libc stub.
314
+ # We try pthread_create on general principles.
315
+
316
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
317
+ # if $ax_pthread_check_cond
318
+ # error "$ax_pthread_check_macro must be defined"
319
+ # endif
320
+ static void *some_global = NULL;
321
+ static void routine(void *a)
322
+ {
323
+ /* To avoid any unused-parameter or
324
+ unused-but-set-parameter warning. */
325
+ some_global = a;
326
+ }
327
+ static void *start_routine(void *a) { return a; }],
328
+ [pthread_t th; pthread_attr_t attr;
329
+ pthread_create(&th, 0, start_routine, 0);
330
+ pthread_join(th, 0);
331
+ pthread_attr_init(&attr);
332
+ pthread_cleanup_push(routine, 0);
333
+ pthread_cleanup_pop(0) /* ; */])],
334
+ [ax_pthread_ok=yes],
335
+ [])
336
+
337
+ CFLAGS="$ax_pthread_save_CFLAGS"
338
+ LIBS="$ax_pthread_save_LIBS"
339
+
340
+ AC_MSG_RESULT([$ax_pthread_ok])
341
+ AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
342
+
343
+ PTHREAD_LIBS=""
344
+ PTHREAD_CFLAGS=""
345
+ done
346
+ fi
347
+
348
+
349
+ # Clang needs special handling, because older versions handle the -pthread
350
+ # option in a rather... idiosyncratic way
351
+
352
+ if test "x$ax_pthread_clang" = "xyes"; then
353
+
354
+ # Clang takes -pthread; it has never supported any other flag
355
+
356
+ # (Note 1: This will need to be revisited if a system that Clang
357
+ # supports has POSIX threads in a separate library. This tends not
358
+ # to be the way of modern systems, but it's conceivable.)
359
+
360
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
361
+ # to get POSIX threads support; the API is always present and
362
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
363
+ # -pthread does define _REENTRANT, and while the Darwin headers
364
+ # ignore this macro, third-party headers might not.)
365
+
366
+ # However, older versions of Clang make a point of warning the user
367
+ # that, in an invocation where only linking and no compilation is
368
+ # taking place, the -pthread option has no effect ("argument unused
369
+ # during compilation"). They expect -pthread to be passed in only
370
+ # when source code is being compiled.
371
+ #
372
+ # Problem is, this is at odds with the way Automake and most other
373
+ # C build frameworks function, which is that the same flags used in
374
+ # compilation (CFLAGS) are also used in linking. Many systems
375
+ # supported by AX_PTHREAD require exactly this for POSIX threads
376
+ # support, and in fact it is often not straightforward to specify a
377
+ # flag that is used only in the compilation phase and not in
378
+ # linking. Such a scenario is extremely rare in practice.
379
+ #
380
+ # Even though use of the -pthread flag in linking would only print
381
+ # a warning, this can be a nuisance for well-run software projects
382
+ # that build with -Werror. So if the active version of Clang has
383
+ # this misfeature, we search for an option to squash it.
384
+
385
+ AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
386
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
387
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
388
+ # Create an alternate version of $ac_link that compiles and
389
+ # links in two steps (.c -> .o, .o -> exe) instead of one
390
+ # (.c -> exe), because the warning occurs only in the second
391
+ # step
392
+ ax_pthread_save_ac_link="$ac_link"
393
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
394
+ ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
395
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
396
+ ax_pthread_save_CFLAGS="$CFLAGS"
397
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
398
+ AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
399
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
400
+ ac_link="$ax_pthread_save_ac_link"
401
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
402
+ [ac_link="$ax_pthread_2step_ac_link"
403
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
404
+ [break])
405
+ ])
406
+ done
407
+ ac_link="$ax_pthread_save_ac_link"
408
+ CFLAGS="$ax_pthread_save_CFLAGS"
409
+ AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
410
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
411
+ ])
412
+
413
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
414
+ no | unknown) ;;
415
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
416
+ esac
417
+
418
+ fi # $ax_pthread_clang = yes
419
+
420
+
421
+
422
+ # Various other checks:
423
+ if test "x$ax_pthread_ok" = "xyes"; then
424
+ ax_pthread_save_CFLAGS="$CFLAGS"
425
+ ax_pthread_save_LIBS="$LIBS"
426
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
427
+ LIBS="$PTHREAD_LIBS $LIBS"
428
+
429
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
430
+ AC_CACHE_CHECK([for joinable pthread attribute],
431
+ [ax_cv_PTHREAD_JOINABLE_ATTR],
432
+ [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
433
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
434
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
435
+ [int attr = $ax_pthread_attr; return attr /* ; */])],
436
+ [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
437
+ [])
438
+ done
439
+ ])
440
+ AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
441
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
442
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"],
443
+ [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
444
+ [$ax_cv_PTHREAD_JOINABLE_ATTR],
445
+ [Define to necessary symbol if this constant
446
+ uses a non-standard name on your system.])
447
+ ax_pthread_joinable_attr_defined=yes
448
+ ])
449
+
450
+ AC_CACHE_CHECK([whether more special flags are required for pthreads],
451
+ [ax_cv_PTHREAD_SPECIAL_FLAGS],
452
+ [ax_cv_PTHREAD_SPECIAL_FLAGS=no
453
+ case $host_os in
454
+ solaris*)
455
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
456
+ ;;
457
+ esac
458
+ ])
459
+ AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
460
+ test "x$ax_pthread_special_flags_added" != "xyes"],
461
+ [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
462
+ ax_pthread_special_flags_added=yes])
463
+
464
+ AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
465
+ [ax_cv_PTHREAD_PRIO_INHERIT],
466
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
467
+ [[int i = PTHREAD_PRIO_INHERIT;
468
+ return i;]])],
469
+ [ax_cv_PTHREAD_PRIO_INHERIT=yes],
470
+ [ax_cv_PTHREAD_PRIO_INHERIT=no])
471
+ ])
472
+ AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
473
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"],
474
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
475
+ ax_pthread_prio_inherit_defined=yes
476
+ ])
477
+
478
+ CFLAGS="$ax_pthread_save_CFLAGS"
479
+ LIBS="$ax_pthread_save_LIBS"
480
+
481
+ # More AIX lossage: compile with *_r variant
482
+ if test "x$GCC" != "xyes"; then
483
+ case $host_os in
484
+ aix*)
485
+ AS_CASE(["x/$CC"],
486
+ [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
487
+ [#handle absolute path differently from PATH based program lookup
488
+ AS_CASE(["x$CC"],
489
+ [x/*],
490
+ [
491
+ AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
492
+ AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
493
+ ],
494
+ [
495
+ AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
496
+ AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
497
+ ]
498
+ )
499
+ ])
500
+ ;;
501
+ esac
502
+ fi
503
+ fi
504
+
505
+ test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
506
+ test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
507
+
508
+ AC_SUBST([PTHREAD_LIBS])
509
+ AC_SUBST([PTHREAD_CFLAGS])
510
+ AC_SUBST([PTHREAD_CC])
511
+ AC_SUBST([PTHREAD_CXX])
512
+
513
+ # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
514
+ if test "x$ax_pthread_ok" = "xyes"; then
515
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
516
+ :
517
+ else
518
+ ax_pthread_ok=no
519
+ $2
520
+ fi
521
+ AC_LANG_POP
522
+ ])dnl AX_PTHREAD
ax_python_devel.m4 ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ===========================================================================
2
+ # https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
3
+ # ===========================================================================
4
+ #
5
+ # SYNOPSIS
6
+ #
7
+ # AX_PYTHON_DEVEL([version[,optional]])
8
+ #
9
+ # DESCRIPTION
10
+ #
11
+ # Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
12
+ # in your configure.ac.
13
+ #
14
+ # This macro checks for Python and tries to get the include path to
15
+ # 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
16
+ # variables. It also exports $(PYTHON_EXTRA_LIBS) and
17
+ # $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
18
+ #
19
+ # You can search for some particular version of Python by passing a
20
+ # parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
21
+ # note that you *have* to pass also an operator along with the version to
22
+ # match, and pay special attention to the single quotes surrounding the
23
+ # version number. Don't use "PYTHON_VERSION" for this: that environment
24
+ # variable is declared as precious and thus reserved for the end-user.
25
+ #
26
+ # By default this will fail if it does not detect a development version of
27
+ # python. If you want it to continue, set optional to true, like
28
+ # AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be
29
+ # "no" if it fails.
30
+ #
31
+ # This macro should work for all versions of Python >= 2.1.0. As an end
32
+ # user, you can disable the check for the python version by setting the
33
+ # PYTHON_NOVERSIONCHECK environment variable to something else than the
34
+ # empty string.
35
+ #
36
+ # If you need to use this macro for an older Python version, please
37
+ # contact the authors. We're always open for feedback.
38
+ #
39
+ # LICENSE
40
+ #
41
+ # Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
42
+ # Copyright (c) 2009 Alan W. Irwin
43
+ # Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
44
+ # Copyright (c) 2009 Andrew Collier
45
+ # Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
46
+ # Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
47
+ # Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
48
+ #
49
+ # This program is free software: you can redistribute it and/or modify it
50
+ # under the terms of the GNU General Public License as published by the
51
+ # Free Software Foundation, either version 3 of the License, or (at your
52
+ # option) any later version.
53
+ #
54
+ # This program is distributed in the hope that it will be useful, but
55
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
56
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
57
+ # Public License for more details.
58
+ #
59
+ # You should have received a copy of the GNU General Public License along
60
+ # with this program. If not, see <https://www.gnu.org/licenses/>.
61
+ #
62
+ # As a special exception, the respective Autoconf Macro's copyright owner
63
+ # gives unlimited permission to copy, distribute and modify the configure
64
+ # scripts that are the output of Autoconf when processing the Macro. You
65
+ # need not follow the terms of the GNU General Public License when using
66
+ # or distributing such scripts, even though portions of the text of the
67
+ # Macro appear in them. The GNU General Public License (GPL) does govern
68
+ # all other use of the material that constitutes the Autoconf Macro.
69
+ #
70
+ # This special exception to the GPL applies to versions of the Autoconf
71
+ # Macro released by the Autoconf Archive. When you make and distribute a
72
+ # modified version of the Autoconf Macro, you may extend this special
73
+ # exception to the GPL to apply to your modified version as well.
74
+
75
+ #serial 37
76
+
77
+ AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
78
+ AC_DEFUN([AX_PYTHON_DEVEL],[
79
+ # Get whether it's optional
80
+ if test -z "$2"; then
81
+ ax_python_devel_optional=false
82
+ else
83
+ ax_python_devel_optional=$2
84
+ fi
85
+ ax_python_devel_found=yes
86
+
87
+ #
88
+ # Allow the use of a (user set) custom python version
89
+ #
90
+ AC_ARG_VAR([PYTHON_VERSION],[The installed Python
91
+ version to use, for example '2.3'. This string
92
+ will be appended to the Python interpreter
93
+ canonical name.])
94
+
95
+ AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
96
+ if test -z "$PYTHON"; then
97
+ AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
98
+ if ! $ax_python_devel_optional; then
99
+ AC_MSG_ERROR([Giving up, python development not available])
100
+ fi
101
+ ax_python_devel_found=no
102
+ PYTHON_VERSION=""
103
+ fi
104
+
105
+ if test $ax_python_devel_found = yes; then
106
+ #
107
+ # Check for a version of Python >= 2.1.0
108
+ #
109
+ AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
110
+ ac_supports_python_ver=`$PYTHON -c "import sys; \
111
+ ver = sys.version.split ()[[0]]; \
112
+ print (ver >= '2.1.0')"`
113
+ if test "$ac_supports_python_ver" != "True"; then
114
+ if test -z "$PYTHON_NOVERSIONCHECK"; then
115
+ AC_MSG_RESULT([no])
116
+ AC_MSG_WARN([
117
+ This version of the AC@&t@_PYTHON_DEVEL macro
118
+ doesn't work properly with versions of Python before
119
+ 2.1.0. You may need to re-run configure, setting the
120
+ variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
121
+ PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
122
+ Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
123
+ to something else than an empty string.
124
+ ])
125
+ if ! $ax_python_devel_optional; then
126
+ AC_MSG_FAILURE([Giving up])
127
+ fi
128
+ ax_python_devel_found=no
129
+ PYTHON_VERSION=""
130
+ else
131
+ AC_MSG_RESULT([skip at user request])
132
+ fi
133
+ else
134
+ AC_MSG_RESULT([yes])
135
+ fi
136
+ fi
137
+
138
+ if test $ax_python_devel_found = yes; then
139
+ #
140
+ # If the macro parameter ``version'' is set, honour it.
141
+ # A Python shim class, VPy, is used to implement correct version comparisons via
142
+ # string expressions, since e.g. a naive textual ">= 2.7.3" won't work for
143
+ # Python 2.7.10 (the ".1" being evaluated as less than ".3").
144
+ #
145
+ if test -n "$1"; then
146
+ AC_MSG_CHECKING([for a version of Python $1])
147
+ cat << EOF > ax_python_devel_vpy.py
148
+ class VPy:
149
+ def vtup(self, s):
150
+ return tuple(map(int, s.strip().replace("rc", ".").split(".")))
151
+ def __init__(self):
152
+ import sys
153
+ self.vpy = tuple(sys.version_info)[[:3]]
154
+ def __eq__(self, s):
155
+ return self.vpy == self.vtup(s)
156
+ def __ne__(self, s):
157
+ return self.vpy != self.vtup(s)
158
+ def __lt__(self, s):
159
+ return self.vpy < self.vtup(s)
160
+ def __gt__(self, s):
161
+ return self.vpy > self.vtup(s)
162
+ def __le__(self, s):
163
+ return self.vpy <= self.vtup(s)
164
+ def __ge__(self, s):
165
+ return self.vpy >= self.vtup(s)
166
+ EOF
167
+ ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \
168
+ ver = ax_python_devel_vpy.VPy(); \
169
+ print (ver $1)"`
170
+ rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py*
171
+ if test "$ac_supports_python_ver" = "True"; then
172
+ AC_MSG_RESULT([yes])
173
+ else
174
+ AC_MSG_RESULT([no])
175
+ AC_MSG_WARN([this package requires Python $1.
176
+ If you have it installed, but it isn't the default Python
177
+ interpreter in your system path, please pass the PYTHON_VERSION
178
+ variable to configure. See ``configure --help'' for reference.
179
+ ])
180
+ if ! $ax_python_devel_optional; then
181
+ AC_MSG_ERROR([Giving up])
182
+ fi
183
+ ax_python_devel_found=no
184
+ PYTHON_VERSION=""
185
+ fi
186
+ fi
187
+ fi
188
+
189
+ if test $ax_python_devel_found = yes; then
190
+ #
191
+ # Check if you have distutils, else fail
192
+ #
193
+ AC_MSG_CHECKING([for the sysconfig Python package])
194
+ ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
195
+ if test $? -eq 0; then
196
+ AC_MSG_RESULT([yes])
197
+ IMPORT_SYSCONFIG="import sysconfig"
198
+ else
199
+ AC_MSG_RESULT([no])
200
+
201
+ AC_MSG_CHECKING([for the distutils Python package])
202
+ ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
203
+ if test $? -eq 0; then
204
+ AC_MSG_RESULT([yes])
205
+ IMPORT_SYSCONFIG="from distutils import sysconfig"
206
+ else
207
+ AC_MSG_WARN([cannot import Python module "distutils".
208
+ Please check your Python installation. The error was:
209
+ $ac_sysconfig_result])
210
+ if ! $ax_python_devel_optional; then
211
+ AC_MSG_ERROR([Giving up])
212
+ fi
213
+ ax_python_devel_found=no
214
+ PYTHON_VERSION=""
215
+ fi
216
+ fi
217
+ fi
218
+
219
+ if test $ax_python_devel_found = yes; then
220
+ #
221
+ # Check for Python include path
222
+ #
223
+ AC_MSG_CHECKING([for Python include path])
224
+ if test -z "$PYTHON_CPPFLAGS"; then
225
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
226
+ # sysconfig module has different functions
227
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
228
+ print (sysconfig.get_path ('include'));"`
229
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
230
+ print (sysconfig.get_path ('platinclude'));"`
231
+ else
232
+ # old distutils way
233
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
234
+ print (sysconfig.get_python_inc ());"`
235
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
236
+ print (sysconfig.get_python_inc (plat_specific=1));"`
237
+ fi
238
+ if test -n "${python_path}"; then
239
+ if test "${plat_python_path}" != "${python_path}"; then
240
+ python_path="-I$python_path -I$plat_python_path"
241
+ else
242
+ python_path="-I$python_path"
243
+ fi
244
+ fi
245
+ PYTHON_CPPFLAGS=$python_path
246
+ fi
247
+ AC_MSG_RESULT([$PYTHON_CPPFLAGS])
248
+ AC_SUBST([PYTHON_CPPFLAGS])
249
+
250
+ #
251
+ # Check for Python library path
252
+ #
253
+ AC_MSG_CHECKING([for Python library path])
254
+ if test -z "$PYTHON_LIBS"; then
255
+ # (makes two attempts to ensure we've got a version number
256
+ # from the interpreter)
257
+ ac_python_version=`cat<<EOD | $PYTHON -
258
+
259
+ # join all versioning strings, on some systems
260
+ # major/minor numbers could be in different list elements
261
+ from sysconfig import *
262
+ e = get_config_var('VERSION')
263
+ if e is not None:
264
+ print(e)
265
+ EOD`
266
+
267
+ if test -z "$ac_python_version"; then
268
+ if test -n "$PYTHON_VERSION"; then
269
+ ac_python_version=$PYTHON_VERSION
270
+ else
271
+ ac_python_version=`$PYTHON -c "import sys; \
272
+ print ("%d.%d" % sys.version_info[[:2]])"`
273
+ fi
274
+ fi
275
+
276
+ # Make the versioning information available to the compiler
277
+ AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
278
+ [If available, contains the Python version number currently in use.])
279
+
280
+ # First, the library directory:
281
+ ac_python_libdir=`cat<<EOD | $PYTHON -
282
+
283
+ # There should be only one
284
+ $IMPORT_SYSCONFIG
285
+ e = sysconfig.get_config_var('LIBDIR')
286
+ if e is not None:
287
+ print (e)
288
+ EOD`
289
+
290
+ # Now, for the library:
291
+ ac_python_library=`cat<<EOD | $PYTHON -
292
+
293
+ $IMPORT_SYSCONFIG
294
+ c = sysconfig.get_config_vars()
295
+ if 'LDVERSION' in c:
296
+ print ('python'+c[['LDVERSION']])
297
+ else:
298
+ print ('python'+c[['VERSION']])
299
+ EOD`
300
+
301
+ # This small piece shamelessly adapted from PostgreSQL python macro;
302
+ # credits goes to momjian, I think. I'd like to put the right name
303
+ # in the credits, if someone can point me in the right direction... ?
304
+ #
305
+ if test -n "$ac_python_libdir" -a -n "$ac_python_library"
306
+ then
307
+ # use the official shared library
308
+ ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
309
+ PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
310
+ else
311
+ # old way: use libpython from python_configdir
312
+ ac_python_libdir=`$PYTHON -c \
313
+ "from sysconfig import get_python_lib as f; \
314
+ import os; \
315
+ print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
316
+ PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
317
+ fi
318
+
319
+ if test -z "$PYTHON_LIBS"; then
320
+ AC_MSG_WARN([
321
+ Cannot determine location of your Python DSO. Please check it was installed with
322
+ dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
323
+ ])
324
+ if ! $ax_python_devel_optional; then
325
+ AC_MSG_ERROR([Giving up])
326
+ fi
327
+ ax_python_devel_found=no
328
+ PYTHON_VERSION=""
329
+ fi
330
+ fi
331
+ fi
332
+
333
+ if test $ax_python_devel_found = yes; then
334
+ AC_MSG_RESULT([$PYTHON_LIBS])
335
+ AC_SUBST([PYTHON_LIBS])
336
+
337
+ #
338
+ # Check for site packages
339
+ #
340
+ AC_MSG_CHECKING([for Python site-packages path])
341
+ if test -z "$PYTHON_SITE_PKG"; then
342
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
343
+ PYTHON_SITE_PKG=`$PYTHON -c "
344
+ $IMPORT_SYSCONFIG;
345
+ if hasattr(sysconfig, 'get_default_scheme'):
346
+ scheme = sysconfig.get_default_scheme()
347
+ else:
348
+ scheme = sysconfig._get_default_scheme()
349
+ if scheme == 'posix_local':
350
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
351
+ scheme = 'posix_prefix'
352
+ prefix = '$prefix'
353
+ if prefix == 'NONE':
354
+ prefix = '$ac_default_prefix'
355
+ sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix})
356
+ print(sitedir)"`
357
+ else
358
+ # distutils.sysconfig way
359
+ PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
360
+ print (sysconfig.get_python_lib(0,0));"`
361
+ fi
362
+ fi
363
+ AC_MSG_RESULT([$PYTHON_SITE_PKG])
364
+ AC_SUBST([PYTHON_SITE_PKG])
365
+
366
+ #
367
+ # Check for platform-specific site packages
368
+ #
369
+ AC_MSG_CHECKING([for Python platform specific site-packages path])
370
+ if test -z "$PYTHON_PLATFORM_SITE_PKG"; then
371
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
372
+ PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "
373
+ $IMPORT_SYSCONFIG;
374
+ if hasattr(sysconfig, 'get_default_scheme'):
375
+ scheme = sysconfig.get_default_scheme()
376
+ else:
377
+ scheme = sysconfig._get_default_scheme()
378
+ if scheme == 'posix_local':
379
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
380
+ scheme = 'posix_prefix'
381
+ prefix = '$prefix'
382
+ if prefix == 'NONE':
383
+ prefix = '$ac_default_prefix'
384
+ sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase': prefix})
385
+ print(sitedir)"`
386
+ else
387
+ # distutils.sysconfig way
388
+ PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
389
+ print (sysconfig.get_python_lib(1,0));"`
390
+ fi
391
+ fi
392
+ AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
393
+ AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
394
+
395
+ #
396
+ # libraries which must be linked in when embedding
397
+ #
398
+ AC_MSG_CHECKING(python extra libraries)
399
+ if test -z "$PYTHON_EXTRA_LIBS"; then
400
+ PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
401
+ conf = sysconfig.get_config_var; \
402
+ print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
403
+ fi
404
+ AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
405
+ AC_SUBST(PYTHON_EXTRA_LIBS)
406
+
407
+ #
408
+ # linking flags needed when embedding
409
+ #
410
+ AC_MSG_CHECKING(python extra linking flags)
411
+ if test -z "$PYTHON_EXTRA_LDFLAGS"; then
412
+ PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
413
+ conf = sysconfig.get_config_var; \
414
+ print (conf('LINKFORSHARED'))"`
415
+ # Hack for macos, it sticks this in here.
416
+ PYTHON_EXTRA_LDFLAGS=`echo $PYTHON_EXTRA_LDFLAGS | sed 's/CoreFoundation.*$/CoreFoundation/'`
417
+ fi
418
+ AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
419
+ AC_SUBST(PYTHON_EXTRA_LDFLAGS)
420
+
421
+ #
422
+ # final check to see if everything compiles alright
423
+ #
424
+ AC_MSG_CHECKING([consistency of all components of python development environment])
425
+ # save current global flags
426
+ ac_save_LIBS="$LIBS"
427
+ ac_save_LDFLAGS="$LDFLAGS"
428
+ ac_save_CPPFLAGS="$CPPFLAGS"
429
+ LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS"
430
+ LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
431
+ CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
432
+ AC_LANG_PUSH([C])
433
+ AC_LINK_IFELSE([
434
+ AC_LANG_PROGRAM([[#include <Python.h>]],
435
+ [[Py_Initialize();]])
436
+ ],[pythonexists=yes],[pythonexists=no])
437
+ AC_LANG_POP([C])
438
+ # turn back to default flags
439
+ CPPFLAGS="$ac_save_CPPFLAGS"
440
+ LIBS="$ac_save_LIBS"
441
+ LDFLAGS="$ac_save_LDFLAGS"
442
+
443
+ AC_MSG_RESULT([$pythonexists])
444
+
445
+ if test ! "x$pythonexists" = "xyes"; then
446
+ AC_MSG_WARN([
447
+ Could not link test program to Python. Maybe the main Python library has been
448
+ installed in some non-standard library path. If so, pass it to configure,
449
+ via the LIBS environment variable.
450
+ Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
451
+ ============================================================================
452
+ ERROR!
453
+ You probably have to install the development version of the Python package
454
+ for your distribution. The exact name of this package varies among them.
455
+ ============================================================================
456
+ ])
457
+ if ! $ax_python_devel_optional; then
458
+ AC_MSG_ERROR([Giving up])
459
+ fi
460
+ ax_python_devel_found=no
461
+ PYTHON_VERSION=""
462
+ fi
463
+ fi
464
+
465
+ #
466
+ # all done!
467
+ #
468
+ ])
bt_packet_logger.c ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * bt_packet_logger.c
3
+ * com.apple.bluetooth.BTPacketLogger service implementation.
4
+ *
5
+ * Copyright (c) 2021 Geoffrey Kruse, 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
+ #include <string.h>
26
+ #include <stdlib.h>
27
+
28
+ #include "bt_packet_logger.h"
29
+ #include "lockdown.h"
30
+ #include "common/debug.h"
31
+
32
+ struct bt_packet_logger_worker_thread {
33
+ bt_packet_logger_client_t client;
34
+ bt_packet_logger_receive_cb_t cbfunc;
35
+ void *user_data;
36
+ uint8_t rxbuff[BT_MAX_PACKET_SIZE];
37
+ };
38
+
39
+ #define SZ_READ_TIMEOUT 100
40
+ #define PAYLOAD_READ_TIMEOUT 500
41
+
42
+ /**
43
+ * Convert a service_error_t value to a bt_packet_logger_error_t value.
44
+ * Used internally to get correct error codes.
45
+ *
46
+ * @param err An service_error_t error code
47
+ *
48
+ * @return A matching bt_packet_logger_error_t error code,
49
+ * BT_PACKET_LOGGER_E_UNKNOWN_ERROR otherwise.
50
+ */
51
+ static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err)
52
+ {
53
+ switch (err) {
54
+ case SERVICE_E_SUCCESS:
55
+ return BT_PACKET_LOGGER_E_SUCCESS;
56
+ case SERVICE_E_INVALID_ARG:
57
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
58
+ case SERVICE_E_MUX_ERROR:
59
+ return BT_PACKET_LOGGER_E_MUX_ERROR;
60
+ case SERVICE_E_SSL_ERROR:
61
+ return BT_PACKET_LOGGER_E_SSL_ERROR;
62
+ case SERVICE_E_NOT_ENOUGH_DATA:
63
+ return BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA;
64
+ case SERVICE_E_TIMEOUT:
65
+ return BT_PACKET_LOGGER_E_TIMEOUT;
66
+ default:
67
+ break;
68
+ }
69
+ return BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
70
+ }
71
+
72
+ bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client)
73
+ {
74
+ if (!device || !service || service->port == 0 || !client || *client) {
75
+ debug_info("Incorrect parameter passed to bt_packet_logger_client_new.");
76
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
77
+ }
78
+
79
+ debug_info("Creating bt_packet_logger_client, port = %d.", service->port);
80
+
81
+ service_client_t parent = NULL;
82
+ bt_packet_logger_error_t ret = bt_packet_logger_error(service_client_new(device, service, &parent));
83
+ if (ret != BT_PACKET_LOGGER_E_SUCCESS) {
84
+ debug_info("Creating base service client failed. Error: %i", ret);
85
+ return ret;
86
+ }
87
+
88
+ bt_packet_logger_client_t client_loc = (bt_packet_logger_client_t) malloc(sizeof(struct bt_packet_logger_client_private));
89
+ client_loc->parent = parent;
90
+ client_loc->worker = THREAD_T_NULL;
91
+
92
+ *client = client_loc;
93
+
94
+ debug_info("bt_packet_logger_client successfully created.");
95
+ return 0;
96
+ }
97
+
98
+ bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label)
99
+ {
100
+ bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
101
+ service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err);
102
+ return err;
103
+ }
104
+
105
+ bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client)
106
+ {
107
+ if (!client)
108
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
109
+ bt_packet_logger_stop_capture(client);
110
+ bt_packet_logger_error_t err = bt_packet_logger_error(service_client_free(client->parent));
111
+ free(client);
112
+
113
+ return err;
114
+ }
115
+
116
+ bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
117
+ {
118
+ bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
119
+ int bytes = 0;
120
+
121
+ if (!client || !data || (size == 0)) {
122
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
123
+ }
124
+
125
+ res = bt_packet_logger_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
126
+ if (res != BT_PACKET_LOGGER_E_SUCCESS && res != BT_PACKET_LOGGER_E_TIMEOUT && res != BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA) {
127
+ debug_info("Could not read data, error %d", res);
128
+ }
129
+ if (received) {
130
+ *received = (uint32_t)bytes;
131
+ }
132
+
133
+ return res;
134
+ }
135
+
136
+ void *bt_packet_logger_worker(void *arg)
137
+ {
138
+ bt_packet_logger_error_t ret = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
139
+ struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)arg;
140
+
141
+ if (!btwt) {
142
+ return NULL;
143
+ }
144
+
145
+ debug_info("Running");
146
+
147
+ while (btwt->client->parent) {
148
+ uint32_t bytes = 0;
149
+ uint16_t len;
150
+
151
+ ret = bt_packet_logger_receive_with_timeout(btwt->client, (char*)&len, 2, &bytes, SZ_READ_TIMEOUT);
152
+
153
+ if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
154
+ continue;
155
+ } else if (ret < 0) {
156
+ debug_info("Connection to bt packet logger interrupted");
157
+ break;
158
+ }
159
+
160
+ // sanity check received length
161
+ if(bytes > 0 && len > sizeof(bt_packet_logger_header_t)) {
162
+ debug_info("Reading %u bytes\n", len);
163
+ ret = bt_packet_logger_receive_with_timeout(btwt->client, (char *)btwt->rxbuff, len, &bytes, PAYLOAD_READ_TIMEOUT);
164
+
165
+ if(len != bytes) {
166
+ debug_info("Failed Read Expected %u, Received %u\n", len, bytes);
167
+ continue;
168
+ }
169
+
170
+ if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
171
+ continue;
172
+ } else if (ret < 0) {
173
+ debug_info("Connection to bt packet logger interrupted");
174
+ break;
175
+ }
176
+
177
+ btwt->cbfunc(btwt->rxbuff, len, btwt->user_data);
178
+ }
179
+ }
180
+
181
+ // null check performed above
182
+ free(btwt);
183
+
184
+ debug_info("Exiting");
185
+
186
+ return NULL;
187
+ }
188
+
189
+ bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data)
190
+ {
191
+ if (!client || !callback)
192
+ return BT_PACKET_LOGGER_E_INVALID_ARG;
193
+
194
+ bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
195
+
196
+ if (client->worker) {
197
+ debug_info("Another syslog capture thread appears to be running already.");
198
+ return res;
199
+ }
200
+
201
+ /* start worker thread */
202
+ struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)malloc(sizeof(struct bt_packet_logger_worker_thread));
203
+ if (btwt) {
204
+ btwt->client = client;
205
+ btwt->cbfunc = callback;
206
+ btwt->user_data = user_data;
207
+
208
+ if (thread_new(&client->worker, bt_packet_logger_worker, btwt) == 0) {
209
+ res = BT_PACKET_LOGGER_E_SUCCESS;
210
+ }
211
+ }
212
+
213
+ return res;
214
+ }
215
+
216
+
217
+ bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client)
218
+ {
219
+ if (client->worker) {
220
+ /* notify thread to finish */
221
+ service_client_t parent = client->parent;
222
+ client->parent = NULL;
223
+ /* join thread to make it exit */
224
+ thread_join(client->worker);
225
+ thread_free(client->worker);
226
+ client->worker = THREAD_T_NULL;
227
+ client->parent = parent;
228
+ }
229
+
230
+ return BT_PACKET_LOGGER_E_SUCCESS;
231
+ }
bt_packet_logger.h ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * bt_packet_logger.h
3
+ * com.apple.bluetooth.BTPacketLogger service header file.
4
+ *
5
+ * Copyright (c) 2021 Geoffrey Kruse, 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
+ #ifndef _BR_PACKET_LOGGER_H
23
+ #define _BR_PACKET_LOGGER_H
24
+
25
+ #include "idevice.h"
26
+ #include "libimobiledevice/bt_packet_logger.h"
27
+ #include "service.h"
28
+ #include <libimobiledevice-glue/thread.h>
29
+
30
+ struct bt_packet_logger_client_private {
31
+ service_client_t parent;
32
+ THREAD_T worker;
33
+ };
34
+
35
+ void *bt_packet_logger_worker(void *arg);
36
+
37
+ #endif
common.c ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * common.c
3
+ * Misc functions used in idevicerestore
4
+ *
5
+ * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
6
+ * Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifdef HAVE_CONFIG_H
25
+ #include <config.h>
26
+ #endif
27
+
28
+ #include <stdio.h>
29
+ #include <stdlib.h>
30
+ #include <string.h>
31
+ #include <unistd.h>
32
+ #include <errno.h>
33
+ #include <libgen.h>
34
+ #include <time.h>
35
+ #include <sys/stat.h>
36
+ #include <fcntl.h>
37
+ #include <ctype.h>
38
+
39
+ #ifdef WIN32
40
+ #include <windows.h>
41
+ #include <conio.h>
42
+ #ifndef _O_EXCL
43
+ #define _O_EXCL 0x0400
44
+ #endif
45
+ #ifndef O_EXCL
46
+ #define O_EXCL _O_EXCL
47
+ #endif
48
+ #else
49
+ #include <sys/time.h>
50
+ #include <pthread.h>
51
+ #include <termios.h>
52
+ #endif
53
+
54
+ #include "common.h"
55
+ #include "endianness.h"
56
+
57
+ #define MAX_PRINT_LEN 64*1024
58
+
59
+ struct idevicerestore_mode_t idevicerestore_modes[] = {
60
+ { 0, "WTF" },
61
+ { 1, "DFU" },
62
+ { 2, "Recovery" },
63
+ { 3, "Restore" },
64
+ { 4, "Normal" },
65
+ { -1, NULL }
66
+ };
67
+
68
+ int idevicerestore_debug = 0;
69
+
70
+ #define idevicerestore_err_buff_size 256
71
+ static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, };
72
+
73
+ static FILE* info_stream = NULL;
74
+ static FILE* error_stream = NULL;
75
+ static FILE* debug_stream = NULL;
76
+
77
+ static int info_disabled = 0;
78
+ static int error_disabled = 0;
79
+ static int debug_disabled = 0;
80
+
81
+ void info(const char* format, ...)
82
+ {
83
+ if (info_disabled) return;
84
+ va_list vargs;
85
+ va_start(vargs, format);
86
+ vfprintf((info_stream) ? info_stream : stdout, format, vargs);
87
+ va_end(vargs);
88
+ }
89
+
90
+ void error(const char* format, ...)
91
+ {
92
+ va_list vargs, vargs2;
93
+ va_start(vargs, format);
94
+ va_copy(vargs2, vargs);
95
+ vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs);
96
+ va_end(vargs);
97
+ if (!error_disabled) {
98
+ vfprintf((error_stream) ? error_stream : stderr, format, vargs2);
99
+ }
100
+ va_end(vargs2);
101
+ }
102
+
103
+ void debug(const char* format, ...)
104
+ {
105
+ if (debug_disabled) return;
106
+ if (!idevicerestore_debug) {
107
+ return;
108
+ }
109
+ va_list vargs;
110
+ va_start(vargs, format);
111
+ vfprintf((debug_stream) ? debug_stream : stderr, format, vargs);
112
+ va_end(vargs);
113
+ }
114
+
115
+ void idevicerestore_set_info_stream(FILE* strm)
116
+ {
117
+ if (strm) {
118
+ info_disabled = 0;
119
+ info_stream = strm;
120
+ } else {
121
+ info_disabled = 1;
122
+ }
123
+ }
124
+
125
+ void idevicerestore_set_error_stream(FILE* strm)
126
+ {
127
+ if (strm) {
128
+ error_disabled = 0;
129
+ error_stream = strm;
130
+ } else {
131
+ error_disabled = 1;
132
+ }
133
+ }
134
+
135
+ void idevicerestore_set_debug_stream(FILE* strm)
136
+ {
137
+ if (strm) {
138
+ debug_disabled = 0;
139
+ debug_stream = strm;
140
+ } else {
141
+ debug_disabled = 1;
142
+ }
143
+ }
144
+
145
+ const char* idevicerestore_get_error(void)
146
+ {
147
+ if (idevicerestore_err_buff[0] == 0) {
148
+ return NULL;
149
+ } else {
150
+ char* p = NULL;
151
+ while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) {
152
+ p[0] = '\0';
153
+ }
154
+ return (const char*)idevicerestore_err_buff;
155
+ }
156
+ }
157
+
158
+ int write_file(const char* filename, const void* data, size_t size) {
159
+ size_t bytes = 0;
160
+ FILE* file = NULL;
161
+
162
+ debug("Writing data to %s\n", filename);
163
+ file = fopen(filename, "wb");
164
+ if (file == NULL) {
165
+ error("write_file: Unable to open file %s\n", filename);
166
+ return -1;
167
+ }
168
+
169
+ bytes = fwrite(data, 1, size, file);
170
+ fclose(file);
171
+
172
+ if (bytes != size) {
173
+ error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size);
174
+ return -1;
175
+ }
176
+
177
+ return size;
178
+ }
179
+
180
+ int read_file(const char* filename, void** data, size_t* size) {
181
+ size_t bytes = 0;
182
+ size_t length = 0;
183
+ FILE* file = NULL;
184
+ char* buffer = NULL;
185
+ struct stat fst;
186
+
187
+ debug("Reading data from %s\n", filename);
188
+
189
+ *size = 0;
190
+ *data = NULL;
191
+
192
+ file = fopen(filename, "rb");
193
+ if (file == NULL) {
194
+ error("read_file: cannot open %s: %s\n", filename, strerror(errno));
195
+ return -1;
196
+ }
197
+
198
+ if (fstat(fileno(file), &fst) < 0) {
199
+ error("read_file: fstat: %s\n", strerror(errno));
200
+ return -1;
201
+ }
202
+ length = fst.st_size;
203
+
204
+ buffer = (char*) malloc(length);
205
+ if (buffer == NULL) {
206
+ error("ERROR: Out of memory\n");
207
+ fclose(file);
208
+ return -1;
209
+ }
210
+ bytes = fread(buffer, 1, length, file);
211
+ fclose(file);
212
+
213
+ if (bytes != length) {
214
+ error("ERROR: Unable to read entire file\n");
215
+ free(buffer);
216
+ return -1;
217
+ }
218
+
219
+ *size = length;
220
+ *data = buffer;
221
+ return 0;
222
+ }
223
+
224
+ void debug_plist(plist_t plist) {
225
+ uint32_t size = 0;
226
+ char* data = NULL;
227
+ plist_to_xml(plist, &data, &size);
228
+ if (size <= MAX_PRINT_LEN)
229
+ info("%s:printing %i bytes plist:\n%s", __FILE__, size, data);
230
+ else
231
+ info("%s:supressed printing %i bytes plist...\n", __FILE__, size);
232
+ free(data);
233
+ }
234
+
235
+ void print_progress_bar(double progress) {
236
+ #ifndef WIN32
237
+ if (info_disabled) return;
238
+ int i = 0;
239
+ if(progress < 0) return;
240
+ if(progress > 100) progress = 100;
241
+ info("\r[");
242
+ for(i = 0; i < 50; i++) {
243
+ if(i < progress / 2) info("=");
244
+ else info(" ");
245
+ }
246
+ info("] %5.1f%%", progress);
247
+ if(progress >= 100) info("\n");
248
+ fflush((info_stream) ? info_stream : stdout);
249
+ #endif
250
+ }
251
+
252
+ #define GET_RAND(min, max) ((rand() % (max - min)) + min)
253
+
254
+ char *generate_guid(void)
255
+ {
256
+ char *guid = (char *) malloc(sizeof(char) * 37);
257
+ const char *chars = "ABCDEF0123456789";
258
+ srand(time(NULL));
259
+ int i = 0;
260
+
261
+ for (i = 0; i < 36; i++) {
262
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
263
+ guid[i] = '-';
264
+ continue;
265
+ } else {
266
+ guid[i] = chars[GET_RAND(0, 16)];
267
+ }
268
+ }
269
+ guid[36] = '\0';
270
+ return guid;
271
+ }
272
+
273
+ int mkdir_with_parents(const char *dir, int mode)
274
+ {
275
+ if (!dir) return -1;
276
+ if (__mkdir(dir, mode) == 0) {
277
+ return 0;
278
+ } else {
279
+ if (errno == EEXIST) {
280
+ return 0;
281
+ } else if (errno == ENOENT) {
282
+ // ignore
283
+ } else {
284
+ return -1;
285
+ }
286
+ }
287
+ int res;
288
+ char *parent = strdup(dir);
289
+ char *parentdir = dirname(parent);
290
+ if (parentdir && (strcmp(parentdir, ".") != 0) && (strcmp(parentdir, dir) != 0)) {
291
+ res = mkdir_with_parents(parentdir, mode);
292
+ } else {
293
+ res = -1;
294
+ }
295
+ free(parent);
296
+ if (res == 0) {
297
+ mkdir_with_parents(dir, mode);
298
+ }
299
+ return res;
300
+ }
301
+
302
+ #ifndef HAVE_MKSTEMP
303
+ /* Based on libc's __gen_tempname() from sysdeps/posix/tempname.c
304
+ Copyright (C) 1991-2018 Free Software Foundation, Inc.
305
+ With changes from https://stackoverflow.com/a/6036308 and some
306
+ additional changes. */
307
+ int mkstemp(char *tmpl)
308
+ {
309
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
310
+ int len;
311
+ char *XXXXXX;
312
+ static unsigned long long value;
313
+ unsigned long long random_time_bits;
314
+ unsigned int count;
315
+ int fd = -1;
316
+ int save_errno = errno;
317
+
318
+ /* A lower bound on the number of temporary files to attempt to
319
+ generate. The maximum total number of temporary file names that
320
+ can exist for a given template is 62**6. It should never be
321
+ necessary to try all these combinations. Instead if a reasonable
322
+ number of names is tried (we define reasonable as 62**3) fail to
323
+ give the system administrator the chance to remove the problems. */
324
+ #define ATTEMPTS_MIN (62 * 62 * 62)
325
+
326
+ /* The number of times to attempt to generate a temporary file. To
327
+ conform to POSIX, this must be no smaller than TMP_MAX. */
328
+ #if ATTEMPTS_MIN < TMP_MAX
329
+ unsigned int attempts = TMP_MAX;
330
+ #else
331
+ unsigned int attempts = ATTEMPTS_MIN;
332
+ #endif
333
+
334
+ len = strlen (tmpl);
335
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
336
+ {
337
+ errno = EINVAL;
338
+ return -1;
339
+ }
340
+
341
+ /* This is where the Xs start. */
342
+ XXXXXX = &tmpl[len - 6];
343
+
344
+ /* Get some more or less random data. */
345
+ #ifdef WIN32
346
+ {
347
+ SYSTEMTIME stNow;
348
+ FILETIME ftNow;
349
+
350
+ // get system time
351
+ GetSystemTime(&stNow);
352
+ if (!SystemTimeToFileTime(&stNow, &ftNow))
353
+ {
354
+ errno = -1;
355
+ return -1;
356
+ }
357
+
358
+ random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32)
359
+ | (unsigned long long)ftNow.dwLowDateTime);
360
+ }
361
+ value += random_time_bits ^ ((unsigned long long)GetCurrentProcessId() << 32 | (unsigned long long)GetCurrentThreadId());
362
+ #else
363
+ {
364
+ struct timeval tvNow = {0, 0};
365
+ gettimeofday(&tvNow, NULL);
366
+ random_time_bits = (((unsigned long long)tvNow.tv_sec << 32)
367
+ | (unsigned long long)tvNow.tv_usec);
368
+ }
369
+ value += random_time_bits ^ ((unsigned long long)getpid() << 32 | (unsigned long long)(uintptr_t)pthread_self());
370
+ #endif
371
+
372
+ for (count = 0; count < attempts; value += 7777, ++count)
373
+ {
374
+ unsigned long long v = value;
375
+
376
+ /* Fill in the random bits. */
377
+ XXXXXX[0] = letters[v % 62];
378
+ v /= 62;
379
+ XXXXXX[1] = letters[v % 62];
380
+ v /= 62;
381
+ XXXXXX[2] = letters[v % 62];
382
+ v /= 62;
383
+ XXXXXX[3] = letters[v % 62];
384
+ v /= 62;
385
+ XXXXXX[4] = letters[v % 62];
386
+ v /= 62;
387
+ XXXXXX[5] = letters[v % 62];
388
+
389
+ #ifdef WIN32
390
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
391
+ #else
392
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
393
+ #endif
394
+ if (fd >= 0)
395
+ {
396
+ errno = save_errno;
397
+ return fd;
398
+ }
399
+ else if (errno != EEXIST)
400
+ return -1;
401
+ }
402
+
403
+ /* We got out of the loop because we ran out of combinations to try. */
404
+ errno = EEXIST;
405
+ return -1;
406
+ }
407
+ #endif
408
+
409
+ char *get_temp_filename(const char *prefix)
410
+ {
411
+ char *result = NULL;
412
+ char *tmpdir;
413
+ size_t lt;
414
+ size_t lp;
415
+ const char *TMPVARS[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", NULL };
416
+ int i = 0;
417
+ int fd;
418
+
419
+ /* check the prefix parameter */
420
+ if (!prefix) {
421
+ prefix = "tmp_";
422
+ }
423
+ #ifdef WIN32
424
+ if (strchr(prefix, '/') || strchr(prefix, '\\')) return NULL;
425
+ #else
426
+ if (strchr(prefix, '/')) return NULL;
427
+ #endif
428
+
429
+ while (TMPVARS[i] && ((tmpdir = getenv(TMPVARS[i])) == NULL)) i++;
430
+ if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
431
+ #ifdef WIN32
432
+ tmpdir = "C:\\WINDOWS\\TEMP";
433
+ #else
434
+ tmpdir = P_tmpdir;
435
+ #endif
436
+ }
437
+ if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
438
+ return NULL;
439
+ }
440
+
441
+ lt = strlen(tmpdir);
442
+ if (lt < 1) {
443
+ return NULL;
444
+ }
445
+ lp = strlen(prefix);
446
+ result = malloc(lt + lp + 8);
447
+ memcpy(result, tmpdir, lt);
448
+ #ifdef WIN32
449
+ if (tmpdir[lt-1] != '/' && tmpdir[lt-1] != '\\') result[lt++] = '\\';
450
+ #else
451
+ if (tmpdir[lt-1] != '/') result[lt++] = '/';
452
+ #endif
453
+ strncpy(result + lt, prefix, lp);
454
+ strcpy(result + lt + lp, "XXXXXX");
455
+ fd = mkstemp(result);
456
+ if (fd < 0) {
457
+ free(result);
458
+ result = NULL;
459
+ }
460
+ close(fd);
461
+ return result;
462
+ }
463
+
464
+ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress)
465
+ {
466
+ if(client && client->progress_cb) {
467
+ client->progress_cb(step, progress, client->progress_cb_data);
468
+ } else {
469
+ // we don't want to be too verbose in regular idevicerestore.
470
+ if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) {
471
+ print_progress_bar(100.0 * progress);
472
+ }
473
+ }
474
+ }
475
+
476
+ #ifndef HAVE_STRSEP
477
+ char* strsep(char** strp, const char* delim)
478
+ {
479
+ char *p, *s;
480
+ if (strp == NULL || *strp == NULL || **strp == '\0') return NULL;
481
+ s = *strp;
482
+ p = s + strcspn(s, delim);
483
+ if (*p != '\0') *p++ = '\0';
484
+ *strp = p;
485
+ return s;
486
+ }
487
+ #endif
488
+
489
+ #ifndef HAVE_REALPATH
490
+ char* realpath(const char *filename, char *resolved_name)
491
+ {
492
+ #ifdef WIN32
493
+ if (access(filename, F_OK) != 0) {
494
+ return NULL;
495
+ }
496
+ if (GetFullPathName(filename, MAX_PATH, resolved_name, NULL) == 0) {
497
+ return NULL;
498
+ }
499
+ return resolved_name;
500
+ #else
501
+ #error please provide a realpath implementation for this platform
502
+ return NULL;
503
+ #endif
504
+ }
505
+ #endif
506
+
507
+ #ifdef WIN32
508
+ #define BS_CC '\b'
509
+ #define CTRL_C_CC 0x03
510
+ #define ESC_CC 0x1B
511
+ #define my_getch _getch
512
+ #else
513
+ #define BS_CC 0x7f
514
+ static int my_getch(void)
515
+ {
516
+ struct termios oldt, newt;
517
+ int ch;
518
+ tcgetattr(STDIN_FILENO, &oldt);
519
+ newt = oldt;
520
+ newt.c_lflag &= ~(ICANON | ECHO);
521
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
522
+ ch = getchar();
523
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
524
+ return ch;
525
+ }
526
+ #endif
527
+
528
+ void get_user_input(char *buf, int maxlen, int secure)
529
+ {
530
+ int len = 0;
531
+ int c;
532
+
533
+ while ((c = my_getch()) > 0) {
534
+ if ((c == '\r') || (c == '\n')) {
535
+ break;
536
+ } else if (isprint(c)) {
537
+ if (len < maxlen-1)
538
+ buf[len++] = c;
539
+ fputc((secure) ? '*' : c, stdout);
540
+ } else if (c == BS_CC) {
541
+ if (len > 0) {
542
+ fputs("\b \b", stdout);
543
+ len--;
544
+ }
545
+ }
546
+ #ifdef WIN32
547
+ else if (c == CTRL_C_CC || c == ESC_CC) {
548
+ c = -1;
549
+ break;
550
+ }
551
+ #endif
552
+ }
553
+ if (c < 0) {
554
+ len = 0;
555
+ }
556
+ fputs("\n", stdout);
557
+ buf[len] = 0;
558
+ }
559
+
560
+ uint64_t _plist_dict_get_uint(plist_t dict, const char *key)
561
+ {
562
+ uint64_t uintval = 0;
563
+ char *strval = NULL;
564
+ uint64_t strsz = 0;
565
+ plist_t node = plist_dict_get_item(dict, key);
566
+ if (!node) {
567
+ return (uint64_t)-1LL;
568
+ }
569
+ switch (plist_get_node_type(node)) {
570
+ case PLIST_UINT:
571
+ plist_get_uint_val(node, &uintval);
572
+ break;
573
+ case PLIST_STRING:
574
+ plist_get_string_val(node, &strval);
575
+ if (strval) {
576
+ uintval = strtoull(strval, NULL, 0);
577
+ free(strval);
578
+ }
579
+ break;
580
+ case PLIST_DATA:
581
+ plist_get_data_val(node, &strval, &strsz);
582
+ if (strval) {
583
+ if (strsz == 8) {
584
+ uintval = le64toh(*(uint64_t*)strval);
585
+ } else if (strsz == 4) {
586
+ uintval = le32toh(*(uint32_t*)strval);
587
+ } else if (strsz == 2) {
588
+ uintval = le16toh(*(uint16_t*)strval);
589
+ } else if (strsz == 1) {
590
+ uintval = strval[0];
591
+ } else {
592
+ error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
593
+ }
594
+ free(strval);
595
+ }
596
+ break;
597
+ default:
598
+ break;
599
+ }
600
+ return uintval;
601
+ }
602
+
603
+ uint8_t _plist_dict_get_bool(plist_t dict, const char *key)
604
+ {
605
+ uint8_t bval = 0;
606
+ uint64_t uintval = 0;
607
+ char *strval = NULL;
608
+ uint64_t strsz = 0;
609
+ plist_t node = plist_dict_get_item(dict, key);
610
+ if (!node) {
611
+ return 0;
612
+ }
613
+ switch (plist_get_node_type(node)) {
614
+ case PLIST_BOOLEAN:
615
+ plist_get_bool_val(node, &bval);
616
+ break;
617
+ case PLIST_UINT:
618
+ plist_get_uint_val(node, &uintval);
619
+ bval = (uint8_t)uintval;
620
+ break;
621
+ case PLIST_STRING:
622
+ plist_get_string_val(node, &strval);
623
+ if (strval) {
624
+ if (strcmp(strval, "true")) {
625
+ bval = 1;
626
+ } else if (strcmp(strval, "false")) {
627
+ bval = 0;
628
+ }
629
+ free(strval);
630
+ }
631
+ break;
632
+ case PLIST_DATA:
633
+ plist_get_data_val(node, &strval, &strsz);
634
+ if (strval) {
635
+ if (strsz == 1) {
636
+ bval = strval[0];
637
+ } else {
638
+ error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
639
+ }
640
+ free(strval);
641
+ }
642
+ break;
643
+ default:
644
+ break;
645
+ }
646
+ return bval;
647
+ }
common.h ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * common.h
3
+ * Misc functions used in idevicerestore
4
+ *
5
+ * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
6
+ * Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifndef IDEVICERESTORE_COMMON_H
25
+ #define IDEVICERESTORE_COMMON_H
26
+
27
+ #ifdef __cplusplus
28
+ extern "C" {
29
+ #endif
30
+
31
+ #ifdef HAVE_CONFIG_H
32
+ #include <config.h>
33
+ #endif
34
+
35
+ #include <inttypes.h>
36
+ #include <unistd.h>
37
+
38
+ #include <plist/plist.h>
39
+ #include <libirecovery.h>
40
+
41
+ #include "idevicerestore.h"
42
+ #include "thread.h"
43
+
44
+ #define MODE_UNKNOWN -1
45
+ #define MODE_WTF 0
46
+ #define MODE_DFU 1
47
+ #define MODE_RECOVERY 2
48
+ #define MODE_RESTORE 3
49
+ #define MODE_NORMAL 4
50
+
51
+ #define FLAG_QUIT 1
52
+
53
+ #define CPFM_FLAG_SECURITY_MODE 1 << 0
54
+ #define CPFM_FLAG_PRODUCTION_MODE 1 << 1
55
+
56
+ #define IBOOT_FLAG_IMAGE4_AWARE 1 << 2
57
+ #define IBOOT_FLAG_EFFECTIVE_SECURITY_MODE 1 << 3
58
+ #define IBOOT_FLAG_EFFECTIVE_PRODUCTION_MODE 1 << 4
59
+
60
+ #define USER_AGENT_STRING "InetURL/1.0"
61
+
62
+ struct dfu_client_t;
63
+ struct normal_client_t;
64
+ struct restore_client_t;
65
+ struct recovery_client_t;
66
+
67
+ struct idevicerestore_mode_t {
68
+ int index;
69
+ const char* string;
70
+ };
71
+
72
+ struct idevicerestore_entry_t {
73
+ char* name;
74
+ char* path;
75
+ char* filename;
76
+ char* blob_data;
77
+ uint32_t blob_size;
78
+ struct idevicerestore_entry* next;
79
+ struct idevicerestore_entry* prev;
80
+ };
81
+
82
+ struct idevicerestore_client_t {
83
+ int flags;
84
+ plist_t tss;
85
+ char* tss_url;
86
+ plist_t version_data;
87
+ uint64_t ecid;
88
+ unsigned char* nonce;
89
+ int nonce_size;
90
+ int image4supported;
91
+ plist_t preflight_info;
92
+ char* udid;
93
+ char* srnm;
94
+ char* ipsw;
95
+ const char* filesystem;
96
+ struct dfu_client_t* dfu;
97
+ struct restore_client_t* restore;
98
+ struct recovery_client_t* recovery;
99
+ irecv_device_t device;
100
+ struct idevicerestore_entry_t** entries;
101
+ struct idevicerestore_mode_t* mode;
102
+ char* version;
103
+ char* build;
104
+ int build_major;
105
+ char* restore_boot_args;
106
+ char* cache_dir;
107
+ unsigned char* root_ticket;
108
+ int root_ticket_len;
109
+ idevicerestore_progress_cb_t progress_cb;
110
+ void* progress_cb_data;
111
+ irecv_device_event_context_t irecv_e_ctx;
112
+ void* idevice_e_ctx;
113
+ mutex_t device_event_mutex;
114
+ cond_t device_event_cond;
115
+ int ignore_device_add_events;
116
+ };
117
+
118
+ extern struct idevicerestore_mode_t idevicerestore_modes[];
119
+
120
+ extern int idevicerestore_debug;
121
+
122
+ __attribute__((format(printf, 1, 2)))
123
+ void info(const char* format, ...);
124
+ __attribute__((format(printf, 1, 2)))
125
+ void error(const char* format, ...);
126
+ __attribute__((format(printf, 1, 2)))
127
+ void debug(const char* format, ...);
128
+
129
+ void debug_plist(plist_t plist);
130
+ void print_progress_bar(double progress);
131
+ int read_file(const char* filename, void** data, size_t* size);
132
+ int write_file(const char* filename, const void* data, size_t size);
133
+
134
+ char *generate_guid(void);
135
+
136
+ #ifdef WIN32
137
+ #include <windows.h>
138
+ #include <unistd.h>
139
+ #define __mkdir(path, mode) mkdir(path)
140
+ #ifndef sleep
141
+ #define sleep(x) Sleep(x*1000)
142
+ #endif
143
+ #define __usleep(x) Sleep(x/1000)
144
+ #else
145
+ #include <sys/stat.h>
146
+ #define __mkdir(path, mode) mkdir(path, mode)
147
+ #define __usleep(x) usleep(x)
148
+ #endif
149
+
150
+ int mkdir_with_parents(const char *dir, int mode);
151
+
152
+ char *get_temp_filename(const char *prefix);
153
+
154
+ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress);
155
+
156
+ #ifndef HAVE_STRSEP
157
+ char* strsep(char** strp, const char* delim);
158
+ #endif
159
+
160
+ #ifndef HAVE_REALPATH
161
+ char* realpath(const char *filename, char *resolved_name);
162
+ #endif
163
+
164
+ void get_user_input(char *buf, int maxlen, int secure);
165
+
166
+ uint8_t _plist_dict_get_bool(plist_t dict, const char *key);
167
+ uint64_t _plist_dict_get_uint(plist_t dict, const char *key);
168
+
169
+ #ifdef __cplusplus
170
+ }
171
+ #endif
172
+
173
+ #endif
companion_proxy.c ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * companion_proxy.c
3
+ * com.apple.companion_proxy service implementation.
4
+ *
5
+ * Copyright (c) 2019-2020 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
+ #include <string.h>
26
+ #include <stdlib.h>
27
+ #include <plist/plist.h>
28
+
29
+ #include "companion_proxy.h"
30
+ #include "lockdown.h"
31
+ #include "common/debug.h"
32
+
33
+ /**
34
+ * Convert a property_list_service_error_t value to a companion_proxy_error_t value.
35
+ * Used internally to get correct error codes.
36
+ *
37
+ * @param err An property_list_service_error_t error code
38
+ *
39
+ * @return A matching companion_proxy_error_t error code,
40
+ * COMPANION_PROXY_E_UNKNOWN_ERROR otherwise.
41
+ */
42
+ static companion_proxy_error_t companion_proxy_error(property_list_service_error_t err)
43
+ {
44
+ switch (err) {
45
+ case PROPERTY_LIST_SERVICE_E_SUCCESS:
46
+ return COMPANION_PROXY_E_SUCCESS;
47
+ case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
48
+ return COMPANION_PROXY_E_INVALID_ARG;
49
+ case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
50
+ return COMPANION_PROXY_E_PLIST_ERROR;
51
+ case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
52
+ return COMPANION_PROXY_E_MUX_ERROR;
53
+ case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
54
+ return COMPANION_PROXY_E_SSL_ERROR;
55
+ case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA:
56
+ return COMPANION_PROXY_E_NOT_ENOUGH_DATA;
57
+ case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
58
+ return COMPANION_PROXY_E_TIMEOUT;
59
+ default:
60
+ break;
61
+ }
62
+ return COMPANION_PROXY_E_UNKNOWN_ERROR;
63
+ }
64
+
65
+ companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client)
66
+ {
67
+ *client = NULL;
68
+
69
+ if (!device || !service || service->port == 0 || !client || *client) {
70
+ debug_info("Incorrect parameter passed to companion_proxy_client_new.");
71
+ return COMPANION_PROXY_E_INVALID_ARG;
72
+ }
73
+
74
+ debug_info("Creating companion_proxy_client, port = %d.", service->port);
75
+
76
+ property_list_service_client_t plclient = NULL;
77
+ companion_proxy_error_t ret = companion_proxy_error(property_list_service_client_new(device, service, &plclient));
78
+ if (ret != COMPANION_PROXY_E_SUCCESS) {
79
+ debug_info("Creating a property list client failed. Error: %i", ret);
80
+ return ret;
81
+ }
82
+
83
+ companion_proxy_client_t client_loc = (companion_proxy_client_t) malloc(sizeof(struct companion_proxy_client_private));
84
+ client_loc->parent = plclient;
85
+ client_loc->event_thread = THREAD_T_NULL;
86
+
87
+ *client = client_loc;
88
+
89
+ debug_info("Created companion_proxy_client successfully.");
90
+ return COMPANION_PROXY_E_SUCCESS;
91
+ }
92
+
93
+ companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label)
94
+ {
95
+ companion_proxy_error_t err = COMPANION_PROXY_E_UNKNOWN_ERROR;
96
+ service_client_factory_start_service(device, COMPANION_PROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(companion_proxy_client_new), &err);
97
+ return err;
98
+ }
99
+
100
+ companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client)
101
+ {
102
+ if (!client)
103
+ return COMPANION_PROXY_E_INVALID_ARG;
104
+
105
+ property_list_service_client_t parent = client->parent;
106
+ client->parent = NULL;
107
+ if (client->event_thread) {
108
+ debug_info("joining event thread");
109
+ thread_join(client->event_thread);
110
+ thread_free(client->event_thread);
111
+ client->event_thread = THREAD_T_NULL;
112
+ }
113
+ companion_proxy_error_t err = companion_proxy_error(property_list_service_client_free(parent));
114
+ free(client);
115
+
116
+ return err;
117
+ }
118
+
119
+ companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist)
120
+ {
121
+ companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
122
+
123
+ res = companion_proxy_error(property_list_service_send_binary_plist(client->parent, plist));
124
+ if (res != COMPANION_PROXY_E_SUCCESS) {
125
+ debug_info("Sending plist failed with error %d", res);
126
+ return res;
127
+ }
128
+
129
+ return res;
130
+ }
131
+
132
+ companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist)
133
+ {
134
+ companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
135
+ plist_t outplist = NULL;
136
+ res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, 10000));
137
+ if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
138
+ debug_info("Could not receive plist, error %d", res);
139
+ plist_free(outplist);
140
+ } else if (res == COMPANION_PROXY_E_SUCCESS) {
141
+ *plist = outplist;
142
+ }
143
+ return res;
144
+ }
145
+
146
+ companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices)
147
+ {
148
+ if (!client || !paired_devices) {
149
+ return COMPANION_PROXY_E_INVALID_ARG;
150
+ }
151
+
152
+ plist_t dict = plist_new_dict();
153
+ plist_dict_set_item(dict, "Command", plist_new_string("GetDeviceRegistry"));
154
+
155
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
156
+ plist_free(dict);
157
+ dict = NULL;
158
+ if (res != COMPANION_PROXY_E_SUCCESS) {
159
+ return res;
160
+ }
161
+
162
+ res = companion_proxy_receive(client, &dict);
163
+ if (res != COMPANION_PROXY_E_SUCCESS) {
164
+ return res;
165
+ }
166
+ if (!dict || !PLIST_IS_DICT(dict)) {
167
+ return COMPANION_PROXY_E_PLIST_ERROR;
168
+ }
169
+ plist_t val = plist_dict_get_item(dict, "PairedDevicesArray");
170
+ if (val) {
171
+ *paired_devices = plist_copy(val);
172
+ res = COMPANION_PROXY_E_SUCCESS;
173
+ } else {
174
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
175
+ val = plist_dict_get_item(dict, "Error");
176
+ if (val) {
177
+ if (plist_string_val_compare(val, "NoPairedWatches")) {
178
+ res = COMPANION_PROXY_E_NO_DEVICES;
179
+ }
180
+ }
181
+ }
182
+ plist_free(dict);
183
+ return res;
184
+ }
185
+
186
+ struct companion_proxy_cb_data {
187
+ companion_proxy_client_t client;
188
+ companion_proxy_device_event_cb_t cbfunc;
189
+ void* user_data;
190
+ };
191
+
192
+ static void* companion_proxy_event_thread(void* arg)
193
+ {
194
+ struct companion_proxy_cb_data* data = (struct companion_proxy_cb_data*)arg;
195
+ companion_proxy_client_t client = data->client;
196
+ companion_proxy_error_t res;
197
+
198
+ plist_t command = plist_new_dict();
199
+ plist_dict_set_item(command, "Command", plist_new_string("StartListeningForDevices"));
200
+ res = companion_proxy_send(client, command);
201
+ plist_free(command);
202
+
203
+ if (res != COMPANION_PROXY_E_SUCCESS) {
204
+ free(data);
205
+ client->event_thread = THREAD_T_NULL;
206
+ return NULL;
207
+ }
208
+
209
+ while (client && client->parent) {
210
+ plist_t node = NULL;
211
+ res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &node, 1000));
212
+ if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
213
+ debug_info("could not receive plist, error %d", res);
214
+ break;
215
+ }
216
+
217
+ if (node) {
218
+ data->cbfunc(node, data->user_data);
219
+ }
220
+ plist_free(node);
221
+ }
222
+
223
+ client->event_thread = THREAD_T_NULL;
224
+ free(data);
225
+
226
+ return NULL;
227
+ }
228
+
229
+ companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata)
230
+ {
231
+ if (!client || !client->parent || !callback) {
232
+ return COMPANION_PROXY_E_INVALID_ARG;
233
+ }
234
+
235
+ if (client->event_thread) {
236
+ return COMPANION_PROXY_E_OP_IN_PROGRESS;
237
+ }
238
+
239
+ companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
240
+ struct companion_proxy_cb_data *data = (struct companion_proxy_cb_data*)malloc(sizeof(struct companion_proxy_cb_data));
241
+ if (data) {
242
+ data->client = client;
243
+ data->cbfunc = callback;
244
+ data->user_data = userdata;
245
+
246
+ if (thread_new(&client->event_thread, companion_proxy_event_thread, data) == 0) {
247
+ res = COMPANION_PROXY_E_SUCCESS;
248
+ } else {
249
+ free(data);
250
+ }
251
+ }
252
+ return res;
253
+ }
254
+
255
+ companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client)
256
+ {
257
+ property_list_service_client_t parent = client->parent;
258
+ client->parent = NULL;
259
+ if (client->event_thread) {
260
+ debug_info("joining event thread");
261
+ thread_join(client->event_thread);
262
+ thread_free(client->event_thread);
263
+ client->event_thread = THREAD_T_NULL;
264
+ }
265
+ client->parent = parent;
266
+ return COMPANION_PROXY_E_SUCCESS;
267
+ }
268
+
269
+ companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value)
270
+ {
271
+ if (!client || !companion_udid || !key || !value) {
272
+ return COMPANION_PROXY_E_INVALID_ARG;
273
+ }
274
+
275
+ plist_t dict = plist_new_dict();
276
+ plist_dict_set_item(dict, "Command", plist_new_string("GetValueFromRegistry"));
277
+ plist_dict_set_item(dict, "GetValueGizmoUDIDKey", plist_new_string(companion_udid));
278
+ plist_dict_set_item(dict, "GetValueKeyKey", plist_new_string(key));
279
+
280
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
281
+ plist_free(dict);
282
+ dict = NULL;
283
+ if (res != COMPANION_PROXY_E_SUCCESS) {
284
+ return res;
285
+ }
286
+
287
+ res = companion_proxy_receive(client, &dict);
288
+ if (res != COMPANION_PROXY_E_SUCCESS) {
289
+ return res;
290
+ }
291
+ if (!dict || !PLIST_IS_DICT(dict)) {
292
+ return COMPANION_PROXY_E_PLIST_ERROR;
293
+ }
294
+ plist_t val = plist_dict_get_item(dict, "RetrievedValueDictionary");
295
+ if (val) {
296
+ *value = plist_copy(val);
297
+ res = COMPANION_PROXY_E_SUCCESS;
298
+ } else {
299
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
300
+ val = plist_dict_get_item(dict, "Error");
301
+ if (val) {
302
+ if (!plist_string_val_compare(val, "UnsupportedWatchKey")) {
303
+ res = COMPANION_PROXY_E_UNSUPPORTED_KEY;
304
+ } else if (plist_string_val_compare(val, "TimeoutReply")) {
305
+ res = COMPANION_PROXY_E_TIMEOUT_REPLY;
306
+ }
307
+ }
308
+ }
309
+ plist_free(dict);
310
+ return res;
311
+ }
312
+
313
+ companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options)
314
+ {
315
+ if (!client) {
316
+ return COMPANION_PROXY_E_INVALID_ARG;
317
+ }
318
+
319
+ plist_t dict = plist_new_dict();
320
+ plist_dict_set_item(dict, "Command", plist_new_string("StartForwardingServicePort"));
321
+ plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
322
+ if (service_name) {
323
+ plist_dict_set_item(dict, "ForwardedServiceName", plist_new_string(service_name));
324
+ }
325
+ plist_dict_set_item(dict, "IsServiceLowPriority", plist_new_bool(0));
326
+ plist_dict_set_item(dict, "PreferWifi", plist_new_bool(0));
327
+ if (options) {
328
+ plist_dict_merge(&dict, options);
329
+ }
330
+
331
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
332
+ plist_free(dict);
333
+ dict = NULL;
334
+ if (res != COMPANION_PROXY_E_SUCCESS) {
335
+ return res;
336
+ }
337
+
338
+ res = companion_proxy_receive(client, &dict);
339
+ if (res != COMPANION_PROXY_E_SUCCESS) {
340
+ return res;
341
+ }
342
+ plist_t val = plist_dict_get_item(dict, "CompanionProxyServicePort");
343
+ if (val) {
344
+ uint64_t u64val = 0;
345
+ plist_get_uint_val(val, &u64val);
346
+ *forward_port = (uint16_t)u64val;
347
+ res = COMPANION_PROXY_E_SUCCESS;
348
+ } else {
349
+ res = COMPANION_PROXY_E_UNKNOWN_ERROR;
350
+ }
351
+ plist_free(dict);
352
+
353
+ return res;
354
+ }
355
+
356
+ companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port)
357
+ {
358
+ if (!client) {
359
+ return COMPANION_PROXY_E_INVALID_ARG;
360
+ }
361
+
362
+ plist_t dict = plist_new_dict();
363
+ plist_dict_set_item(dict, "Command", plist_new_string("StopForwardingServicePort"));
364
+ plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
365
+
366
+ companion_proxy_error_t res = companion_proxy_send(client, dict);
367
+ plist_free(dict);
368
+ dict = NULL;
369
+ if (res != COMPANION_PROXY_E_SUCCESS) {
370
+ return res;
371
+ }
372
+
373
+ res = companion_proxy_receive(client, &dict);
374
+ if (res != COMPANION_PROXY_E_SUCCESS) {
375
+ return res;
376
+ }
377
+ plist_free(dict);
378
+
379
+ return res;
380
+ }
companion_proxy.h ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * companion_proxy.h
3
+ * com.apple.companion_proxy service header file.
4
+ *
5
+ * Copyright (c) 2019-2020 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
+ #ifndef __COMPANION_PROXY_H
23
+ #define __COMPANION_PROXY_H
24
+
25
+ #include "idevice.h"
26
+ #include "libimobiledevice/companion_proxy.h"
27
+ #include "property_list_service.h"
28
+ #include <libimobiledevice-glue/thread.h>
29
+
30
+ struct companion_proxy_client_private {
31
+ property_list_service_client_t parent;
32
+ THREAD_T event_thread;
33
+ };
34
+
35
+ #endif
configure.ac ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- Autoconf -*-
2
+ # Process this file with autoconf to produce a configure script.
3
+
4
+ AC_PREREQ([2.68])
5
+ AC_INIT([libimobiledevice], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/libimobiledevice/issues], [], [https://libimobiledevice.org])
6
+ AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news])
7
+ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
8
+ AC_CONFIG_SRCDIR([src/])
9
+ AC_CONFIG_HEADERS([config.h])
10
+ AC_CONFIG_MACRO_DIR([m4])
11
+
12
+ dnl libtool versioning
13
+ # +1 : 0 : +1 == adds new functions to the interface
14
+ # +1 : 0 : 0 == changes or removes functions (changes include both
15
+ # changes to the signature and the semantic)
16
+ # ? :+1 : ? == just internal changes
17
+ # CURRENT : REVISION : AGE
18
+ LIBIMOBILEDEVICE_SO_VERSION=7:0:1
19
+
20
+ AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION)
21
+
22
+ # Check if we have a version defined
23
+ if test -z $PACKAGE_VERSION; then
24
+ AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.])
25
+ fi
26
+
27
+ dnl Minimum package versions
28
+ LIBUSBMUXD_VERSION=2.0.2
29
+ LIBPLIST_VERSION=2.3.0
30
+ LIMD_GLUE_VERSION=1.3.0
31
+ LIBTATSU_VERSION=1.0.3
32
+
33
+ AC_SUBST(LIBUSBMUXD_VERSION)
34
+ AC_SUBST(LIBPLIST_VERSION)
35
+ AC_SUBST(LIMD_GLUE_VERSION)
36
+
37
+ # Checks for programs.
38
+ AC_PROG_CC
39
+ AC_PROG_CXX
40
+ AM_PROG_CC_C_O
41
+ LT_INIT
42
+
43
+ # Checks for libraries.
44
+ PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION)
45
+ PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION)
46
+ PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION)
47
+ PKG_CHECK_MODULES(libtatsu, libtatsu-1.0 >= $LIBTATSU_VERSION)
48
+ AC_ARG_WITH([readline],
49
+ [AS_HELP_STRING([--without-readline],
50
+ [build without support for libreadline (default is yes)])],
51
+ [check_libreadline=false],
52
+ [check_libreadline=true])
53
+ if test "$check_libreadline" = "true"; then
54
+ PKG_CHECK_MODULES(readline, readline >= 1.0, have_readline=yes, have_readline=no)
55
+ if test "x$have_readline" = "xyes"; then
56
+ AC_DEFINE(HAVE_READLINE, 1, [Define if readline library is available])
57
+ fi
58
+ fi
59
+ AM_CONDITIONAL([HAVE_READLINE],[test "x$have_readline" = "xyes"])
60
+
61
+ # Checks for header files.
62
+ AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h])
63
+
64
+ # Checks for typedefs, structures, and compiler characteristics.
65
+ AC_C_CONST
66
+ AC_TYPE_SIZE_T
67
+ AC_TYPE_SSIZE_T
68
+ AC_TYPE_UINT16_T
69
+ AC_TYPE_UINT32_T
70
+ AC_TYPE_UINT8_T
71
+
72
+ # Checks for library functions.
73
+ AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs gettimeofday localtime_r])
74
+
75
+ AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"])
76
+ if test "x$ac_cv_have_endian_h" = "xno"; then
77
+ AC_DEFINE(__LITTLE_ENDIAN,1234,[little endian])
78
+ AC_DEFINE(__BIG_ENDIAN,4321,[big endian])
79
+ AC_C_BIGENDIAN([ac_cv_c_bigendian="yes"], [ac_cv_c_bigendian="no"], [], [])
80
+ if test "x$ac_cv_c_bigendian" = "xyes"; then
81
+ AC_DEFINE(__BYTE_ORDER,4321,[big endian byte order])
82
+ else
83
+ AC_DEFINE(__BYTE_ORDER,1234,[little endian byte order])
84
+ fi
85
+ fi
86
+
87
+ CACHED_CFLAGS="$CFLAGS"
88
+ CFLAGS+=" $libplist_CFLAGS -Werror"
89
+
90
+ AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]])
91
+
92
+ # check if libplist has plist_new_unix_date()
93
+ AC_CACHE_CHECK(for plist_new_unix_date, ac_cv_plist_unix_date,
94
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
95
+ #include <plist/plist.h>
96
+ ]], [[
97
+ return plist_new_unix_date(0) ? 0 : 1
98
+ ]])],[ac_cv_plist_unix_date=yes],[ac_cv_plist_unix_date=no]))
99
+ if test "$ac_cv_plist_unix_date" = "yes"; then
100
+ AC_DEFINE(HAVE_PLIST_UNIX_DATE, 1, [Define if libplist has new unix date API (>= 2.7.0)])
101
+ fi
102
+
103
+ CFLAGS="$CACHED_CFLAGS"
104
+
105
+ # Check for operating system
106
+ AC_MSG_CHECKING([for platform-specific build settings])
107
+ case ${host_os} in
108
+ *mingw32*|*cygwin*)
109
+ AC_MSG_RESULT([${host_os}])
110
+ win32=true
111
+ AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
112
+ deplibs_check_method='pass_all'
113
+ ;;
114
+ darwin*)
115
+ AC_MSG_RESULT([${host_os}])
116
+ darwin=true
117
+ ;;
118
+ *)
119
+ AC_MSG_RESULT([${host_os}])
120
+ AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE_NAME])])
121
+ AC_CHECK_LIB(pthread, [pthread_once], [], [AC_MSG_ERROR([pthread with pthread_once required to build $PACKAGE_NAME])])
122
+ ;;
123
+ esac
124
+ AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
125
+ AM_CONDITIONAL(DARWIN, test x$darwin = xtrue)
126
+
127
+ AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>])
128
+
129
+ # Cython Python Bindings
130
+ AC_ARG_WITH([cython],
131
+ [AS_HELP_STRING([--without-cython],
132
+ [build Python bindings using Cython (default is yes)])],
133
+ [build_cython=false],
134
+ [build_cython=true])
135
+ if test "$build_cython" = "true"; then
136
+ AC_PROG_CYTHON([3.0.0])
137
+ if [test "x$CYTHON" != "xfalse"]; then
138
+ AM_PATH_PYTHON([3.0], [
139
+ CYTHON_PYTHON
140
+ AS_COMPILER_FLAG([-Wno-cast-function-type -Werror], [
141
+ CYTHON_CFLAGS+=" -Wno-cast-function-type"
142
+ AC_SUBST([CYTHON_CFLAGS])
143
+ ], [])
144
+ ])
145
+ else
146
+ AC_MSG_WARN([Use the "--without-cython" option to avoid this warning.])
147
+ fi
148
+ else
149
+ CYTHON=false
150
+ fi
151
+ if [test "x$CYTHON" != "xfalse"]; then
152
+ PKG_PROG_PKG_CONFIG
153
+ AC_MSG_CHECKING([for libplist Cython bindings])
154
+ CYTHON_PLIST_INCLUDE_DIR=$($PKG_CONFIG --variable=includedir libplist-2.0)/plist/cython
155
+ if [test ! -d "$CYTHON_PLIST_INCLUDE_DIR"]; then
156
+ CYTHON=false
157
+ CYTHON_SUB=
158
+ cython_python_bindings=no
159
+ AC_MSG_RESULT([no])
160
+ AC_MSG_WARN([Unable to find libplist Cython bindings. You should install your distribution specific libplist Cython bindings package.])
161
+ else
162
+ AC_SUBST([CYTHON_PLIST_INCLUDE_DIR])
163
+ AC_MSG_RESULT([$CYTHON_PLIST_INCLUDE_DIR])
164
+ CYTHON_SUB=cython
165
+ cython_python_bindings=yes
166
+ fi
167
+ else
168
+ CYTHON_SUB=
169
+ cython_python_bindings=no
170
+ fi
171
+ AM_CONDITIONAL([HAVE_CYTHON],[test "x$CYTHON_SUB" = "xcython"])
172
+ AC_SUBST([CYTHON_SUB])
173
+
174
+ default_openssl=yes
175
+
176
+ AC_ARG_WITH([mbedtls],
177
+ [AS_HELP_STRING([--without-mbedtls],
178
+ [Do not look for mbedtls])],
179
+ [use_mbedtls=$withval],
180
+ [use_mbedtls=no])
181
+ if test "x$use_mbedtls" = "xyes"; then
182
+ default_openssl=no
183
+ fi
184
+ AC_ARG_WITH([gnutls],
185
+ [AS_HELP_STRING([--without-gnutls],
186
+ [Do not look for GnuTLS])],
187
+ [use_gnutls=$withval],
188
+ [use_gnutls=no])
189
+ if test "x$use_gnutls" = "xyes"; then
190
+ default_openssl=no
191
+ fi
192
+ AC_ARG_WITH([openssl],
193
+ [AS_HELP_STRING([--without-openssl],
194
+ [Do not look for OpenSSL])],
195
+ [use_openssl=$withval],
196
+ [use_openssl=$default_openssl])
197
+
198
+ if test "x$use_mbedtls" = "xyes"; then
199
+ CACHED_CFLAGS="$CFLAGS"
200
+ conf_mbedtls_CFLAGS=""
201
+ if test -n "$mbedtls_INCLUDES"; then
202
+ CFLAGS=" -I$mbedtls_INCLUDES"
203
+ conf_mbedtls_CFLAGS="-I$mbedtls_INCLUDES"
204
+ fi
205
+ conf_mbedtls_LIBS=""
206
+ if test -n "$mbedtls_LIBDIR"; then
207
+ conf_mbedtls_LIBS+=" -L$mbedtls_LIBDIR"
208
+ fi
209
+ if test -n "$mbedtls_LIBS"; then
210
+ conf_mbedtls_LIBS+=" $mbedtls_LIBS"
211
+ else
212
+ conf_mbedtls_LIBS+=" -lmbedtls -lmbedx509 -lmbedcrypto"
213
+ fi
214
+ AC_CHECK_HEADER(mbedtls/ssl.h, [break], [AC_MSG_ERROR([MbedTLS support explicitly requested, but includes could not be found. Try setting mbedtls_INCLUDES=/path/to/mbedtls/include])])
215
+ CFLAGS="$CACHED_CFLAGS"
216
+ AC_DEFINE(HAVE_MBEDTLS, 1, [Define if you have MbedTLS support])
217
+ ssl_lib_CFLAGS="$conf_mbedtls_CFLAGS"
218
+ ssl_lib_LIBS="$conf_mbedtls_LIBS"
219
+ AC_SUBST(ssl_lib_CFLAGS)
220
+ AC_SUBST(ssl_lib_LIBS)
221
+ ssl_provider="MbedTLS";
222
+ ssl_requires=""
223
+ AC_SUBST(ssl_requires)
224
+ else
225
+ if test "x$use_openssl" = "xyes"; then
226
+ pkg_req_openssl="openssl >= 0.9.8"
227
+ PKG_CHECK_MODULES(openssl, $pkg_req_openssl, have_openssl=yes, have_openssl=no)
228
+ if test "x$have_openssl" != "xyes"; then
229
+ AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found])
230
+ else
231
+ AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support])
232
+ ssl_lib_CFLAGS="$openssl_CFLAGS"
233
+ ssl_lib_LIBS="$openssl_LIBS"
234
+ AC_SUBST(ssl_lib_CFLAGS)
235
+ AC_SUBST(ssl_lib_LIBS)
236
+ ssl_provider="OpenSSL";
237
+ ssl_requires="$pkg_req_openssl"
238
+ # test if we have LibreSSL
239
+ CACHED_CFLAGS="$CFLAGS"
240
+ CFLAGS="$openssl_CFLAGS"
241
+ ac_cv_is_libressl=no
242
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
243
+ [[
244
+ #include <openssl/opensslv.h>
245
+ ]], [
246
+ #ifndef LIBRESSL_VERSION_NUMBER
247
+ #error No LibreSSL
248
+ #endif
249
+ ])],
250
+ [
251
+ ac_cv_is_libressl=yes
252
+ ],
253
+ )
254
+ CFLAGS="$CACHED_CFLAGS"
255
+ if test "x$ac_cv_is_libressl" = "xyes"; then
256
+ ssl_provider="LibreSSL"
257
+ case ${host_os} in
258
+ darwin*)
259
+ case ${openssl_LIBS} in
260
+ *.tbd*)
261
+ # using system LibreSSL on Darwin
262
+ ssl_requires=""
263
+ ;;
264
+ esac
265
+ ;;
266
+ esac
267
+ fi
268
+ AC_SUBST(ssl_requires)
269
+ fi
270
+ else
271
+ if test "x$use_gnutls" = "xyes"; then
272
+ pkg_req_gnutls="gnutls >= 2.2.0"
273
+ pkg_req_libtasn1="libtasn1 >= 1.1"
274
+ PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls)
275
+ AC_CHECK_HEADERS([gcrypt.h])
276
+ AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])])
277
+ PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1)
278
+ AC_DEFINE(HAVE_GCRYPT, 1, [Define if you have libgcrypt support])
279
+ AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS support])
280
+ ssl_lib_CFLAGS="$libgnutls_CFLAGS $libtasn1_CFLAGS $libgcrypt_CFLAGS"
281
+ ssl_lib_LIBS="$libgnutls_LIBS $libtasn1_LIBS $libgcrypt_LIBS"
282
+ AC_SUBST(ssl_lib_CFLAGS)
283
+ AC_SUBST(ssl_lib_LIBS)
284
+ ssl_provider="GnuTLS"
285
+ ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1"
286
+ AC_SUBST(ssl_requires)
287
+ else
288
+ AC_MSG_ERROR([No SSL library configured. $PACKAGE cannot be built without a supported SSL library.])
289
+ fi
290
+ fi
291
+ fi
292
+ AM_CONDITIONAL(HAVE_MBEDTLS, test "x$use_mbedtls" = "xyes")
293
+ AM_CONDITIONAL(HAVE_OPENSSL, test "x$use_openssl" = "xyes")
294
+ AM_CONDITIONAL(HAVE_GCRYPT, test "x$use_gnutls" = "xyes")
295
+
296
+ AC_ARG_ENABLE([wireless-pairing],
297
+ [AS_HELP_STRING([--disable-wireless-pairing],
298
+ [Do not build with wirless pairing support (default is yes)])])
299
+ if test "$enable_wireless_pairing" != "no"; then
300
+ AC_DEFINE(HAVE_WIRELESS_PAIRING,1,[Define if building with wireless pairing support])
301
+ fi
302
+ AM_CONDITIONAL(HAVE_WIRELESS_PAIRING, test "$enable_wireless_pairing" != "no")
303
+
304
+ AC_ARG_ENABLE([debug],
305
+ [AS_HELP_STRING([--enable-debug],
306
+ [build debug message output code (default is no)])],
307
+ [no_debug_code=false],
308
+ [no_debug_code=true])
309
+ if test "$no_debug_code" = true; then
310
+ building_debug_code=no
311
+ AC_DEFINE(STRIP_DEBUG_CODE,1,[Define if debug message output code should not be built.])
312
+ else
313
+ building_debug_code=yes
314
+ fi
315
+
316
+ AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fsigned-char -fvisibility=hidden")
317
+
318
+ if test "x$enable_static" = "xyes" -a "x$enable_shared" = "xno"; then
319
+ GLOBAL_CFLAGS+=" -DLIBIMOBILEDEVICE_STATIC"
320
+ fi
321
+
322
+ AC_SUBST(GLOBAL_CFLAGS)
323
+
324
+ # check for large file support
325
+ AC_SYS_LARGEFILE
326
+
327
+ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
328
+
329
+ AC_CONFIG_FILES([
330
+ Makefile
331
+ 3rd_party/Makefile
332
+ 3rd_party/ed25519/Makefile
333
+ 3rd_party/libsrp6a-sha512/Makefile
334
+ common/Makefile
335
+ src/Makefile
336
+ src/libimobiledevice-1.0.pc
337
+ include/Makefile
338
+ tools/Makefile
339
+ cython/Makefile
340
+ docs/Makefile
341
+ doxygen.cfg
342
+ ])
343
+ AC_OUTPUT
344
+
345
+ echo "
346
+ Configuration for $PACKAGE $VERSION:
347
+ -------------------------------------------
348
+
349
+ Install prefix: .........: $prefix
350
+ Debug code ..............: $building_debug_code
351
+ Python bindings .........: $cython_python_bindings
352
+ SSL support backend .....: $ssl_provider
353
+
354
+ Now type 'make' to build $PACKAGE $VERSION,
355
+ and then 'make install' for installation.
356
+ "
cython_python.m4 ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ AC_DEFUN([CYTHON_PYTHON],[
2
+ AC_REQUIRE([AC_PROG_CYTHON])
3
+ AC_REQUIRE([AX_PYTHON_DEVEL])
4
+ test "x$1" != "xno" || cython_shadow=" -noproxy"
5
+ AC_SUBST([CYTHON_PYTHON_OPT],[-python$cython_shadow])
6
+ AC_SUBST([CYTHON_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
7
+ ])
debug.c ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * debug.c
3
+ * contains utilitary functions for debugging
4
+ *
5
+ * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6
+ * Copyright (c) 2010 Martin S. All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+ #ifdef HAVE_CONFIG_H
24
+ #include <config.h>
25
+ #endif
26
+ #include <stdarg.h>
27
+ #define _GNU_SOURCE 1
28
+ #define __USE_GNU 1
29
+ #include <stdio.h>
30
+ #include <stdint.h>
31
+ #include <stdlib.h>
32
+ #include <time.h>
33
+ #ifndef _WIN32
34
+ #include <sys/time.h>
35
+ #endif
36
+
37
+ #include "src/idevice.h"
38
+ #include "debug.h"
39
+ #include "libimobiledevice/libimobiledevice.h"
40
+
41
+ #ifndef STRIP_DEBUG_CODE
42
+ #include "asprintf.h"
43
+ #endif
44
+
45
+ static int debug_level;
46
+
47
+ void internal_set_debug_level(int level)
48
+ {
49
+ debug_level = level;
50
+ }
51
+
52
+ #define MAX_PRINT_LEN (16*1024)
53
+
54
+ #ifndef STRIP_DEBUG_CODE
55
+ static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
56
+ {
57
+ char str_time[24];
58
+ #ifdef _WIN32
59
+ SYSTEMTIME lt;
60
+ GetLocalTime(&lt);
61
+ snprintf(str_time, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
62
+ #else
63
+ #ifdef HAVE_GETTIMEOFDAY
64
+ struct timeval tv;
65
+ struct tm *tp;
66
+ gettimeofday(&tv, NULL);
67
+ #ifdef HAVE_LOCALTIME_R
68
+ struct tm tp_;
69
+ tp = localtime_r(&tv.tv_sec, &tp_);
70
+ #else
71
+ tp = localtime(&tv.tv_sec);
72
+ #endif
73
+ strftime(str_time, 9, "%H:%M:%S", tp);
74
+ snprintf(str_time+8, 10, ".%03d", (int)tv.tv_usec/1000);
75
+ #else
76
+ time_t the_time;
77
+ time(&the_time);
78
+ strftime(str_time, 15, "%H:%M:%S", localtime (&the_time));
79
+ #endif
80
+ #endif
81
+ fprintf(stderr, "%s %s:%d %s(): %s\n", str_time, file, line, func, buffer);
82
+ }
83
+ #endif
84
+
85
+ void debug_info_real(const char *func, const char *file, int line, const char *format, ...)
86
+ {
87
+ #ifndef STRIP_DEBUG_CODE
88
+ va_list args;
89
+ char *buffer = NULL;
90
+
91
+ if (!debug_level)
92
+ return;
93
+
94
+ /* run the real fprintf */
95
+ va_start(args, format);
96
+ if(vasprintf(&buffer, format, args)<0){}
97
+ va_end(args);
98
+
99
+ debug_print_line(func, file, line, buffer);
100
+
101
+ free(buffer);
102
+ #endif
103
+ }
104
+
105
+ void debug_buffer(const char *data, const int length)
106
+ {
107
+ #ifndef STRIP_DEBUG_CODE
108
+ int i;
109
+ int j;
110
+ unsigned char c;
111
+
112
+ if (debug_level) {
113
+ for (i = 0; i < length; i += 16) {
114
+ fprintf(stderr, "%04x: ", i);
115
+ for (j = 0; j < 16; j++) {
116
+ if (i + j >= length) {
117
+ fprintf(stderr, " ");
118
+ continue;
119
+ }
120
+ fprintf(stderr, "%02x ", *(data + i + j) & 0xff);
121
+ }
122
+ fprintf(stderr, " | ");
123
+ for (j = 0; j < 16; j++) {
124
+ if (i + j >= length)
125
+ break;
126
+ c = *(data + i + j);
127
+ if ((c < 32) || (c > 127)) {
128
+ fprintf(stderr, ".");
129
+ continue;
130
+ }
131
+ fprintf(stderr, "%c", c);
132
+ }
133
+ fprintf(stderr, "\n");
134
+ }
135
+ fprintf(stderr, "\n");
136
+ }
137
+ #endif
138
+ }
139
+
140
+ void debug_buffer_to_file(const char *file, const char *data, const int length)
141
+ {
142
+ #ifndef STRIP_DEBUG_CODE
143
+ if (debug_level) {
144
+ FILE *f = fopen(file, "wb");
145
+ fwrite(data, 1, length, f);
146
+ fflush(f);
147
+ fclose(f);
148
+ }
149
+ #endif
150
+ }
151
+
152
+ void debug_plist_real(const char *func, const char *file, int line, plist_t plist)
153
+ {
154
+ #ifndef STRIP_DEBUG_CODE
155
+ if (!plist)
156
+ return;
157
+
158
+ char *buffer = NULL;
159
+ uint32_t length = 0;
160
+ plist_to_xml(plist, &buffer, &length);
161
+
162
+ /* get rid of ending newline as one is already added in the debug line */
163
+ if (buffer[length-1] == '\n')
164
+ buffer[length-1] = '\0';
165
+
166
+ if (length <= MAX_PRINT_LEN)
167
+ debug_info_real(func, file, line, "printing %i bytes plist:\n%s", length, buffer);
168
+ else
169
+ debug_info_real(func, file, line, "supress printing %i bytes plist...\n", length);
170
+
171
+ free(buffer);
172
+ #endif
173
+ }
174
+
debug.h ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * debug.h
3
+ * contains utilitary functions for debugging
4
+ *
5
+ * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6
+ * Copyright (c) 2010 Martin S. All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+ #ifndef __DEBUG_H
24
+ #define __DEBUG_H
25
+
26
+ #include <plist/plist.h>
27
+
28
+ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE)
29
+ #define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__)
30
+ #define debug_plist(a) debug_plist_real (__func__, __FILE__, __LINE__, a)
31
+ #elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE)
32
+ #define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
33
+ #define debug_plist(a) debug_plist_real (__FUNCTION__, __FILE__, __LINE__, a)
34
+ #else
35
+ #define debug_info(...)
36
+ #define debug_plist(a)
37
+ #endif
38
+
39
+ void debug_info_real(const char *func,
40
+ const char *file,
41
+ int line,
42
+ const char *format, ...);
43
+
44
+ void debug_buffer(const char *data, const int length);
45
+ void debug_buffer_to_file(const char *file, const char *data, const int length);
46
+ void debug_plist_real(const char *func,
47
+ const char *file,
48
+ int line,
49
+ plist_t plist);
50
+
51
+ void internal_set_debug_level(int level);
52
+
53
+ #endif
debugserver.c ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * debugserver.c
3
+ * com.apple.debugserver service implementation.
4
+ *
5
+ * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
6
+ * Copyright (c) 2014-2015 Martin Szulecki All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+ #ifdef HAVE_CONFIG_H
24
+ #include <config.h>
25
+ #endif
26
+ #include <string.h>
27
+ #include <stdlib.h>
28
+ #define _GNU_SOURCE 1
29
+ #define __USE_GNU 1
30
+ #include <stdio.h>
31
+
32
+ #include <libimobiledevice-glue/utils.h>
33
+
34
+ #include "debugserver.h"
35
+ #include "lockdown.h"
36
+ #include "common/debug.h"
37
+ #include "asprintf.h"
38
+
39
+ /**
40
+ * Convert a service_error_t value to a debugserver_error_t value.
41
+ * Used internally to get correct error codes.
42
+ *
43
+ * @param err An service_error_t error code
44
+ *
45
+ * @return A matching debugserver_error_t error code,
46
+ * DEBUGSERVER_E_UNKNOWN_ERROR otherwise.
47
+ */
48
+ static debugserver_error_t debugserver_error(service_error_t err)
49
+ {
50
+ switch (err) {
51
+ case SERVICE_E_SUCCESS:
52
+ return DEBUGSERVER_E_SUCCESS;
53
+ case SERVICE_E_INVALID_ARG:
54
+ return DEBUGSERVER_E_INVALID_ARG;
55
+ case SERVICE_E_MUX_ERROR:
56
+ return DEBUGSERVER_E_MUX_ERROR;
57
+ case SERVICE_E_SSL_ERROR:
58
+ return DEBUGSERVER_E_SSL_ERROR;
59
+ case SERVICE_E_TIMEOUT:
60
+ return DEBUGSERVER_E_TIMEOUT;
61
+ default:
62
+ break;
63
+ }
64
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
65
+ }
66
+
67
+ debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client)
68
+ {
69
+ *client = NULL;
70
+
71
+ if (!device || !service || service->port == 0 || !client || *client) {
72
+ debug_info("Incorrect parameter passed to debugserver_client_new.");
73
+ return DEBUGSERVER_E_INVALID_ARG;
74
+ }
75
+
76
+ debug_info("Creating debugserver_client, port = %d.", service->port);
77
+
78
+ service_client_t parent = NULL;
79
+ debugserver_error_t ret = debugserver_error(service_client_new(device, service, &parent));
80
+ if (ret != DEBUGSERVER_E_SUCCESS) {
81
+ debug_info("Creating base service client failed. Error: %i", ret);
82
+ return ret;
83
+ }
84
+
85
+ if (service->identifier && (strcmp(service->identifier, DEBUGSERVER_SECURE_SERVICE_NAME) != 0)) {
86
+ service_disable_bypass_ssl(parent, 1);
87
+ }
88
+
89
+ debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private));
90
+ client_loc->parent = parent;
91
+ client_loc->noack_mode = 0;
92
+ client_loc->cancel_receive = NULL;
93
+ client_loc->receive_loop_timeout = 1000;
94
+
95
+ *client = client_loc;
96
+
97
+ debug_info("debugserver_client successfully created.");
98
+ return DEBUGSERVER_E_SUCCESS;
99
+ }
100
+
101
+ debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label)
102
+ {
103
+ debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR;
104
+ service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
105
+ if (err != DEBUGSERVER_E_SUCCESS) {
106
+ err = DEBUGSERVER_E_UNKNOWN_ERROR;
107
+ service_client_factory_start_service(device, DEBUGSERVER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
108
+ }
109
+ return err;
110
+ }
111
+
112
+ debugserver_error_t debugserver_client_free(debugserver_client_t client)
113
+ {
114
+ if (!client)
115
+ return DEBUGSERVER_E_INVALID_ARG;
116
+
117
+ debugserver_error_t err = debugserver_error(service_client_free(client->parent));
118
+ client->parent = NULL;
119
+ free(client);
120
+
121
+ return err;
122
+ }
123
+
124
+ debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
125
+ {
126
+ debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
127
+ int bytes = 0;
128
+
129
+ if (!client || !data || (size == 0)) {
130
+ return DEBUGSERVER_E_INVALID_ARG;
131
+ }
132
+
133
+ debug_info("sending %d bytes", size);
134
+ res = debugserver_error(service_send(client->parent, data, size, (uint32_t*)&bytes));
135
+ if (bytes <= 0) {
136
+ debug_info("ERROR: sending to device failed.");
137
+ }
138
+ if (sent) {
139
+ *sent = (uint32_t)bytes;
140
+ }
141
+
142
+ return res;
143
+ }
144
+
145
+ debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
146
+ {
147
+ debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
148
+ int bytes = 0;
149
+
150
+ if (!client || !data || (size == 0)) {
151
+ return DEBUGSERVER_E_INVALID_ARG;
152
+ }
153
+
154
+ res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
155
+ if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) {
156
+ debug_info("Could not read data, error %d", res);
157
+ }
158
+ if (received) {
159
+ *received = (uint32_t)bytes;
160
+ }
161
+
162
+ return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res;
163
+ }
164
+
165
+ debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
166
+ {
167
+ debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
168
+ do {
169
+ /* Is this allowed to return DEBUGSERVER_E_TIMEOUT and also set data and received? */
170
+ res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout);
171
+ } while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive());
172
+ return res;
173
+ }
174
+
175
+ debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
176
+ {
177
+ int i;
178
+ debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private));
179
+
180
+ /* copy name */
181
+ tmp->name = strdup(name);
182
+
183
+ /* copy arguments */
184
+ tmp->argc = argc;
185
+ tmp->argv = NULL;
186
+ if (argc > 0) {
187
+ tmp->argv = malloc(sizeof(char*) * (argc + 2));
188
+ for (i = 0; i < argc; i++) {
189
+ tmp->argv[i] = strdup(argv[i]);
190
+ }
191
+ tmp->argv[i+1] = NULL;
192
+ }
193
+
194
+ /* return */
195
+ *command = tmp;
196
+
197
+ return DEBUGSERVER_E_SUCCESS;
198
+ }
199
+
200
+ debugserver_error_t debugserver_command_free(debugserver_command_t command)
201
+ {
202
+ int i;
203
+ debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
204
+
205
+ if (!command)
206
+ return DEBUGSERVER_E_INVALID_ARG;
207
+
208
+ if (command) {
209
+ if (command->name)
210
+ free(command->name);
211
+ if (command->argv && command->argc) {
212
+ for (i = 0; i < command->argc; i++) {
213
+ free(command->argv[i]);
214
+ }
215
+ free(command->argv);
216
+ }
217
+ free(command);
218
+ res = DEBUGSERVER_E_SUCCESS;
219
+ }
220
+
221
+ return res;
222
+ }
223
+
224
+ static int debugserver_hex2int(char c)
225
+ {
226
+ if (c >= '0' && c <= '9')
227
+ return c - '0';
228
+ else if (c >= 'a' && c <= 'f')
229
+ return 10 + c - 'a';
230
+ else if (c >= 'A' && c <= 'F')
231
+ return 10 + c - 'A';
232
+ else
233
+ return c;
234
+ }
235
+
236
+ static char debugserver_int2hex(int x)
237
+ {
238
+ const char *hexchars = "0123456789ABCDEF";
239
+ return hexchars[x];
240
+ }
241
+
242
+ #define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex(((byte) >> 0x4) & 0xf)
243
+ #define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex((byte) & 0xf)
244
+ #define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) (((byte) >> 0x4) & 0xf)
245
+ #define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) ((byte) & 0xf)
246
+
247
+ static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size)
248
+ {
249
+ uint32_t checksum = 0;
250
+ uint32_t i;
251
+
252
+ for (i = 0; i < size; i++) {
253
+ checksum += buffer[i];
254
+ }
255
+
256
+ return checksum;
257
+ }
258
+
259
+ static int debugserver_response_is_checksum_valid(const char* response, uint32_t size)
260
+ {
261
+ uint32_t checksum = 0;
262
+ if ((size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1) > 0)
263
+ checksum = debugserver_get_checksum_for_buffer(&response[1], size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
264
+
265
+ debug_info("checksum: 0x%x", checksum);
266
+
267
+ if ((unsigned)debugserver_hex2int(response[size - 2]) != DEBUGSERVER_HEX_DECODE_FIRST_BYTE(checksum))
268
+ return 0;
269
+
270
+ if ((unsigned)debugserver_hex2int(response[size - 1]) != DEBUGSERVER_HEX_DECODE_SECOND_BYTE(checksum))
271
+ return 0;
272
+
273
+ debug_info("valid checksum");
274
+
275
+ return 1;
276
+ }
277
+
278
+ void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
279
+ {
280
+ uint32_t position;
281
+ uint32_t index;
282
+ uint32_t length = strlen(buffer);
283
+ *encoded_length = (2 * length) + DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1;
284
+
285
+ *encoded_buffer = malloc(sizeof(char) * (*encoded_length));
286
+ memset(*encoded_buffer, '\0', *encoded_length);
287
+ for (position = 0, index = 0; index < length; index++) {
288
+ position = (index * (2 * sizeof(char)));
289
+ (*encoded_buffer)[position] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(buffer[index]);
290
+ (*encoded_buffer)[position + 1] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(buffer[index]);
291
+ }
292
+ }
293
+
294
+ void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
295
+ {
296
+ *buffer = malloc(sizeof(char) * ((encoded_length / 2)+1));
297
+ char* t = *buffer;
298
+ const char *f = encoded_buffer;
299
+ const char *fend = f + encoded_length;
300
+ while (f < fend) {
301
+ *t++ = debugserver_hex2int(*f) << 4 | debugserver_hex2int(f[1]);
302
+ f += 2;
303
+ }
304
+ *t = '\0';
305
+ }
306
+
307
+ static void debugserver_format_command(const char* prefix, const char* command, const char* arguments, int calculate_checksum, char** buffer, uint32_t* size)
308
+ {
309
+ char checksum_hash[DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1] = {'#', '0', '0', '\0'};
310
+ char* encoded = NULL;
311
+ uint32_t encoded_length = 0;
312
+
313
+ if (arguments) {
314
+ /* arguments must be hex encoded */
315
+ debugserver_encode_string(arguments, &encoded, &encoded_length);
316
+ } else {
317
+ encoded = NULL;
318
+ }
319
+
320
+ char* encoded_command = string_concat(command, encoded, NULL);
321
+ encoded_length = strlen(encoded_command);
322
+
323
+ if (calculate_checksum) {
324
+ uint32_t checksum = debugserver_get_checksum_for_buffer(encoded_command, encoded_length);
325
+ checksum_hash[1] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(checksum);
326
+ checksum_hash[2] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(checksum);
327
+ }
328
+
329
+ *buffer = string_concat(prefix, encoded_command, checksum_hash, NULL);
330
+ *size = strlen(prefix) + strlen(encoded_command) + DEBUGSERVER_CHECKSUM_HASH_LENGTH;
331
+
332
+ debug_info("formatted command: %s size: %d checksum: 0x%s", *buffer, *size, checksum_hash);
333
+
334
+ if (encoded_command)
335
+ free(encoded_command);
336
+
337
+ if (encoded)
338
+ free(encoded);
339
+ }
340
+
341
+ static debugserver_error_t debugserver_client_send_ack(debugserver_client_t client)
342
+ {
343
+ debug_info("sending ACK");
344
+ return debugserver_client_send(client, "+", sizeof(char), NULL);
345
+ }
346
+
347
+ static debugserver_error_t debugserver_client_send_noack(debugserver_client_t client)
348
+ {
349
+ debug_info("sending !ACK");
350
+ return debugserver_client_send(client, "-", sizeof(char), NULL);
351
+ }
352
+
353
+ debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled)
354
+ {
355
+ if (!client)
356
+ return DEBUGSERVER_E_INVALID_ARG;
357
+
358
+ client->noack_mode = (enabled == 0)? 1: 0;
359
+
360
+ debug_info("ack mode: %s", client->noack_mode == 0 ? "on": "off");
361
+
362
+ return DEBUGSERVER_E_SUCCESS;
363
+ }
364
+
365
+ debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout)
366
+ {
367
+ if (!client)
368
+ return DEBUGSERVER_E_INVALID_ARG;
369
+
370
+ client->cancel_receive = cancel_receive;
371
+ client->receive_loop_timeout = receive_loop_timeout;
372
+
373
+ debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout);
374
+
375
+ return DEBUGSERVER_E_SUCCESS;
376
+ }
377
+
378
+ static debugserver_error_t debugserver_client_receive_internal_char(debugserver_client_t client, char* received_char)
379
+ {
380
+ debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
381
+ uint32_t bytes = 0;
382
+
383
+ /* we loop here as we expect an answer */
384
+ res = debugserver_client_receive(client, received_char, sizeof(char), &bytes);
385
+ if (res != DEBUGSERVER_E_SUCCESS) {
386
+ return res;
387
+ }
388
+ if (bytes != 1) {
389
+ debug_info("received %d bytes when asking for %d!", bytes, sizeof(char));
390
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
391
+ }
392
+ return res;
393
+ }
394
+
395
+ debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
396
+ {
397
+ debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
398
+
399
+ char data = '\0';
400
+ int skip_prefix = 0;
401
+
402
+ char* buffer = malloc(1024);
403
+ uint32_t buffer_size = 0;
404
+ uint32_t buffer_capacity = 1024;
405
+
406
+ if (response)
407
+ *response = NULL;
408
+
409
+ if (!client->noack_mode) {
410
+ debug_info("attempting to receive ACK (+)");
411
+ res = debugserver_client_receive_internal_char(client, &data);
412
+ if (res != DEBUGSERVER_E_SUCCESS) {
413
+ goto cleanup;
414
+ }
415
+ if (data == '+') {
416
+ debug_info("received ACK (+)");
417
+ } else if (data == '$') {
418
+ debug_info("received prefix ($)");
419
+ buffer[0] = '$';
420
+ buffer_size = 1;
421
+ skip_prefix = 1;
422
+ } else {
423
+ debug_info("unrecognized response when looking for ACK: %c", data);
424
+ goto cleanup;
425
+ }
426
+ }
427
+
428
+ debug_info("skip_prefix: %d", skip_prefix);
429
+
430
+ if (!skip_prefix) {
431
+ debug_info("attempting to receive prefix ($)");
432
+ res = debugserver_client_receive_internal_char(client, &data);
433
+ if (res != DEBUGSERVER_E_SUCCESS) {
434
+ goto cleanup;
435
+ }
436
+ if (data == '$') {
437
+ debug_info("received prefix ($)");
438
+ buffer[0] = '$';
439
+ buffer_size = 1;
440
+ } else {
441
+ debug_info("unrecognized response when looking for prefix: %c", data);
442
+ goto cleanup;
443
+ }
444
+ }
445
+
446
+ uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
447
+ int receiving_checksum_response = 0;
448
+ debug_info("attempting to read up response until checksum");
449
+
450
+ while ((checksum_length > 0)) {
451
+ res = debugserver_client_receive_internal_char(client, &data);
452
+ if (res != DEBUGSERVER_E_SUCCESS) {
453
+ goto cleanup;
454
+ }
455
+ if (data == '#') {
456
+ receiving_checksum_response = 1;
457
+ }
458
+ if (receiving_checksum_response) {
459
+ checksum_length--;
460
+ }
461
+ if (buffer_size + 1 >= buffer_capacity) {
462
+ char* newbuffer = realloc(buffer, buffer_capacity+1024);
463
+ if (!newbuffer) {
464
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
465
+ }
466
+ buffer = newbuffer;
467
+ buffer_capacity += 1024;
468
+ }
469
+ buffer[buffer_size] = data;
470
+ buffer_size += sizeof(char);
471
+ }
472
+ debug_info("validating response checksum...");
473
+ if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) {
474
+ if (response) {
475
+ /* assemble response string */
476
+ uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
477
+ *response = (char*)malloc(resp_size + 1);
478
+ memcpy(*response, buffer + 1, resp_size);
479
+ (*response)[resp_size] = '\0';
480
+ if (response_size) *response_size = resp_size;
481
+ }
482
+ if (!client->noack_mode) {
483
+ /* confirm valid command */
484
+ debugserver_client_send_ack(client);
485
+ }
486
+ } else {
487
+ /* response was invalid */
488
+ res = DEBUGSERVER_E_RESPONSE_ERROR;
489
+ if (!client->noack_mode) {
490
+ /* report invalid command */
491
+ debugserver_client_send_noack(client);
492
+ }
493
+ }
494
+
495
+ cleanup:
496
+ if (response) {
497
+ debug_info("response: %s", *response);
498
+ }
499
+
500
+ if (buffer)
501
+ free(buffer);
502
+
503
+ return res;
504
+ }
505
+
506
+ debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
507
+ {
508
+ debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
509
+ int i;
510
+ uint32_t bytes = 0;
511
+
512
+ char* send_buffer = NULL;
513
+ uint32_t send_buffer_size = 0;
514
+
515
+ char* command_arguments = NULL;
516
+
517
+ /* concat all arguments */
518
+ for (i = 0; i < command->argc; i++) {
519
+ debug_info("argv[%d]: %s", i, command->argv[i]);
520
+ command_arguments = string_append(command_arguments, command->argv[i], NULL);
521
+ }
522
+
523
+ debug_info("command_arguments(%d): %s", command->argc, command_arguments);
524
+
525
+ /* encode command arguments, add checksum if required and assemble entire command */
526
+ debugserver_format_command("$", command->name, command_arguments, 1, &send_buffer, &send_buffer_size);
527
+
528
+ debug_info("sending encoded command: %s", send_buffer);
529
+
530
+ res = debugserver_client_send(client, send_buffer, send_buffer_size, &bytes);
531
+ debug_info("command result: %d", res);
532
+ if (res != DEBUGSERVER_E_SUCCESS) {
533
+ goto cleanup;
534
+ }
535
+
536
+ /* receive response */
537
+ res = debugserver_client_receive_response(client, response, response_size);
538
+ debug_info("response result: %d", res);
539
+ if (res != DEBUGSERVER_E_SUCCESS) {
540
+ goto cleanup;
541
+ }
542
+
543
+ if (response) {
544
+ debug_info("received response: %s", *response);
545
+ }
546
+
547
+ /* disable sending ack on the client */
548
+ if (!strncmp(command->name, "QStartNoAckMode", 16)) {
549
+ debugserver_client_set_ack_mode(client, 0);
550
+ }
551
+
552
+ cleanup:
553
+ if (command_arguments)
554
+ free(command_arguments);
555
+
556
+ if (send_buffer)
557
+ free(send_buffer);
558
+
559
+ return res;
560
+ }
561
+
562
+ debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
563
+ {
564
+ if (!client || !env)
565
+ return DEBUGSERVER_E_INVALID_ARG;
566
+
567
+ debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
568
+ char* env_tmp = strdup(env);
569
+ char* env_arg[2] = { env_tmp, NULL };
570
+
571
+ debugserver_command_t command = NULL;
572
+ debugserver_command_new("QEnvironmentHexEncoded:", 1, env_arg, &command);
573
+ result = debugserver_client_send_command(client, command, response, NULL);
574
+ debugserver_command_free(command);
575
+
576
+ free(env_tmp);
577
+
578
+ return result;
579
+ }
580
+
581
+ debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
582
+ {
583
+ if (!client || !argc)
584
+ return DEBUGSERVER_E_INVALID_ARG;
585
+
586
+ debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
587
+ char *pkt = NULL;
588
+ size_t pkt_len = 0;
589
+ int i = 0;
590
+
591
+ /* calculate total length */
592
+ while (i < argc && argv && argv[i]) {
593
+ char *prefix = NULL;
594
+ int ret = asprintf(&prefix, ",%zu,%d,", strlen(argv[i]) * 2, i);
595
+ if (ret < 0 || prefix == NULL) {
596
+ debug_info("asprintf failed, out of memory?");
597
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
598
+ }
599
+ pkt_len += strlen(prefix) + strlen(argv[i]) * 2;
600
+ free(prefix);
601
+ i++;
602
+ }
603
+
604
+ /* allocate packet and initialize it */
605
+ pkt = (char *) malloc(pkt_len + 1);
606
+ memset(pkt, 0, pkt_len + 1);
607
+
608
+ char *pktp = pkt;
609
+
610
+ i = 0;
611
+ while (i < argc && argv && argv[i]) {
612
+ debug_info("argv[%d] = \"%s\"", i, argv[i]);
613
+
614
+ char *prefix = NULL;
615
+ char *m = NULL;
616
+ size_t arg_len = strlen(argv[i]);
617
+ size_t arg_hexlen = arg_len * 2;
618
+
619
+ int ret = asprintf(&prefix, ",%zu,%d,", arg_hexlen, i);
620
+ if (ret < 0 || prefix == NULL) {
621
+ debug_info("asprintf failed, out of memory?");
622
+ return DEBUGSERVER_E_UNKNOWN_ERROR;
623
+ }
624
+
625
+ m = (char *) malloc(arg_hexlen);
626
+ char *p = m;
627
+ char *q = (char*)argv[i];
628
+ while (*q) {
629
+ *p++ = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(*q);
630
+ *p++ = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(*q);
631
+ q++;
632
+ }
633
+
634
+ memcpy(pktp, prefix, strlen(prefix));
635
+ pktp += strlen(prefix);
636
+
637
+ memcpy(pktp, m, arg_hexlen);
638
+ pktp += arg_hexlen;
639
+
640
+ free(prefix);
641
+ free(m);
642
+
643
+ i++;
644
+ }
645
+
646
+ pkt[0] = 'A';
647
+
648
+ debugserver_command_t command = NULL;
649
+ debugserver_command_new(pkt, 0, NULL, &command);
650
+ result = debugserver_client_send_command(client, command, response, NULL);
651
+ debugserver_command_free(command);
652
+
653
+ if (pkt)
654
+ free(pkt);
655
+
656
+ return result;
657
+ }
debugserver.h ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * debugserver.h
3
+ * com.apple.debugserver service header file.
4
+ *
5
+ * Copyright (c) 2014 Martin Szulecki 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
+ #ifndef _DEBUGSERVER_H
23
+ #define _DEBUGSERVER_H
24
+
25
+ #include "idevice.h"
26
+ #include "libimobiledevice/debugserver.h"
27
+ #include "service.h"
28
+
29
+ #define DEBUGSERVER_CHECKSUM_HASH_LENGTH 0x3
30
+
31
+ struct debugserver_client_private {
32
+ service_client_t parent;
33
+ int noack_mode;
34
+ int (*cancel_receive)();
35
+ int receive_loop_timeout;
36
+ };
37
+
38
+ struct debugserver_command_private {
39
+ char* name;
40
+ int argc;
41
+ char** argv;
42
+ };
43
+
44
+ #endif
debugserver.pxi ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from "libimobiledevice/debugserver.h":
2
+ cdef struct debugserver_client_private:
3
+ pass
4
+ ctypedef debugserver_client_private *debugserver_client_t
5
+ cdef struct debugserver_command_private:
6
+ pass
7
+ ctypedef debugserver_command_private *debugserver_command_t
8
+ ctypedef enum debugserver_error_t:
9
+ DEBUGSERVER_E_SUCCESS = 0
10
+ DEBUGSERVER_E_INVALID_ARG = -1
11
+ DEBUGSERVER_E_MUX_ERROR = -2
12
+ DEBUGSERVER_E_SSL_ERROR = -3
13
+ DEBUGSERVER_E_RESPONSE_ERROR = -4
14
+ DEBUGSERVER_E_UNKNOWN_ERROR = -256
15
+
16
+ debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client)
17
+ debugserver_error_t debugserver_client_free(debugserver_client_t client)
18
+
19
+ debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
20
+ debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
21
+ debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received)
22
+ debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout)
23
+ debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
24
+ debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
25
+ debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
26
+
27
+ debugserver_error_t debugserver_command_new(const char* name, int argc, const char* argv[], debugserver_command_t* command)
28
+ debugserver_error_t debugserver_command_free(debugserver_command_t command)
29
+ void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
30
+ void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
31
+
32
+
33
+ cdef class DebugServerError(BaseError):
34
+ def __init__(self, *args, **kwargs):
35
+ self._lookup_table = {
36
+ DEBUGSERVER_E_SUCCESS: "Success",
37
+ DEBUGSERVER_E_INVALID_ARG: "Invalid argument",
38
+ DEBUGSERVER_E_MUX_ERROR: "MUX error",
39
+ DEBUGSERVER_E_SSL_ERROR: "SSL error",
40
+ DEBUGSERVER_E_RESPONSE_ERROR: "Response error",
41
+ DEBUGSERVER_E_UNKNOWN_ERROR: "Unknown error",
42
+ }
43
+ BaseError.__init__(self, *args, **kwargs)
44
+
45
+
46
+ from cpython.bytes cimport PyBytes_AsString as PyString_AsString
47
+ cdef char ** to_cstring_array(list_str):
48
+ if not list_str:
49
+ return NULL
50
+ cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
51
+ for i in xrange(len(list_str)):
52
+ ret[i] = PyString_AsString(list_str[i])
53
+ return ret
54
+
55
+
56
+ cdef class DebugServerCommand(Base):
57
+ cdef debugserver_command_t _c_command
58
+
59
+ def __init__(self, bytes name, int argc = 0, argv = None, *args, **kwargs):
60
+ cdef:
61
+ char* c_name = name
62
+ char** c_argv = to_cstring_array(argv)
63
+
64
+ try:
65
+ self.handle_error(debugserver_command_new(c_name, argc, c_argv, &self._c_command))
66
+ except BaseError, e:
67
+ raise
68
+ finally:
69
+ free(c_argv)
70
+
71
+ def __enter__(self):
72
+ return self
73
+
74
+ def __exit__(self, type, value, traceback):
75
+ self.free()
76
+
77
+ cdef free(self):
78
+ cdef debugserver_error_t err
79
+ if self._c_command is not NULL:
80
+ err = debugserver_command_free(self._c_command)
81
+ self.handle_error(err)
82
+
83
+ cdef inline BaseError _error(self, int16_t ret):
84
+ return DebugServerError(ret)
85
+
86
+
87
+ cdef class DebugServerClient(BaseService):
88
+ __service_name__ = "com.apple.debugserver"
89
+ cdef debugserver_client_t _c_client
90
+
91
+ def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs):
92
+ if (device is not None and descriptor is not None):
93
+ self.handle_error(debugserver_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client)))
94
+
95
+ def __dealloc__(self):
96
+ cdef debugserver_error_t err
97
+ if self._c_client is not NULL:
98
+ err = debugserver_client_free(self._c_client)
99
+ self.handle_error(err)
100
+
101
+ cdef BaseError _error(self, int16_t ret):
102
+ return DebugServerError(ret)
103
+
104
+ cpdef uint32_t send(self, bytes data):
105
+ cdef:
106
+ uint32_t bytes_send
107
+ char* c_data = data
108
+ try:
109
+ self.handle_error(debugserver_client_send(self._c_client, c_data, len(data), &bytes_send))
110
+ except BaseError, e:
111
+ raise
112
+
113
+ return bytes_send
114
+
115
+ cpdef bytes send_command(self, DebugServerCommand command):
116
+ cdef:
117
+ char* c_response = NULL
118
+ bytes result
119
+
120
+ try:
121
+ self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response, NULL))
122
+ if c_response:
123
+ result = c_response
124
+ return result
125
+ else:
126
+ return None
127
+ except BaseError, e:
128
+ raise
129
+ finally:
130
+ free(c_response)
131
+
132
+ cpdef bytes receive(self, uint32_t size):
133
+ cdef:
134
+ uint32_t bytes_received
135
+ char* c_data = <char *>malloc(size)
136
+ bytes result
137
+
138
+ try:
139
+ self.handle_error(debugserver_client_receive(self._c_client, c_data, size, &bytes_received))
140
+ result = c_data[:bytes_received]
141
+ return result
142
+ except BaseError, e:
143
+ raise
144
+ finally:
145
+ free(c_data)
146
+
147
+ cpdef bytes receive_with_timeout(self, uint32_t size, unsigned int timeout):
148
+ cdef:
149
+ uint32_t bytes_received
150
+ char* c_data = <char *>malloc(size)
151
+ bytes result
152
+
153
+ try:
154
+ self.handle_error(debugserver_client_receive_with_timeout(self._c_client, c_data, size, &bytes_received, timeout))
155
+ result = c_data[:bytes_received]
156
+ return result
157
+ except BaseError, e:
158
+ raise
159
+ finally:
160
+ free(c_data)
161
+
162
+ cpdef bytes receive_response(self):
163
+ cdef:
164
+ char* c_response = NULL
165
+ bytes result
166
+
167
+ try:
168
+ self.handle_error(debugserver_client_receive_response(self._c_client, &c_response, NULL))
169
+ if c_response:
170
+ result = c_response
171
+ return result
172
+ else:
173
+ return None
174
+ except BaseError, e:
175
+ raise
176
+ finally:
177
+ free(c_response)
178
+
179
+ cpdef bytes set_argv(self, int argc, argv):
180
+ cdef:
181
+ char** c_argv = to_cstring_array(argv)
182
+ char* c_response = NULL
183
+ bytes result
184
+
185
+ try:
186
+ self.handle_error(debugserver_client_set_argv(self._c_client, argc, c_argv, &c_response))
187
+ if c_response:
188
+ result = c_response
189
+ return result
190
+ else:
191
+ return None
192
+ except BaseError, e:
193
+ raise
194
+ finally:
195
+ free(c_argv)
196
+ free(c_response)
197
+
198
+ cpdef bytes set_environment_hex_encoded(self, bytes env):
199
+ cdef:
200
+ char* c_env = env
201
+ char* c_response = NULL
202
+ bytes result
203
+
204
+ try:
205
+ self.handle_error(debugserver_client_set_environment_hex_encoded(self._c_client, c_env, &c_response))
206
+ if c_response:
207
+ result = c_response
208
+ return result
209
+ else:
210
+ return None
211
+ except BaseError, e:
212
+ raise
213
+ finally:
214
+ free(c_response)
215
+
216
+ cpdef bytes encode_string(self, bytes buffer):
217
+ cdef:
218
+ char *c_buffer = buffer
219
+ uint32_t encoded_length = len(c_buffer) * 2 + 0x3 + 1
220
+ char* c_encoded_buffer = <char *>malloc(encoded_length)
221
+ bytes result
222
+
223
+ try:
224
+ debugserver_encode_string(c_buffer, &c_encoded_buffer, &encoded_length)
225
+ result = c_encoded_buffer[:encoded_length]
226
+ return result
227
+ except BaseError, e:
228
+ raise
229
+ finally:
230
+ free(c_encoded_buffer)
231
+
232
+ cpdef bytes decode_string(self, bytes encoded_buffer):
233
+ cdef:
234
+ char* c_encoded_buffer = encoded_buffer
235
+ uint32_t encoded_length = len(c_encoded_buffer)
236
+ char *c_buffer = <char *>malloc(encoded_length)
237
+ bytes result
238
+
239
+ try:
240
+ debugserver_decode_string(c_encoded_buffer, encoded_length, &c_buffer)
241
+ result = c_buffer
242
+ return result
243
+ except BaseError, e:
244
+ raise
245
+ finally:
246
+ free(c_buffer)
device_link_service.c ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * device_link_service.c
3
+ * DeviceLink service implementation.
4
+ *
5
+ * Copyright (c) 2010-2019 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
+ #include <string.h>
26
+ #include <stdlib.h>
27
+ #include "device_link_service.h"
28
+ #include "property_list_service.h"
29
+ #include "common/debug.h"
30
+
31
+ static device_link_service_error_t device_link_error(property_list_service_error_t err)
32
+ {
33
+ switch (err) {
34
+ case PROPERTY_LIST_SERVICE_E_SUCCESS:
35
+ return DEVICE_LINK_SERVICE_E_SUCCESS;
36
+ case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
37
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
38
+ case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
39
+ return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
40
+ case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
41
+ return DEVICE_LINK_SERVICE_E_MUX_ERROR;
42
+ case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
43
+ return DEVICE_LINK_SERVICE_E_SSL_ERROR;
44
+ case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
45
+ return DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT;
46
+ default:
47
+ break;
48
+ }
49
+ return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
50
+ }
51
+
52
+ /**
53
+ * Internally used function to extract the message string from a DL* message
54
+ * plist.
55
+ *
56
+ * @param dl_msg The DeviceLink property list to parse.
57
+ * @param message A pointer that will be set to a newly allocated char*
58
+ * containing the DLMessage* string from the given plist. It is up to
59
+ * the caller to free the allocated memory. If this parameter is NULL
60
+ * it will be ignored.
61
+ *
62
+ * @return 1 if the given plist is a DL* message, or 0 if the plist does not
63
+ * contain any DL* message.
64
+ */
65
+ static int device_link_service_get_message(plist_t dl_msg, char **message)
66
+ {
67
+ plist_t cmd = NULL;
68
+ char *cmd_str = NULL;
69
+
70
+ /* sanity check */
71
+ if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || (plist_array_get_size(dl_msg) < 1)) {
72
+ return 0;
73
+ }
74
+
75
+ /* get dl command */
76
+ cmd = plist_array_get_item(dl_msg, 0);
77
+ if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) {
78
+ return 0;
79
+ }
80
+
81
+ plist_get_string_val(cmd, &cmd_str);
82
+ if (!cmd_str) {
83
+ return 0;
84
+ }
85
+
86
+ if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2) != 0)) {
87
+ free(cmd_str);
88
+ return 0;
89
+ }
90
+
91
+ if (message)
92
+ *message = cmd_str;
93
+
94
+ /* we got a DL* message */
95
+ return 1;
96
+ }
97
+
98
+ /**
99
+ * Creates a new device link service client.
100
+ *
101
+ * @param device The device to connect to.
102
+ * @param service The service descriptor returned by lockdownd_start_service.
103
+ * @param client Reference that will point to a newly allocated
104
+ * device_link_service_client_t upon successful return.
105
+ *
106
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
107
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid,
108
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed.
109
+ */
110
+ device_link_service_error_t device_link_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, device_link_service_client_t *client)
111
+ {
112
+ if (!device || !service || service->port == 0 || !client || *client) {
113
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
114
+ }
115
+
116
+ property_list_service_client_t plistclient = NULL;
117
+ device_link_service_error_t err = device_link_error(property_list_service_client_new(device, service, &plistclient));
118
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
119
+ return err;
120
+ }
121
+
122
+ /* create client object */
123
+ device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_private));
124
+ client_loc->parent = plistclient;
125
+
126
+ /* all done, return success */
127
+ *client = client_loc;
128
+ return DEVICE_LINK_SERVICE_E_SUCCESS;
129
+ }
130
+
131
+ /**
132
+ * Frees a device link service client.
133
+ *
134
+ * @param client The device_link_service_client_t to free.
135
+ *
136
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
137
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent
138
+ * is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error
139
+ * freeing the parent property_list_service client.
140
+ */
141
+ device_link_service_error_t device_link_service_client_free(device_link_service_client_t client)
142
+ {
143
+ if (!client)
144
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
145
+
146
+ device_link_service_error_t err = device_link_error(property_list_service_client_free(client->parent));
147
+ free(client);
148
+
149
+ return err;
150
+ }
151
+
152
+ /**
153
+ * Performs the DLMessageVersionExchange with the connected device.
154
+ * This should be the first operation to be executed by an implemented
155
+ * device link service client.
156
+ *
157
+ * @param client The device_link_service client to use.
158
+ * @param version_major The major version number to check.
159
+ * @param version_minor The minor version number to check.
160
+ *
161
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
162
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL,
163
+ * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs,
164
+ * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the
165
+ * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version
166
+ * given by the device is larger than the given version,
167
+ * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise.
168
+ */
169
+ device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor)
170
+ {
171
+ if (!client)
172
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
173
+
174
+ device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
175
+
176
+ /* perform version exchange */
177
+ plist_t array = NULL;
178
+ char *msg = NULL;
179
+
180
+ /* receive DLMessageVersionExchange from device */
181
+ err = device_link_error(property_list_service_receive_plist(client->parent, &array));
182
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
183
+ debug_info("Did not receive initial message from device!");
184
+ goto leave;
185
+ }
186
+ device_link_service_get_message(array, &msg);
187
+ if (!msg || strcmp(msg, "DLMessageVersionExchange") != 0) {
188
+ debug_info("Did not receive DLMessageVersionExchange from device!");
189
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
190
+ goto leave;
191
+ }
192
+ free(msg);
193
+ msg = NULL;
194
+
195
+ /* get major and minor version number */
196
+ if (plist_array_get_size(array) < 3) {
197
+ debug_info("DLMessageVersionExchange has unexpected format!");
198
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
199
+ goto leave;
200
+ }
201
+ plist_t maj = plist_array_get_item(array, 1);
202
+ plist_t min = plist_array_get_item(array, 2);
203
+ uint64_t vmajor = 0;
204
+ uint64_t vminor = 0;
205
+ if (maj) {
206
+ plist_get_uint_val(maj, &vmajor);
207
+ }
208
+ if (min) {
209
+ plist_get_uint_val(min, &vminor);
210
+ }
211
+ if (vmajor > version_major) {
212
+ debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
213
+ err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
214
+ goto leave;
215
+ } else if ((vmajor == version_major) && (vminor > version_minor)) {
216
+ debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
217
+ err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
218
+ goto leave;
219
+ }
220
+ plist_free(array);
221
+
222
+ /* version is ok, send reply */
223
+ array = plist_new_array();
224
+ plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
225
+ plist_array_append_item(array, plist_new_string("DLVersionsOk"));
226
+ plist_array_append_item(array, plist_new_uint(version_major));
227
+ err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
228
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
229
+ debug_info("Error when sending DLVersionsOk");
230
+ goto leave;
231
+ }
232
+ plist_free(array);
233
+
234
+ /* receive DeviceReady message */
235
+ array = NULL;
236
+ err = device_link_error(property_list_service_receive_plist(client->parent, &array));
237
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
238
+ debug_info("Error when receiving DLMessageDeviceReady!");
239
+ goto leave;
240
+ }
241
+ device_link_service_get_message(array, &msg);
242
+ if (!msg || strcmp(msg, "DLMessageDeviceReady") != 0) {
243
+ debug_info("Did not get DLMessageDeviceReady!");
244
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
245
+ goto leave;
246
+ }
247
+ err = DEVICE_LINK_SERVICE_E_SUCCESS;
248
+
249
+ leave:
250
+ if (msg) {
251
+ free(msg);
252
+ }
253
+ if (array) {
254
+ plist_free(array);
255
+ }
256
+ return err;
257
+ }
258
+
259
+ /**
260
+ * Performs a disconnect with the connected device link service client.
261
+ *
262
+ * @param client The device link service client to disconnect.
263
+ * @param message Optional message to send send to the device or NULL.
264
+ *
265
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
266
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL,
267
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending
268
+ * the the disconnect message.
269
+ */
270
+ device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client, const char *message)
271
+ {
272
+ if (!client)
273
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
274
+
275
+ plist_t array = plist_new_array();
276
+ plist_array_append_item(array, plist_new_string("DLMessageDisconnect"));
277
+ if (message)
278
+ plist_array_append_item(array, plist_new_string(message));
279
+ else
280
+ plist_array_append_item(array, plist_new_string("___EmptyParameterString___"));
281
+
282
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
283
+ plist_free(array);
284
+
285
+ return err;
286
+ }
287
+
288
+ /**
289
+ * Sends a DLMessagePing plist.
290
+ *
291
+ * @param client The device link service client to use.
292
+ * @param message String to send as ping message.
293
+ *
294
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
295
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid,
296
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR if the DLMessagePing plist could
297
+ * not be sent.
298
+ */
299
+ device_link_service_error_t device_link_service_send_ping(device_link_service_client_t client, const char *message)
300
+ {
301
+ if (!client || !client->parent || !message)
302
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
303
+
304
+ plist_t array = plist_new_array();
305
+ plist_array_append_item(array, plist_new_string("DLMessagePing"));
306
+ plist_array_append_item(array, plist_new_string(message));
307
+
308
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
309
+ plist_free(array);
310
+
311
+ return err;
312
+ }
313
+
314
+ /**
315
+ * Sends a DLMessageProcessMessage plist.
316
+ *
317
+ * @param client The device link service client to use.
318
+ * @param message PLIST_DICT to send.
319
+ *
320
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
321
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid or
322
+ * message is not a PLIST_DICT, or DEVICE_LINK_SERVICE_E_MUX_ERROR if
323
+ * the DLMessageProcessMessage plist could not be sent.
324
+ */
325
+ device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message)
326
+ {
327
+ if (!client || !client->parent || !message)
328
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
329
+
330
+ if (plist_get_node_type(message) != PLIST_DICT)
331
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
332
+
333
+ plist_t array = plist_new_array();
334
+ plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
335
+ plist_array_append_item(array, plist_copy(message));
336
+
337
+ device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
338
+ plist_free(array);
339
+
340
+ return err;
341
+ }
342
+
343
+ /**
344
+ * Receives a DL* message plist
345
+ *
346
+ * @param client The connected device link service client used for receiving.
347
+ * @param msg_plist Pointer to a plist that will be set to the contents of the
348
+ * message plist upon successful return.
349
+ * @param dlmessage A pointer that will be set to a newly allocated char*
350
+ * containing the DL* string from the given plist. It is up to the caller
351
+ * to free the allocated memory. If this parameter is NULL
352
+ * it will be ignored.
353
+ *
354
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS if a DL* message was received,
355
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid,
356
+ * DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is invalid
357
+ * or is not a DL* message plist, or DEVICE_LINK_SERVICE_E_MUX_ERROR if
358
+ * receiving from the device failed.
359
+ */
360
+ device_link_service_error_t device_link_service_receive_message(device_link_service_client_t client, plist_t *msg_plist, char **dlmessage)
361
+ {
362
+ if (!client || !client->parent || !msg_plist)
363
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
364
+
365
+ *msg_plist = NULL;
366
+ device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, msg_plist));
367
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
368
+ return err;
369
+ }
370
+
371
+ if (!device_link_service_get_message(*msg_plist, dlmessage)) {
372
+ debug_info("Did not receive a DL* message as expected!");
373
+ return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
374
+ }
375
+ return DEVICE_LINK_SERVICE_E_SUCCESS;
376
+ }
377
+
378
+ /**
379
+ * Receives a DLMessageProcessMessage plist.
380
+ *
381
+ * @param client The connected device link service client used for receiving.
382
+ * @param message Pointer to a plist that will be set to the contents of the
383
+ * message contents upon successful return.
384
+ *
385
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS when a DLMessageProcessMessage was
386
+ * received, DEVICE_LINK_SERVICE_E_INVALID_ARG when client or message is
387
+ * invalid, DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is
388
+ * invalid or is not a DLMessageProcessMessage,
389
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR if receiving from device fails.
390
+ */
391
+ device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message)
392
+ {
393
+ if (!client || !client->parent || !message)
394
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
395
+
396
+ plist_t pmsg = NULL;
397
+ device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, &pmsg));
398
+ if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
399
+ return err;
400
+ }
401
+
402
+ err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
403
+
404
+ char *msg = NULL;
405
+ device_link_service_get_message(pmsg, &msg);
406
+ if (!msg || strcmp(msg, "DLMessageProcessMessage") != 0) {
407
+ debug_info("Did not receive DLMessageProcessMessage as expected!");
408
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
409
+ goto leave;
410
+ }
411
+
412
+ if (plist_array_get_size(pmsg) != 2) {
413
+ debug_info("Malformed plist received for DLMessageProcessMessage");
414
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
415
+ goto leave;
416
+ }
417
+
418
+ plist_t msg_loc = plist_array_get_item(pmsg, 1);
419
+ if (msg_loc) {
420
+ *message = plist_copy(msg_loc);
421
+ err = DEVICE_LINK_SERVICE_E_SUCCESS;
422
+ } else {
423
+ *message = NULL;
424
+ err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
425
+ }
426
+
427
+ leave:
428
+ if (msg)
429
+ free(msg);
430
+ if (pmsg)
431
+ plist_free(pmsg);
432
+
433
+ return err;
434
+ }
435
+
436
+ /**
437
+ * Generic device link service send function.
438
+ *
439
+ * @param client The device link service client to use for sending
440
+ * @param plist The property list to send
441
+ *
442
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
443
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
444
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could
445
+ * not be sent.
446
+ */
447
+ device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist)
448
+ {
449
+ if (!client || !plist) {
450
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
451
+ }
452
+ return device_link_error(property_list_service_send_binary_plist(client->parent, plist));
453
+ }
454
+
455
+ /* Generic device link service receive function.
456
+ *
457
+ * @param client The device link service client to use for sending
458
+ * @param plist Pointer that will point to the property list received upon
459
+ * successful return.
460
+ *
461
+ * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
462
+ * DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
463
+ * or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be
464
+ * received.
465
+ */
466
+ device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist)
467
+ {
468
+ if (!client || !plist || (plist && *plist)) {
469
+ return DEVICE_LINK_SERVICE_E_INVALID_ARG;
470
+ }
471
+
472
+ return device_link_error(property_list_service_receive_plist(client->parent, plist));
473
+ }
474
+
device_link_service.h ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * device_link_service.h
3
+ * Definitions for the DeviceLink service
4
+ *
5
+ * Copyright (c) 2010-2019 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
+ #ifndef __DEVICE_LINK_SERVICE_H
23
+ #define __DEVICE_LINK_SERVICE_H
24
+
25
+ #include "idevice.h"
26
+ #include "property_list_service.h"
27
+
28
+ /* Error Codes */
29
+ typedef enum {
30
+ DEVICE_LINK_SERVICE_E_SUCCESS = 0,
31
+ DEVICE_LINK_SERVICE_E_INVALID_ARG = -1,
32
+ DEVICE_LINK_SERVICE_E_PLIST_ERROR = -2,
33
+ DEVICE_LINK_SERVICE_E_MUX_ERROR = -3,
34
+ DEVICE_LINK_SERVICE_E_SSL_ERROR = -4,
35
+ DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT = -5,
36
+ DEVICE_LINK_SERVICE_E_BAD_VERSION = -6,
37
+ DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR = -256
38
+ } device_link_service_error_t;
39
+
40
+ struct device_link_service_client_private {
41
+ property_list_service_client_t parent;
42
+ };
43
+
44
+ typedef struct device_link_service_client_private *device_link_service_client_t;
45
+
46
+ device_link_service_error_t device_link_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, device_link_service_client_t *client);
47
+ device_link_service_error_t device_link_service_client_free(device_link_service_client_t client);
48
+ device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor);
49
+ device_link_service_error_t device_link_service_send_ping(device_link_service_client_t client, const char *message);
50
+ device_link_service_error_t device_link_service_receive_message(device_link_service_client_t client, plist_t *msg_plist, char **dlmessage);
51
+ device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message);
52
+ device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message);
53
+ device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client, const char *message);
54
+ device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist);
55
+ device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist);
56
+
57
+ #endif
dfu.c ADDED
@@ -0,0 +1,470 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * dfu.c
3
+ * Functions for handling idevices in DFU mode
4
+ *
5
+ * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
6
+ * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #include <stdio.h>
25
+ #include <stdlib.h>
26
+ #include <string.h>
27
+ #include <unistd.h>
28
+ #include <libirecovery.h>
29
+
30
+ #include "dfu.h"
31
+ #include "tss.h"
32
+ #include "recovery.h"
33
+ #include "idevicerestore.h"
34
+ #include "common.h"
35
+
36
+ static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) {
37
+ if (event->type == IRECV_PROGRESS) {
38
+ print_progress_bar(event->progress);
39
+ }
40
+ return 0;
41
+ }
42
+
43
+ int dfu_client_new(struct idevicerestore_client_t* client) {
44
+ int i = 0;
45
+ int attempts = 10;
46
+ irecv_client_t dfu = NULL;
47
+
48
+ if (client->dfu == NULL) {
49
+ client->dfu = (struct dfu_client_t*)malloc(sizeof(struct dfu_client_t));
50
+ memset(client->dfu, 0, sizeof(struct dfu_client_t));
51
+ if (client->dfu == NULL) {
52
+ error("ERROR: Out of memory\n");
53
+ return -1;
54
+ }
55
+ }
56
+
57
+ for (i = 1; i <= attempts; i++) {
58
+ if (irecv_open_with_ecid(&dfu, client->ecid) == IRECV_E_SUCCESS) {
59
+ break;
60
+ }
61
+
62
+ if (i >= attempts) {
63
+ error("ERROR: Unable to connect to device in DFU mode\n");
64
+ return -1;
65
+ }
66
+
67
+ sleep(1);
68
+ debug("Retrying connection...\n");
69
+ }
70
+
71
+ irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL);
72
+ client->dfu->client = dfu;
73
+ return 0;
74
+ }
75
+
76
+ void dfu_client_free(struct idevicerestore_client_t* client) {
77
+ if(client != NULL) {
78
+ if (client->dfu != NULL) {
79
+ if(client->dfu->client != NULL) {
80
+ irecv_close(client->dfu->client);
81
+ client->dfu->client = NULL;
82
+ }
83
+ free(client->dfu);
84
+ }
85
+ client->dfu = NULL;
86
+ }
87
+ }
88
+
89
+ int dfu_check_mode(struct idevicerestore_client_t* client, int* mode) {
90
+ irecv_client_t dfu = NULL;
91
+ int probe_mode = -1;
92
+
93
+ if (client->udid && client->ecid == 0) {
94
+ /* if we have a UDID but no ECID we can't make sure this is the correct device */
95
+ return -1;
96
+ }
97
+
98
+ irecv_init();
99
+ if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
100
+ return -1;
101
+ }
102
+
103
+ irecv_get_mode(dfu, &probe_mode);
104
+
105
+ if ((probe_mode != IRECV_K_DFU_MODE) && (probe_mode != IRECV_K_WTF_MODE)) {
106
+ irecv_close(dfu);
107
+ return -1;
108
+ }
109
+
110
+ *mode = (probe_mode == IRECV_K_WTF_MODE) ? MODE_WTF : MODE_DFU;
111
+
112
+ irecv_close(dfu);
113
+
114
+ return 0;
115
+ }
116
+
117
+ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) {
118
+ irecv_client_t dfu = NULL;
119
+ irecv_error_t dfu_error = IRECV_E_SUCCESS;
120
+ irecv_device_t device = NULL;
121
+
122
+ irecv_init();
123
+ if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
124
+ return NULL;
125
+ }
126
+
127
+ dfu_error = irecv_devices_get_device_by_client(dfu, &device);
128
+ irecv_close(dfu);
129
+ if (dfu_error != IRECV_E_SUCCESS) {
130
+ return NULL;
131
+ }
132
+
133
+ return device;
134
+ }
135
+
136
+ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size)
137
+ {
138
+ irecv_error_t err = 0;
139
+
140
+ info("Sending data (%d bytes)...\n", size);
141
+
142
+ err = irecv_send_buffer(client->dfu->client, buffer, size, 1);
143
+ if (err != IRECV_E_SUCCESS) {
144
+ error("ERROR: Unable to send data: %s\n", irecv_strerror(err));
145
+ return -1;
146
+ }
147
+
148
+ return 0;
149
+ }
150
+
151
+ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) {
152
+ char* path = NULL;
153
+
154
+ if (client->tss) {
155
+ if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
156
+ debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component);
157
+ }
158
+ }
159
+ if (!path) {
160
+ if (build_identity_get_component_path(build_identity, component, &path) < 0) {
161
+ error("ERROR: Unable to get path for component '%s'\n", component);
162
+ free(path);
163
+ return -1;
164
+ }
165
+ }
166
+
167
+ unsigned char* component_data = NULL;
168
+ unsigned int component_size = 0;
169
+
170
+ if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
171
+ error("ERROR: Unable to extract component: %s\n", component);
172
+ free(path);
173
+ return -1;
174
+ }
175
+ free(path);
176
+ path = NULL;
177
+
178
+ unsigned char* data = NULL;
179
+ uint32_t size = 0;
180
+
181
+ if (personalize_component(component, component_data, component_size, client->tss, &data, &size) < 0) {
182
+ error("ERROR: Unable to get personalized component: %s\n", component);
183
+ free(component_data);
184
+ return -1;
185
+ }
186
+ free(component_data);
187
+ component_data = NULL;
188
+
189
+ if (!client->image4supported && client->build_major > 8 && !(client->flags & FLAG_CUSTOM) && !strcmp(component, "iBEC")) {
190
+ unsigned char* ticket = NULL;
191
+ unsigned int tsize = 0;
192
+ if (tss_response_get_ap_ticket(client->tss, &ticket, &tsize) < 0) {
193
+ error("ERROR: Unable to get ApTicket from TSS request\n");
194
+ return -1;
195
+ }
196
+ uint32_t fillsize = 0;
197
+ if (tsize % 64 != 0) {
198
+ fillsize = ((tsize / 64) + 1) * 64;
199
+ }
200
+ debug("ticket size = %d\nfillsize = %d\n", tsize, fillsize);
201
+ unsigned char* newdata = (unsigned char*)malloc(size + fillsize);
202
+ memcpy(newdata, ticket, tsize);
203
+ memset(newdata + tsize, '\xFF', fillsize - tsize);
204
+ memcpy(newdata + fillsize, data, size);
205
+ free(data);
206
+ data = newdata;
207
+ size += fillsize;
208
+ }
209
+
210
+ info("Sending %s (%d bytes)...\n", component, size);
211
+
212
+ // FIXME: Did I do this right????
213
+ irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1);
214
+ if (err != IRECV_E_SUCCESS) {
215
+ error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err));
216
+ free(data);
217
+ return -1;
218
+ }
219
+
220
+ free(data);
221
+ return 0;
222
+ }
223
+
224
+ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) {
225
+ if(client->dfu == NULL) {
226
+ if (dfu_client_new(client) < 0) {
227
+ return -1;
228
+ }
229
+ }
230
+
231
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
232
+ if (!device_info) {
233
+ return -1;
234
+ }
235
+
236
+ *cpid = device_info->cpid;
237
+
238
+ return 0;
239
+ }
240
+
241
+ int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) {
242
+ if(client->dfu == NULL) {
243
+ if (dfu_client_new(client) < 0) {
244
+ return -1;
245
+ }
246
+ }
247
+
248
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
249
+ if (!device_info) {
250
+ return -1;
251
+ }
252
+
253
+ *ecid = device_info->ecid;
254
+
255
+ return 0;
256
+ }
257
+
258
+ int dfu_is_image4_supported(struct idevicerestore_client_t* client)
259
+ {
260
+ if(client->dfu == NULL) {
261
+ if (dfu_client_new(client) < 0) {
262
+ return 0;
263
+ }
264
+ }
265
+
266
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
267
+ if (!device_info) {
268
+ return 0;
269
+ }
270
+
271
+ return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE);
272
+ }
273
+
274
+ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) {
275
+ if(client->dfu == NULL) {
276
+ if (dfu_client_new(client) < 0) {
277
+ return -1;
278
+ }
279
+ }
280
+
281
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
282
+ if (!device_info) {
283
+ return -1;
284
+ }
285
+
286
+ if (device_info->ap_nonce && device_info->ap_nonce_size > 0) {
287
+ *nonce = (unsigned char*)malloc(device_info->ap_nonce_size);
288
+ if (!*nonce) {
289
+ return -1;
290
+ }
291
+ *nonce_size = device_info->ap_nonce_size;
292
+ memcpy(*nonce, device_info->ap_nonce, *nonce_size);
293
+ }
294
+
295
+ return 0;
296
+ }
297
+
298
+ int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) {
299
+ if(client->dfu == NULL) {
300
+ if (dfu_client_new(client) < 0) {
301
+ return -1;
302
+ }
303
+ }
304
+
305
+ const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
306
+ if (!device_info) {
307
+ return -1;
308
+ }
309
+
310
+ if (device_info->sep_nonce && device_info->sep_nonce_size > 0) {
311
+ *nonce = (unsigned char*)malloc(device_info->sep_nonce_size);
312
+ if (!*nonce) {
313
+ return -1;
314
+ }
315
+ *nonce_size = device_info->sep_nonce_size;
316
+ memcpy(*nonce, device_info->sep_nonce, *nonce_size);
317
+ }
318
+
319
+ return 0;
320
+ }
321
+
322
+ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity)
323
+ {
324
+ int mode = 0;
325
+
326
+ if (dfu_client_new(client) < 0) {
327
+ error("ERROR: Unable to connect to DFU device\n");
328
+ return -1;
329
+ }
330
+
331
+ irecv_get_mode(client->dfu->client, &mode);
332
+
333
+ if (mode != IRECV_K_DFU_MODE) {
334
+ info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
335
+ client->mode = &idevicerestore_modes[MODE_RECOVERY];
336
+ return 0;
337
+ }
338
+
339
+ mutex_lock(&client->device_event_mutex);
340
+
341
+ if (dfu_send_component(client, build_identity, "iBSS") < 0) {
342
+ error("ERROR: Unable to send iBSS to device\n");
343
+ irecv_close(client->dfu->client);
344
+ client->dfu->client = NULL;
345
+ return -1;
346
+ }
347
+ dfu_client_free(client);
348
+
349
+ if (client->build_major > 8) {
350
+ /* reconnect */
351
+ debug("Waiting for device to disconnect...\n");
352
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
353
+ if (client->mode != &idevicerestore_modes[MODE_UNKNOWN] || (client->flags & FLAG_QUIT)) {
354
+ mutex_unlock(&client->device_event_mutex);
355
+ if (!(client->flags & FLAG_QUIT)) {
356
+ error("ERROR: Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n");
357
+ }
358
+ return -1;
359
+ }
360
+ debug("Waiting for device to reconnect...\n");
361
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
362
+ if ((client->mode != &idevicerestore_modes[MODE_DFU] && client->mode != &idevicerestore_modes[MODE_RECOVERY]) || (client->flags & FLAG_QUIT)) {
363
+ mutex_unlock(&client->device_event_mutex);
364
+ if (!(client->flags & FLAG_QUIT)) {
365
+ error("ERROR: Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n");
366
+ }
367
+ return -1;
368
+ }
369
+ mutex_unlock(&client->device_event_mutex);
370
+ dfu_client_new(client);
371
+
372
+ /* get nonce */
373
+ unsigned char* nonce = NULL;
374
+ int nonce_size = 0;
375
+ int nonce_changed = 0;
376
+ if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) {
377
+ error("ERROR: Unable to get ApNonce from device!\n");
378
+ return -1;
379
+ }
380
+
381
+ if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
382
+ nonce_changed = 1;
383
+ if (client->nonce) {
384
+ free(client->nonce);
385
+ }
386
+ client->nonce = nonce;
387
+ client->nonce_size = nonce_size;
388
+ } else {
389
+ free(nonce);
390
+ }
391
+
392
+ info("Nonce: ");
393
+ int i;
394
+ for (i = 0; i < client->nonce_size; i++) {
395
+ info("%02x ", client->nonce[i]);
396
+ }
397
+ info("\n");
398
+
399
+ if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
400
+ // Welcome iOS5. We have to re-request the TSS with our nonce.
401
+ plist_free(client->tss);
402
+ if (get_tss_response(client, build_identity, &client->tss) < 0) {
403
+ error("ERROR: Unable to get SHSH blobs for this device\n");
404
+ return -1;
405
+ }
406
+ if (!client->tss) {
407
+ error("ERROR: can't continue without TSS\n");
408
+ return -1;
409
+ }
410
+ fixup_tss(client->tss);
411
+ }
412
+
413
+ if (irecv_usb_set_configuration(client->dfu->client, 1) < 0) {
414
+ error("ERROR: set configuration failed\n");
415
+ }
416
+
417
+ mutex_lock(&client->device_event_mutex);
418
+
419
+ /* send iBEC */
420
+ if (dfu_send_component(client, build_identity, "iBEC") < 0) {
421
+ mutex_unlock(&client->device_event_mutex);
422
+ error("ERROR: Unable to send iBEC to device\n");
423
+ irecv_close(client->dfu->client);
424
+ client->dfu->client = NULL;
425
+ return -1;
426
+ }
427
+
428
+ if (client->mode == &idevicerestore_modes[MODE_RECOVERY]) {
429
+ if (irecv_send_command(client->dfu->client, "go") != IRECV_E_SUCCESS) {
430
+ mutex_unlock(&client->device_event_mutex);
431
+ error("ERROR: Unable to execute iBEC\n");
432
+ return -1;
433
+ }
434
+ irecv_usb_control_transfer(client->dfu->client, 0x21, 1, 0, 0, 0, 0, 5000);
435
+ }
436
+ dfu_client_free(client);
437
+ }
438
+
439
+ debug("Waiting for device to disconnect...\n");
440
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
441
+ if (client->mode != &idevicerestore_modes[MODE_UNKNOWN] || (client->flags & FLAG_QUIT)) {
442
+ mutex_unlock(&client->device_event_mutex);
443
+ if (!(client->flags & FLAG_QUIT)) {
444
+ error("ERROR: Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
445
+ }
446
+ return -1;
447
+ }
448
+ debug("Waiting for device to reconnect in recovery mode...\n");
449
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
450
+ if (client->mode != &idevicerestore_modes[MODE_RECOVERY] || (client->flags & FLAG_QUIT)) {
451
+ mutex_unlock(&client->device_event_mutex);
452
+ if (!(client->flags & FLAG_QUIT)) {
453
+ error("ERROR: Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
454
+ }
455
+ return -1;
456
+ }
457
+ mutex_unlock(&client->device_event_mutex);
458
+
459
+ if (recovery_client_new(client) < 0) {
460
+ error("ERROR: Unable to connect to recovery device\n");
461
+ if (client->recovery->client) {
462
+ irecv_close(client->recovery->client);
463
+ client->recovery->client = NULL;
464
+ }
465
+ return -1;
466
+ }
467
+
468
+ return 0;
469
+ }
470
+
dfu.h ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * dfu.h
3
+ * Functions for handling idevices in DFU mode
4
+ *
5
+ * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved.
6
+ * Copyright (c) 2012-2015 Nikias Bassen. All Rights Reserved.
7
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #ifndef IDEVICERESTORE_DFU_H
25
+ #define IDEVICERESTORE_DFU_H
26
+
27
+ #ifdef __cplusplus
28
+ extern "C" {
29
+ #endif
30
+
31
+ #include <libirecovery.h>
32
+ #include "common.h"
33
+
34
+ struct dfu_client_t {
35
+ irecv_client_t client;
36
+ const char* ipsw;
37
+ plist_t tss;
38
+ };
39
+
40
+ int dfu_client_new(struct idevicerestore_client_t* client);
41
+ void dfu_client_free(struct idevicerestore_client_t* client);
42
+ int dfu_check_mode(struct idevicerestore_client_t* client, int* mode);
43
+ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client);
44
+ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size);
45
+ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);
46
+ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid);
47
+ int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
48
+ int dfu_is_image4_supported(struct idevicerestore_client_t* client);
49
+ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
50
+ int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
51
+ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity);
52
+
53
+
54
+ #ifdef __cplusplus
55
+ }
56
+ #endif
57
+
58
+ #endif
diagnostics_relay.c ADDED
@@ -0,0 +1,467 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * diagnostics_relay.c
3
+ * com.apple.mobile.diagnostics_relay service implementation.
4
+ *
5
+ * Copyright (c) 2012 Martin Szulecki, 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
+ #include <string.h>
26
+ #include <stdlib.h>
27
+ #include "diagnostics_relay.h"
28
+ #include "property_list_service.h"
29
+ #include "common/debug.h"
30
+
31
+ #define RESULT_SUCCESS 0
32
+ #define RESULT_FAILURE 1
33
+ #define RESULT_UNKNOWN_REQUEST 2
34
+
35
+ /**
36
+ * Internally used function for checking the result from a service response
37
+ * plist to a previously sent request.
38
+ *
39
+ * @param dict The plist to evaluate.
40
+ *
41
+ * @return RESULT_SUCCESS when the result is 'Success',
42
+ * RESULT_FAILURE when the result is 'Failure',
43
+ * or a negative value if an error occurred during evaluation.
44
+ */
45
+ static int diagnostics_relay_check_result(plist_t dict)
46
+ {
47
+ int ret = -1;
48
+
49
+ plist_t result_node = plist_dict_get_item(dict, "Status");
50
+ if (!result_node)
51
+ return ret;
52
+
53
+ plist_type result_type = plist_get_node_type(result_node);
54
+ if (result_type == PLIST_STRING) {
55
+ char *result_value = NULL;
56
+
57
+ plist_get_string_val(result_node, &result_value);
58
+
59
+ if (result_value) {
60
+ if (!strcmp(result_value, "Success")) {
61
+ ret = RESULT_SUCCESS;
62
+ } else if (!strcmp(result_value, "Failure")) {
63
+ ret = RESULT_FAILURE;
64
+ } else if (!strcmp(result_value, "UnknownRequest")) {
65
+ ret = RESULT_UNKNOWN_REQUEST;
66
+ } else {
67
+ debug_info("ERROR: unknown result value '%s'", result_value);
68
+ }
69
+ }
70
+ if (result_value)
71
+ free(result_value);
72
+ }
73
+ return ret;
74
+ }
75
+
76
+ diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client)
77
+ {
78
+ if (!device || !service || service->port == 0 || !client || *client) {
79
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
80
+ }
81
+
82
+ property_list_service_client_t plistclient = NULL;
83
+ if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
84
+ return DIAGNOSTICS_RELAY_E_MUX_ERROR;
85
+ }
86
+
87
+ /* create client object */
88
+ diagnostics_relay_client_t client_loc = (diagnostics_relay_client_t) malloc(sizeof(struct diagnostics_relay_client_private));
89
+ client_loc->parent = plistclient;
90
+
91
+ /* all done, return success */
92
+ *client = client_loc;
93
+ return DIAGNOSTICS_RELAY_E_SUCCESS;
94
+ }
95
+
96
+ diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label)
97
+ {
98
+ diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
99
+ service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err);
100
+ return err;
101
+ }
102
+
103
+ diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
104
+ {
105
+ if (!client)
106
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
107
+
108
+ if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
109
+ return DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
110
+ }
111
+ free(client);
112
+ return DIAGNOSTICS_RELAY_E_SUCCESS;
113
+ }
114
+
115
+ /**
116
+ * Receives a plist from the service.
117
+ *
118
+ * @param client The diagnostics_relay client
119
+ * @param plist The plist to store the received data
120
+ *
121
+ * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
122
+ * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
123
+ */
124
+ static diagnostics_relay_error_t diagnostics_relay_receive(diagnostics_relay_client_t client, plist_t *plist)
125
+ {
126
+ if (!client || !plist || (plist && *plist))
127
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
128
+
129
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
130
+ property_list_service_error_t err;
131
+
132
+ err = property_list_service_receive_plist(client->parent, plist);
133
+ if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
134
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
135
+ }
136
+
137
+ if (!*plist)
138
+ ret = DIAGNOSTICS_RELAY_E_PLIST_ERROR;
139
+
140
+ return ret;
141
+ }
142
+
143
+ /**
144
+ * Sends a plist to the service.
145
+ *
146
+ * @note This function is low-level and should only be used if you need to send
147
+ * a new type of message.
148
+ *
149
+ * @param client The diagnostics_relay client
150
+ * @param plist The plist to send
151
+ *
152
+ * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
153
+ * DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
154
+ */
155
+ static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client_t client, plist_t plist)
156
+ {
157
+ if (!client || !plist)
158
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
159
+
160
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
161
+ property_list_service_error_t err;
162
+
163
+ err = property_list_service_send_xml_plist(client->parent, plist);
164
+ if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
165
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
166
+ }
167
+ return ret;
168
+ }
169
+
170
+ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
171
+ {
172
+ if (!client)
173
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
174
+
175
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
176
+
177
+ plist_t dict = plist_new_dict();
178
+ plist_dict_set_item(dict, "Request", plist_new_string("Goodbye"));
179
+
180
+ ret = diagnostics_relay_send(client, dict);
181
+ plist_free(dict);
182
+ dict = NULL;
183
+
184
+ ret = diagnostics_relay_receive(client, &dict);
185
+ if (!dict) {
186
+ debug_info("did not get goodbye response back");
187
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
188
+ }
189
+
190
+ int check = diagnostics_relay_check_result(dict);
191
+ if (check == RESULT_SUCCESS) {
192
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
193
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
194
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
195
+ } else {
196
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
197
+ }
198
+
199
+ plist_free(dict);
200
+ dict = NULL;
201
+ return ret;
202
+ }
203
+
204
+ diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
205
+ {
206
+ if (!client)
207
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
208
+
209
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
210
+
211
+ plist_t dict = plist_new_dict();
212
+
213
+ plist_dict_set_item(dict,"Request", plist_new_string("Sleep"));
214
+ ret = diagnostics_relay_send(client, dict);
215
+ plist_free(dict);
216
+ dict = NULL;
217
+
218
+ ret = diagnostics_relay_receive(client, &dict);
219
+ if (!dict) {
220
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
221
+ }
222
+
223
+ int check = diagnostics_relay_check_result(dict);
224
+ if (check == RESULT_SUCCESS) {
225
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
226
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
227
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
228
+ } else {
229
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
230
+ }
231
+
232
+ plist_free(dict);
233
+ return ret;
234
+ }
235
+
236
+ static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, diagnostics_relay_action_t flags)
237
+ {
238
+ if (!client)
239
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
240
+
241
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
242
+
243
+ plist_t dict = plist_new_dict();
244
+ plist_dict_set_item(dict,"Request", plist_new_string(name));
245
+
246
+ if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) {
247
+ plist_dict_set_item(dict, "WaitForDisconnect", plist_new_bool(1));
248
+ }
249
+
250
+ if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) {
251
+ plist_dict_set_item(dict, "DisplayPass", plist_new_bool(1));
252
+ }
253
+
254
+ if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) {
255
+ plist_dict_set_item(dict, "DisplayFail", plist_new_bool(1));
256
+ }
257
+
258
+ ret = diagnostics_relay_send(client, dict);
259
+ plist_free(dict);
260
+ dict = NULL;
261
+
262
+ ret = diagnostics_relay_receive(client, &dict);
263
+ if (!dict) {
264
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
265
+ }
266
+
267
+ int check = diagnostics_relay_check_result(dict);
268
+ if (check == RESULT_SUCCESS) {
269
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
270
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
271
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
272
+ } else {
273
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
274
+ }
275
+
276
+ plist_free(dict);
277
+ return ret;
278
+ }
279
+
280
+ diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
281
+ {
282
+ return internal_diagnostics_relay_action(client, "Restart", flags);
283
+ }
284
+
285
+ diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
286
+ {
287
+ return internal_diagnostics_relay_action(client, "Shutdown", flags);
288
+ }
289
+
290
+ diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
291
+ {
292
+ if (!client || diagnostics == NULL)
293
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
294
+
295
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
296
+
297
+ plist_t dict = plist_new_dict();
298
+ plist_dict_set_item(dict,"Request", plist_new_string(type));
299
+ ret = diagnostics_relay_send(client, dict);
300
+ plist_free(dict);
301
+ dict = NULL;
302
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
303
+ return ret;
304
+ }
305
+
306
+ ret = diagnostics_relay_receive(client, &dict);
307
+ if (!dict) {
308
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
309
+ }
310
+
311
+ int check = diagnostics_relay_check_result(dict);
312
+ if (check == RESULT_SUCCESS) {
313
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
314
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
315
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
316
+ } else {
317
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
318
+ }
319
+
320
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
321
+ plist_free(dict);
322
+ return ret;
323
+ }
324
+
325
+ plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
326
+ if (value_node) {
327
+ *diagnostics = plist_copy(value_node);
328
+ }
329
+
330
+ plist_free(dict);
331
+ return ret;
332
+ }
333
+
334
+ diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
335
+ {
336
+ if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL)
337
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
338
+
339
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
340
+
341
+ plist_t dict = plist_new_dict();
342
+ plist_dict_set_item(dict,"MobileGestaltKeys", plist_copy(keys));
343
+ plist_dict_set_item(dict,"Request", plist_new_string("MobileGestalt"));
344
+ ret = diagnostics_relay_send(client, dict);
345
+ plist_free(dict);
346
+ dict = NULL;
347
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
348
+ return ret;
349
+ }
350
+
351
+ ret = diagnostics_relay_receive(client, &dict);
352
+ if (!dict) {
353
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
354
+ }
355
+
356
+ int check = diagnostics_relay_check_result(dict);
357
+ if (check == RESULT_SUCCESS) {
358
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
359
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
360
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
361
+ } else {
362
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
363
+ }
364
+
365
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
366
+ plist_free(dict);
367
+ return ret;
368
+ }
369
+
370
+ plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
371
+ if (value_node) {
372
+ *result = plist_copy(value_node);
373
+ }
374
+
375
+ plist_free(dict);
376
+ return ret;
377
+ }
378
+
379
+ diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result)
380
+ {
381
+ if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL)
382
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
383
+
384
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
385
+
386
+ plist_t dict = plist_new_dict();
387
+ if (entry_name)
388
+ plist_dict_set_item(dict,"EntryName", plist_new_string(entry_name));
389
+ if (entry_class)
390
+ plist_dict_set_item(dict,"EntryClass", plist_new_string(entry_class));
391
+ plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
392
+ ret = diagnostics_relay_send(client, dict);
393
+ plist_free(dict);
394
+ dict = NULL;
395
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
396
+ return ret;
397
+ }
398
+
399
+ ret = diagnostics_relay_receive(client, &dict);
400
+ if (!dict) {
401
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
402
+ }
403
+
404
+ int check = diagnostics_relay_check_result(dict);
405
+ if (check == RESULT_SUCCESS) {
406
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
407
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
408
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
409
+ } else {
410
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
411
+ }
412
+
413
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
414
+ plist_free(dict);
415
+ return ret;
416
+ }
417
+
418
+ plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
419
+ if (value_node) {
420
+ *result = plist_copy(value_node);
421
+ }
422
+
423
+ plist_free(dict);
424
+ return ret;
425
+ }
426
+
427
+ diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
428
+ {
429
+ if (!client || plane == NULL || result == NULL)
430
+ return DIAGNOSTICS_RELAY_E_INVALID_ARG;
431
+
432
+ diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
433
+
434
+ plist_t dict = plist_new_dict();
435
+ plist_dict_set_item(dict,"CurrentPlane", plist_new_string(plane));
436
+ plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
437
+ ret = diagnostics_relay_send(client, dict);
438
+ plist_free(dict);
439
+ dict = NULL;
440
+
441
+ ret = diagnostics_relay_receive(client, &dict);
442
+ if (!dict) {
443
+ return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
444
+ }
445
+
446
+ int check = diagnostics_relay_check_result(dict);
447
+ if (check == RESULT_SUCCESS) {
448
+ ret = DIAGNOSTICS_RELAY_E_SUCCESS;
449
+ } else if (check == RESULT_UNKNOWN_REQUEST) {
450
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
451
+ } else {
452
+ ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
453
+ }
454
+
455
+ if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
456
+ plist_free(dict);
457
+ return ret;
458
+ }
459
+
460
+ plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
461
+ if (value_node) {
462
+ *result = plist_copy(value_node);
463
+ }
464
+
465
+ plist_free(dict);
466
+ return ret;
467
+ }
diagnostics_relay.h ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * diagnostics_relay.h
3
+ * com.apple.mobile.diagnostics_relay service header file.
4
+ *
5
+ * Copyright (c) 2012 Martin Szulecki, 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
+ #ifndef __DIAGNOSTICS_RELAY_H
23
+ #define __DIAGNOSTICS_RELAY_H
24
+
25
+ #include "idevice.h"
26
+ #include "libimobiledevice/diagnostics_relay.h"
27
+ #include "property_list_service.h"
28
+
29
+ struct diagnostics_relay_client_private {
30
+ property_list_service_client_t parent;
31
+ };
32
+
33
+ #endif
diagnostics_relay.pxi ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ REQUEST_TYPE_ALL = "All"
2
+ REQUEST_TYPE_WIFI = "WiFi"
3
+ REQUEST_TYPE_GAS_GAUGE = "GasGauge"
4
+ REQUEST_TYPE_NAND = "NAND"
5
+
6
+ cdef extern from "libimobiledevice/diagnostics_relay.h":
7
+ cdef struct diagnostics_relay_client_private:
8
+ pass
9
+ ctypedef diagnostics_relay_client_private *diagnostics_relay_client_t
10
+
11
+ ctypedef enum diagnostics_relay_error_t:
12
+ DIAGNOSTICS_RELAY_E_SUCCESS = 0
13
+ DIAGNOSTICS_RELAY_E_INVALID_ARG = -1
14
+ DIAGNOSTICS_RELAY_E_PLIST_ERROR = -2
15
+ DIAGNOSTICS_RELAY_E_MUX_ERROR = -3
16
+ DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST = -4
17
+ DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256
18
+ ctypedef enum diagnostics_relay_action_t:
19
+ DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT = (1 << 1)
20
+ DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS = (1 << 2)
21
+ DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL = (1 << 3)
22
+
23
+ diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, diagnostics_relay_client_t * client)
24
+ diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
25
+
26
+ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
27
+ diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
28
+ diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
29
+ diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
30
+ diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, char* type, plist.plist_t* diagnostics)
31
+ diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist.plist_t keys, plist.plist_t* result)
32
+ diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, char* name, char* class_name, plist.plist_t* result)
33
+ diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, char* plane, plist.plist_t* result)
34
+
35
+ cdef class DiagnosticsRelayError(BaseError):
36
+ def __init__(self, *args, **kwargs):
37
+ self._lookup_table = {
38
+ DIAGNOSTICS_RELAY_E_SUCCESS: "Success",
39
+ DIAGNOSTICS_RELAY_E_INVALID_ARG: "Invalid argument",
40
+ DIAGNOSTICS_RELAY_E_PLIST_ERROR: "Property list error",
41
+ DIAGNOSTICS_RELAY_E_MUX_ERROR: "MUX error",
42
+ DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST: "Unknown request",
43
+ DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR: "Unknown error"
44
+ }
45
+ BaseError.__init__(self, *args, **kwargs)
46
+
47
+ cdef class DiagnosticsRelayClient(PropertyListService):
48
+ __service_name__ = "com.apple.mobile.diagnostics_relay"
49
+ cdef diagnostics_relay_client_t _c_client
50
+
51
+ def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs):
52
+ self.handle_error(diagnostics_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client))
53
+
54
+ def __dealloc__(self):
55
+ cdef diagnostics_relay_error_t err
56
+ if self._c_client is not NULL:
57
+ err = diagnostics_relay_client_free(self._c_client)
58
+ self.handle_error(err)
59
+
60
+ cdef inline BaseError _error(self, int16_t ret):
61
+ return DiagnosticsRelayError(ret)
62
+
63
+ cpdef goodbye(self):
64
+ self.handle_error(diagnostics_relay_goodbye(self._c_client))
65
+
66
+ cpdef sleep(self):
67
+ self.handle_error(diagnostics_relay_sleep(self._c_client))
68
+
69
+ cpdef restart(self, diagnostics_relay_action_t flags):
70
+ self.handle_error(diagnostics_relay_restart(self._c_client, flags))
71
+
72
+ cpdef shutdown(self, diagnostics_relay_action_t flags):
73
+ self.handle_error(diagnostics_relay_shutdown(self._c_client, flags))
74
+
75
+ cpdef plist.Node request_diagnostics(self, bytes type):
76
+ cdef:
77
+ plist.plist_t c_node = NULL
78
+ diagnostics_relay_error_t err
79
+ err = diagnostics_relay_request_diagnostics(self._c_client, type, &c_node)
80
+ try:
81
+ self.handle_error(err)
82
+ return plist.plist_t_to_node(c_node)
83
+ except BaseError, e:
84
+ if c_node != NULL:
85
+ plist.plist_free(c_node)
86
+ raise
87
+
88
+ cpdef plist.Node query_mobilegestalt(self, plist.Node keys = None):
89
+ cdef:
90
+ plist.plist_t c_node = NULL
91
+ diagnostics_relay_error_t err
92
+ plist.plist_t keys_c_node = NULL
93
+ if keys is not None:
94
+ keys_c_node = keys._c_node
95
+ err = diagnostics_relay_query_mobilegestalt(self._c_client, keys_c_node, &c_node)
96
+ try:
97
+ self.handle_error(err)
98
+ return plist.plist_t_to_node(c_node)
99
+ except BaseError, e:
100
+ if c_node != NULL:
101
+ plist.plist_free(c_node)
102
+ raise
103
+
104
+ cpdef plist.Node query_ioregistry_entry(self, bytes name, bytes class_name):
105
+ cdef:
106
+ plist.plist_t c_node = NULL
107
+ diagnostics_relay_error_t err
108
+ err = diagnostics_relay_query_ioregistry_entry(self._c_client, name, class_name, &c_node)
109
+ try:
110
+ self.handle_error(err)
111
+ return plist.plist_t_to_node(c_node)
112
+ except BaseError, e:
113
+ if c_node != NULL:
114
+ plist.plist_free(c_node)
115
+ raise
116
+
117
+ cpdef plist.Node query_ioregistry_plane(self, bytes plane = None):
118
+ cdef:
119
+ plist.plist_t c_node = NULL
120
+ diagnostics_relay_error_t err
121
+ err = diagnostics_relay_query_ioregistry_plane(self._c_client, plane, &c_node)
122
+ try:
123
+ self.handle_error(err)
124
+ return plist.plist_t_to_node(c_node)
125
+ except BaseError, e:
126
+ if c_node != NULL:
127
+ plist.plist_free(c_node)
128
+ raise
download.c ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * download.c
3
+ * file download helper functions
4
+ *
5
+ * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
6
+ * Copyright (c) 2012-2013 Martin Szulecki. All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+ #include <stdint.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+ #include <curl/curl.h>
26
+
27
+ #include "download.h"
28
+ #include "common.h"
29
+
30
+ typedef struct {
31
+ int length;
32
+ char* content;
33
+ } curl_response;
34
+
35
+ static size_t download_write_buffer_callback(char* data, size_t size, size_t nmemb, curl_response* response) {
36
+ size_t total = size * nmemb;
37
+ if (total != 0) {
38
+ response->content = realloc(response->content, response->length + total + 1);
39
+ memcpy(response->content + response->length, data, total);
40
+ response->content[response->length + total] = '\0';
41
+ response->length += total;
42
+ }
43
+ return total;
44
+ }
45
+
46
+ int download_to_buffer(const char* url, char** buf, uint32_t* length)
47
+ {
48
+ int res = 0;
49
+ CURL* handle = curl_easy_init();
50
+ if (handle == NULL) {
51
+ error("ERROR: could not initialize CURL\n");
52
+ return -1;
53
+ }
54
+
55
+ curl_response response;
56
+ response.length = 0;
57
+ response.content = malloc(1);
58
+ response.content[0] = '\0';
59
+
60
+ if (idevicerestore_debug)
61
+ curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
62
+
63
+ /* disable SSL verification to allow download from untrusted https locations */
64
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
65
+
66
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&download_write_buffer_callback);
67
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
68
+ if (strncmp(url, "https://api.ipsw.me/", 20) == 0) {
69
+ curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING " idevicerestore/" PACKAGE_VERSION);
70
+ } else {
71
+ curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
72
+ }
73
+ curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
74
+ curl_easy_setopt(handle, CURLOPT_URL, url);
75
+
76
+ curl_easy_perform(handle);
77
+ curl_easy_cleanup(handle);
78
+
79
+ if (response.length > 0) {
80
+ *length = response.length;
81
+ *buf = response.content;
82
+ } else {
83
+ res = -1;
84
+ }
85
+
86
+ return res;
87
+ }
88
+
89
+ static int lastprogress = 0;
90
+
91
+ static int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
92
+ {
93
+ double p = (dlnow / dltotal) * 100;
94
+
95
+ if (p < 100.0) {
96
+ if ((int)p > lastprogress) {
97
+ info("downloading: %d%%\n", (int)p);
98
+ lastprogress = (int)p;
99
+ }
100
+ }
101
+
102
+ return 0;
103
+ }
104
+
105
+ int download_to_file(const char* url, const char* filename, int enable_progress)
106
+ {
107
+ int res = 0;
108
+ CURL* handle = curl_easy_init();
109
+ if (handle == NULL) {
110
+ error("ERROR: could not initialize CURL\n");
111
+ return -1;
112
+ }
113
+
114
+ FILE* f = fopen(filename, "wb");
115
+ if (!f) {
116
+ error("ERROR: cannot open '%s' for writing\n", filename);
117
+ return -1;
118
+ }
119
+
120
+ lastprogress = 0;
121
+
122
+ if (idevicerestore_debug)
123
+ curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
124
+
125
+ /* disable SSL verification to allow download from untrusted https locations */
126
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
127
+
128
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
129
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, f);
130
+
131
+ if (enable_progress > 0)
132
+ curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress);
133
+
134
+ curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1);
135
+ curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
136
+ curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
137
+ curl_easy_setopt(handle, CURLOPT_URL, url);
138
+
139
+ curl_easy_perform(handle);
140
+ curl_easy_cleanup(handle);
141
+
142
+ #ifdef WIN32
143
+ fflush(f);
144
+ uint64_t sz = _lseeki64(fileno(f), 0, SEEK_CUR);
145
+ #else
146
+ off_t sz = ftello(f);
147
+ #endif
148
+ fclose(f);
149
+
150
+ if ((sz == 0) || ((int64_t)sz == (int64_t)-1)) {
151
+ res = -1;
152
+ remove(filename);
153
+ }
154
+
155
+ return res;
156
+ }
download.h ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * download.h
3
+ * file download helper functions (header file)
4
+ *
5
+ * Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
6
+ * Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+ #ifndef IDEVICERESTORE_DOWNLOAD_H
23
+ #define IDEVICERESTORE_DOWNLOAD_H
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ #include <stdint.h>
30
+
31
+ int download_to_buffer(const char* url, char** buf, uint32_t* length);
32
+ int download_to_file(const char* url, const char* filename, int enable_progress);
33
+
34
+ #ifdef __cplusplus
35
+ }
36
+ #endif
37
+
38
+ #endif
doxygen.cfg.in ADDED
The diff for this file is too large to render. See raw diff
 
endianness.h ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef ENDIANNESS_H
2
+ #define ENDIANNESS_H
3
+
4
+ #ifndef __LITTLE_ENDIAN
5
+ #define __LITTLE_ENDIAN 1234
6
+ #endif
7
+
8
+ #ifndef __BIG_ENDIAN
9
+ #define __BIG_ENDIAN 4321
10
+ #endif
11
+
12
+ #ifndef __BYTE_ORDER
13
+ #ifdef __LITTLE_ENDIAN__
14
+ #define __BYTE_ORDER __LITTLE_ENDIAN
15
+ #else
16
+ #ifdef __BIG_ENDIAN__
17
+ #define __BYTE_ORDER __BIG_ENDIAN
18
+ #endif
19
+ #endif
20
+ #endif
21
+
22
+ #ifndef be16toh
23
+ #if __BYTE_ORDER == __BIG_ENDIAN
24
+ #define be16toh(x) (x)
25
+ #else
26
+ #define be16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
27
+ #endif
28
+ #endif
29
+
30
+ #ifndef htobe16
31
+ #define htobe16 be16toh
32
+ #endif
33
+
34
+ #ifndef le16toh
35
+ #if __BYTE_ORDER == __BIG_ENDIAN
36
+ #define le16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
37
+ #else
38
+ #define le16toh(x) (x)
39
+ #endif
40
+ #endif
41
+
42
+ #ifndef htole16
43
+ #define htole16 le16toh
44
+ #endif
45
+
46
+ #ifndef __bswap_32
47
+ #define __bswap_32(x) ((((x) & 0xFF000000) >> 24) \
48
+ | (((x) & 0x00FF0000) >> 8) \
49
+ | (((x) & 0x0000FF00) << 8) \
50
+ | (((x) & 0x000000FF) << 24))
51
+ #endif
52
+
53
+ #ifndef be32toh
54
+ #if __BYTE_ORDER == __BIG_ENDIAN
55
+ #define be32toh(x) (x)
56
+ #else
57
+ #define be32toh(x) __bswap_32(x)
58
+ #endif
59
+ #endif
60
+
61
+ #ifndef htobe32
62
+ #define htobe32 be32toh
63
+ #endif
64
+
65
+ #ifndef le32toh
66
+ #if __BYTE_ORDER == __BIG_ENDIAN
67
+ #define le32toh(x) __bswap_32(x)
68
+ #else
69
+ #define le32toh(x) (x)
70
+ #endif
71
+ #endif
72
+
73
+ #ifndef htole32
74
+ #define htole32 le32toh
75
+ #endif
76
+
77
+ #ifndef __bswap_64
78
+ #define __bswap_64(x) ((((x) & 0xFF00000000000000ull) >> 56) \
79
+ | (((x) & 0x00FF000000000000ull) >> 40) \
80
+ | (((x) & 0x0000FF0000000000ull) >> 24) \
81
+ | (((x) & 0x000000FF00000000ull) >> 8) \
82
+ | (((x) & 0x00000000FF000000ull) << 8) \
83
+ | (((x) & 0x0000000000FF0000ull) << 24) \
84
+ | (((x) & 0x000000000000FF00ull) << 40) \
85
+ | (((x) & 0x00000000000000FFull) << 56))
86
+ #endif
87
+
88
+ #ifndef htobe64
89
+ #if __BYTE_ORDER == __BIG_ENDIAN
90
+ #define htobe64(x) (x)
91
+ #else
92
+ #define htobe64(x) __bswap_64(x)
93
+ #endif
94
+ #endif
95
+
96
+ #ifndef be64toh
97
+ #define be64toh htobe64
98
+ #endif
99
+
100
+ #ifndef le64toh
101
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
102
+ #define le64toh(x) (x)
103
+ #else
104
+ #define le64toh(x) __bswap_64(x)
105
+ #endif
106
+ #endif
107
+
108
+ #ifndef htole64
109
+ #define htole64 le64toh
110
+ #endif
111
+
112
+ #if (defined(__BIG_ENDIAN__) \
113
+ && !defined(__FLOAT_WORD_ORDER__)) \
114
+ || (defined(__FLOAT_WORD_ORDER__) \
115
+ && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
116
+ #define float_bswap64(x) __bswap_64(x)
117
+ #define float_bswap32(x) __bswap_32(x)
118
+ #else
119
+ #define float_bswap64(x) (x)
120
+ #define float_bswap32(x) (x)
121
+ #endif
122
+
123
+ #endif /* ENDIANNESS_H */
fdr.c ADDED
@@ -0,0 +1,629 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * fdr.c
3
+ * Connection proxy service used by FDR
4
+ *
5
+ * Copyright (c) 2014 BALATON Zoltan. 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
+ #include <sys/types.h>
23
+ #include <sys/stat.h>
24
+ #include <errno.h>
25
+ #include <fcntl.h>
26
+ #include <stdio.h>
27
+ #include <stdlib.h>
28
+ #include <string.h>
29
+ #include <unistd.h>
30
+ #include <libimobiledevice/libimobiledevice.h>
31
+
32
+ #include "socket.h" /* from libimobiledevice/common */
33
+ #include "common.h"
34
+ #include "idevicerestore.h"
35
+ #include "fdr.h"
36
+ #include <endianness.h> /* from libimobiledevice */
37
+
38
+ #define CTRL_PORT 0x43a /*1082*/
39
+ #define CTRLCMD "BeginCtrl"
40
+ #define HELLOCTRLCMD "HelloCtrl"
41
+ #define HELLOCMD "HelloConn"
42
+
43
+ #define FDR_SYNC_MSG 0x1
44
+ #define FDR_PROXY_MSG 0x105
45
+ #define FDR_PLIST_MSG 0xbbaa
46
+
47
+ static uint64_t conn_port;
48
+ static int ctrlprotoversion = 2;
49
+ static int serial;
50
+
51
+ static int fdr_receive_plist(fdr_client_t fdr, plist_t* data);
52
+ static int fdr_send_plist(fdr_client_t fdr, plist_t data);
53
+ static int fdr_ctrl_handshake(fdr_client_t fdr);
54
+ static int fdr_sync_handshake(fdr_client_t fdr);
55
+ static int fdr_handle_sync_cmd(fdr_client_t fdr);
56
+ static int fdr_handle_plist_cmd(fdr_client_t fdr);
57
+ static int fdr_handle_proxy_cmd(fdr_client_t fdr);
58
+
59
+ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr)
60
+ {
61
+ int res = -1, i = 0;
62
+ int attempts = 10;
63
+ idevice_connection_t connection = NULL;
64
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
65
+ uint16_t port = (type == FDR_CONN ? conn_port : CTRL_PORT);
66
+
67
+ *fdr = NULL;
68
+
69
+ debug("Connecting to FDR client at port %u\n", port);
70
+
71
+ for (i = 1; i <= attempts; i++) {
72
+ device_error = idevice_connect(device, port, &connection);
73
+ if (device_error == IDEVICE_E_SUCCESS) {
74
+ break;
75
+ }
76
+
77
+ if (i >= attempts) {
78
+ error("ERROR: Unable to connect to FDR client (%d)\n", device_error);
79
+ return -1;
80
+ }
81
+
82
+ sleep(2);
83
+ debug("Retrying connection...\n");
84
+ }
85
+
86
+ fdr_client_t fdr_loc = calloc(1, sizeof(struct fdr_client));
87
+ if (!fdr_loc) {
88
+ error("ERROR: Unable to allocate memory\n");
89
+ return -1;
90
+ }
91
+ fdr_loc->connection = connection;
92
+ fdr_loc->device = device;
93
+ fdr_loc->type = type;
94
+
95
+ /* Do handshake */
96
+ if (type == FDR_CTRL)
97
+ res = fdr_ctrl_handshake(fdr_loc);
98
+ else if (type == FDR_CONN)
99
+ res = fdr_sync_handshake(fdr_loc);
100
+
101
+ if (res) {
102
+ fdr_free(fdr_loc);
103
+ return -1;
104
+ }
105
+
106
+ *fdr = fdr_loc;
107
+
108
+ return 0;
109
+ }
110
+
111
+ void fdr_disconnect(fdr_client_t fdr)
112
+ {
113
+ if (!fdr)
114
+ return;
115
+
116
+ if (fdr->connection) {
117
+ idevice_connection_t conn = fdr->connection;
118
+ fdr->connection = NULL;
119
+ idevice_disconnect(conn);
120
+ }
121
+ }
122
+
123
+ void fdr_free(fdr_client_t fdr)
124
+ {
125
+ if (!fdr)
126
+ return;
127
+
128
+ fdr_disconnect(fdr);
129
+
130
+ free(fdr);
131
+ fdr = NULL;
132
+ }
133
+
134
+ int fdr_poll_and_handle_message(fdr_client_t fdr)
135
+ {
136
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
137
+ uint32_t bytes = 0;
138
+ uint16_t cmd;
139
+
140
+ if (!fdr) {
141
+ error("ERROR: Invalid FDR client\n");
142
+ return -1;
143
+ }
144
+
145
+ device_error = idevice_connection_receive_timeout(fdr->connection, (char *)&cmd, sizeof(cmd), &bytes, 20000);
146
+ #ifdef HAVE_IDEVICE_E_TIMEOUT
147
+ if (device_error == IDEVICE_E_TIMEOUT || (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd)))
148
+ #else
149
+ if (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd))
150
+ #endif
151
+ {
152
+ debug("FDR %p timeout waiting for command\n", fdr);
153
+ return 0;
154
+ }
155
+ else if (device_error != IDEVICE_E_SUCCESS) {
156
+ if (fdr->connection) {
157
+ error("ERROR: Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd));
158
+ }
159
+ return -1;
160
+ }
161
+
162
+ if (cmd == FDR_SYNC_MSG) {
163
+ debug("FDR %p got sync message\n", fdr);
164
+ return fdr_handle_sync_cmd(fdr);
165
+ }
166
+
167
+ if (cmd == FDR_PROXY_MSG) {
168
+ debug("FDR %p got proxy message\n", fdr);
169
+ return fdr_handle_proxy_cmd(fdr);
170
+ }
171
+
172
+ if (cmd == FDR_PLIST_MSG) {
173
+ debug("FDR %p got plist message\n", fdr);
174
+ return fdr_handle_plist_cmd(fdr);
175
+ }
176
+
177
+ error("WARNING: FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes);
178
+ return 0;
179
+ }
180
+
181
+ void *fdr_listener_thread(void *cdata)
182
+ {
183
+ fdr_client_t fdr = cdata;
184
+ int res;
185
+
186
+ while (fdr && fdr->connection) {
187
+ debug("FDR %p waiting for message...\n", fdr);
188
+ res = fdr_poll_and_handle_message(fdr);
189
+ if (fdr->type == FDR_CTRL && res >= 0)
190
+ continue; // main thread should always retry
191
+ if (res != 0)
192
+ break;
193
+ }
194
+ debug("FDR %p terminating...\n", fdr);
195
+ fdr_free(fdr);
196
+ return (void *)(intptr_t)res;
197
+ }
198
+
199
+ static int fdr_receive_plist(fdr_client_t fdr, plist_t* data)
200
+ {
201
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
202
+ uint32_t len, bytes = 0;
203
+ char* buf = NULL;
204
+
205
+ device_error = idevice_connection_receive(fdr->connection, (char*)&len, sizeof(len), &bytes);
206
+ if (device_error != IDEVICE_E_SUCCESS) {
207
+ error("ERROR: Unable to receive packet length from FDR (%d)\n", device_error);
208
+ return -1;
209
+ }
210
+
211
+ buf = calloc(1, len);
212
+ if (!buf) {
213
+ error("ERROR: Unable to allocate memory for FDR receive buffer\n");
214
+ return -1;
215
+ }
216
+
217
+ device_error = idevice_connection_receive(fdr->connection, buf, len, &bytes);
218
+ if (device_error != IDEVICE_E_SUCCESS) {
219
+ error("ERROR: Unable to receive data from FDR\n");
220
+ free(buf);
221
+ return -1;
222
+ }
223
+ plist_from_bin(buf, bytes, data);
224
+ free(buf);
225
+
226
+ debug("FDR Received %d bytes\n", bytes);
227
+
228
+ return 0;
229
+ }
230
+
231
+ static int fdr_send_plist(fdr_client_t fdr, plist_t data)
232
+ {
233
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
234
+ char *buf = NULL;
235
+ uint32_t len = 0, bytes = 0;
236
+
237
+ if (!data)
238
+ return -1;
239
+
240
+ plist_to_bin(data, &buf, &len);
241
+ if (!buf)
242
+ return -1;
243
+
244
+ debug("FDR sending %d bytes:\n", len);
245
+ if (idevicerestore_debug)
246
+ debug_plist(data);
247
+ device_error = idevice_connection_send(fdr->connection, (char *)&len, sizeof(len), &bytes);
248
+ if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(len)) {
249
+ error("ERROR: FDR unable to send data length. (%d) Sent %u of %u bytes.\n",
250
+ device_error, bytes, (uint32_t)sizeof(len));
251
+ free(buf);
252
+ return -1;
253
+ }
254
+ device_error = idevice_connection_send(fdr->connection, buf, len, &bytes);
255
+ free(buf);
256
+ if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
257
+ error("ERROR: FDR unable to send data (%d). Sent %u of %u bytes.\n",
258
+ device_error, bytes, len);
259
+ return -1;
260
+ }
261
+
262
+ debug("FDR Sent %d bytes\n", bytes);
263
+ return 0;
264
+ }
265
+
266
+ static int fdr_ctrl_handshake(fdr_client_t fdr)
267
+ {
268
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
269
+ uint32_t bytes = 0, len = sizeof(CTRLCMD);
270
+ plist_t dict, node;
271
+ int res;
272
+
273
+ debug("About to do ctrl handshake\n");
274
+
275
+ ctrlprotoversion = 2;
276
+
277
+ device_error = idevice_connection_send(fdr->connection, CTRLCMD, len, &bytes);
278
+ if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
279
+ debug("Hmm... lookes like the device doesn't like the newer protocol, using the old one\n");
280
+ ctrlprotoversion = 1;
281
+ len = sizeof(HELLOCTRLCMD);
282
+ device_error = idevice_connection_send(fdr->connection, HELLOCTRLCMD, len, &bytes);
283
+ if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
284
+ error("ERROR: FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len);
285
+ return -1;
286
+ }
287
+ }
288
+
289
+ if (ctrlprotoversion == 2) {
290
+ dict = plist_new_dict();
291
+ plist_dict_set_item(dict, "Command", plist_new_string(CTRLCMD));
292
+ plist_dict_set_item(dict, "CtrlProtoVersion", plist_new_uint(ctrlprotoversion));
293
+ res = fdr_send_plist(fdr, dict);
294
+ plist_free(dict);
295
+ if (res) {
296
+ error("ERROR: FDR could not send Begin command.\n");
297
+ return -1;
298
+ }
299
+
300
+ if (fdr_receive_plist(fdr, &dict)) {
301
+ error("ERROR: FDR did not get Begin command reply.\n");
302
+ return -1;
303
+ }
304
+ if (idevicerestore_debug)
305
+ debug_plist(dict);
306
+ node = plist_dict_get_item(dict, "ConnPort");
307
+ if (node && plist_get_node_type(node) == PLIST_UINT) {
308
+ plist_get_uint_val(node, &conn_port);
309
+ } else {
310
+ error("ERROR: Could not get FDR ConnPort value\n");
311
+ return -1;
312
+ }
313
+
314
+ plist_free(dict);
315
+ } else {
316
+ char buf[16];
317
+ uint16_t cport = 0;
318
+
319
+ memset(buf, '\0', sizeof(buf));
320
+
321
+ bytes = 0;
322
+ device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
323
+ if (device_error != IDEVICE_E_SUCCESS) {
324
+ error("ERROR: Could not receive reply to HelloCtrl command\n");
325
+ return -1;
326
+ }
327
+ if (memcmp(buf, "HelloCtrl", 10) != 0) {
328
+ buf[9] = '\0';
329
+ error("ERROR: Did not receive HelloCtrl as reply, but %s\n", buf);
330
+ return -1;
331
+ }
332
+
333
+ bytes = 0;
334
+ device_error = idevice_connection_receive(fdr->connection, (char*)&cport, 2, &bytes);
335
+ if (device_error != IDEVICE_E_SUCCESS) {
336
+ error("ERROR: Failed to receive conn port\n");
337
+ return -1;
338
+ }
339
+
340
+ conn_port = le16toh(cport);
341
+ }
342
+
343
+ debug("Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port);
344
+
345
+ return 0;
346
+ }
347
+
348
+ static int fdr_sync_handshake(fdr_client_t fdr)
349
+ {
350
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
351
+ uint32_t bytes = 0, len = sizeof(HELLOCMD);
352
+ plist_t reply;
353
+
354
+ device_error = idevice_connection_send(fdr->connection, HELLOCMD, len, &bytes);
355
+ if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
356
+ error("ERROR: FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len);
357
+ return -1;
358
+ }
359
+
360
+ if (ctrlprotoversion == 2) {
361
+ if (fdr_receive_plist(fdr, &reply)) {
362
+ error("ERROR: FDR did not get HelloConn reply.\n");
363
+ return -1;
364
+ }
365
+ char* identifier = NULL;
366
+ char* cmd = NULL;
367
+ plist_t node = NULL;
368
+ node = plist_dict_get_item(reply, "Command");
369
+ if (node) {
370
+ plist_get_string_val(node, &cmd);
371
+ }
372
+ node = plist_dict_get_item(reply, "Identifier");
373
+ if (node) {
374
+ plist_get_string_val(node, &identifier);
375
+ }
376
+ plist_free(reply);
377
+
378
+ if (!cmd || (strcmp(cmd, "HelloConn") != 0)) {
379
+ if (cmd) {
380
+ free(cmd);
381
+ }
382
+ if (identifier) {
383
+ free(identifier);
384
+ }
385
+ error("ERROR: Did not receive HelloConn reply...\n");
386
+ return -1;
387
+ }
388
+ free(cmd);
389
+
390
+ if (identifier) {
391
+ debug("Got device identifier %s\n", identifier);
392
+ free(identifier);
393
+ }
394
+
395
+ } else {
396
+ char buf[16];
397
+ memset(buf, '\0', sizeof(buf));
398
+ bytes = 0;
399
+ device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
400
+ if (device_error != IDEVICE_E_SUCCESS) {
401
+ error("ERROR: Could not receive reply to HelloConn command\n");
402
+ return -1;
403
+ }
404
+ if (memcmp(buf, "HelloConn", 10) != 0) {
405
+ buf[9] = '\0';
406
+ error("ERROR: Did not receive HelloConn as reply, but %s\n", buf);
407
+ return -1;
408
+ }
409
+ }
410
+
411
+ return 0;
412
+ }
413
+
414
+ static int fdr_handle_sync_cmd(fdr_client_t fdr_ctrl)
415
+ {
416
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
417
+ fdr_client_t fdr;
418
+ thread_t fdr_thread = (thread_t)NULL;
419
+ int res = 0;
420
+ uint32_t bytes = 0;
421
+ char buf[4096];
422
+
423
+ device_error = idevice_connection_receive(fdr_ctrl->connection, buf, sizeof(buf), &bytes);
424
+ if (device_error != IDEVICE_E_SUCCESS || bytes != 2) {
425
+ error("ERROR: Unexpected data from FDR\n");
426
+ return -1;
427
+ }
428
+ /* Open a new connection and wait for messages on it */
429
+ if (fdr_connect(fdr_ctrl->device, FDR_CONN, &fdr)) {
430
+ error("ERROR: Failed to connect to FDR port\n");
431
+ return -1;
432
+ }
433
+ debug("FDR connected in reply to sync message, starting command thread\n");
434
+ res = thread_new(&fdr_thread, fdr_listener_thread, fdr);
435
+ if(res) {
436
+ error("ERROR: Failed to start FDR command thread\n");
437
+ fdr_free(fdr);
438
+ }
439
+ return res;
440
+ }
441
+
442
+ static int fdr_handle_plist_cmd(fdr_client_t fdr)
443
+ {
444
+ int res = 0;
445
+ plist_t dict;
446
+
447
+ if (fdr_receive_plist(fdr, &dict)) {
448
+ error("ERROR: FDR %p could not receive plist command.\n", fdr);
449
+ return -1;
450
+ }
451
+ plist_t node = plist_dict_get_item(dict, "Command");
452
+ if (!node || (plist_get_node_type(node) != PLIST_STRING)) {
453
+ error("ERROR: FDR %p Could not find Command in plist command\n", fdr);
454
+ plist_free(dict);
455
+ return -1;
456
+ }
457
+ char *command = NULL;
458
+ plist_get_string_val(node, &command);
459
+ plist_free(dict);
460
+
461
+ if (!command) {
462
+ info("FDR %p received empty plist command\n", fdr);
463
+ return -1;
464
+ }
465
+
466
+ if (!strcmp(command, "Ping")) {
467
+ dict = plist_new_dict();
468
+ plist_dict_set_item(dict, "Pong", plist_new_bool(1));
469
+ res = fdr_send_plist(fdr, dict);
470
+ plist_free(dict);
471
+ if (res) {
472
+ error("ERROR: FDR %p could not send Ping command reply.\n", fdr);
473
+ free(command);
474
+ return -1;
475
+ }
476
+ } else {
477
+ error("WARNING: FDR %p received unknown plist command: %s\n", fdr, command);
478
+ free(command);
479
+ return -1;
480
+ }
481
+
482
+ free(command);
483
+ /* FDR connection will be terminated remotely. Next receive will get nothing, error and terminate this worker thread. */
484
+ return 0;
485
+ }
486
+
487
+ static int fdr_handle_proxy_cmd(fdr_client_t fdr)
488
+ {
489
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
490
+ char *buf = NULL;
491
+ size_t bufsize = 1048576;
492
+ uint32_t sent = 0, bytes = 0;
493
+ char *host = NULL;
494
+ uint16_t port = 0;
495
+
496
+ buf = malloc(bufsize);
497
+ if (!buf) {
498
+ error("ERROR: %s: malloc failed\n", __func__);
499
+ return -1;
500
+ }
501
+
502
+ device_error = idevice_connection_receive(fdr->connection, buf, bufsize, &bytes);
503
+ if (device_error != IDEVICE_E_SUCCESS) {
504
+ free(buf);
505
+ error("ERROR: FDR %p failed to read data for proxy command\n", fdr);
506
+ return -1;
507
+ }
508
+ debug("Got proxy command with %u bytes\n", bytes);
509
+
510
+ /* Just return success here unconditionally because we don't know
511
+ * anything else and we will eventually abort on failure anyway */
512
+ uint16_t ack = 5;
513
+ device_error = idevice_connection_send(fdr->connection, (char *)&ack, sizeof(ack), &sent);
514
+ if (device_error != IDEVICE_E_SUCCESS || sent != sizeof(ack)) {
515
+ free(buf);
516
+ error("ERROR: FDR %p unable to send ack. Sent %u of %u bytes.\n",
517
+ fdr, sent, (uint32_t)sizeof(ack));
518
+ return -1;
519
+ }
520
+
521
+ if (bytes < 3) {
522
+ debug("FDR %p proxy command data too short, retrying\n", fdr);
523
+ return fdr_poll_and_handle_message(fdr);
524
+ }
525
+
526
+ /* ack command data too */
527
+ device_error = idevice_connection_send(fdr->connection, buf, bytes, &sent);
528
+ if (device_error != IDEVICE_E_SUCCESS || sent != bytes) {
529
+ free(buf);
530
+ error("ERROR: FDR %p unable to send data. Sent %u of %u bytes.\n",
531
+ fdr, sent, bytes);
532
+ return -1;
533
+ }
534
+
535
+ /* Now try to handle actual messages */
536
+ /* Connect: 0 3 hostlen <host> <port> */
537
+ if (buf[0] == 0 && buf[1] == 3) {
538
+ uint16_t *p = (uint16_t *)&buf[bytes - 2];
539
+ port = be16toh(*p);
540
+ buf[bytes - 2] = '\0';
541
+ host = strdup(&buf[3]);
542
+ debug("FDR %p Proxy connect request to %s:%u\n", fdr, host, port);
543
+ }
544
+
545
+ if (!host || !buf[2]) {
546
+ /* missing or zero length host name */
547
+ free(buf);
548
+ return 0;
549
+ }
550
+
551
+ /* else wait for messages and forward them */
552
+ int sockfd = socket_connect(host, port);
553
+ free(host);
554
+ if (sockfd < 0) {
555
+ free(buf);
556
+ error("ERROR: Failed to connect socket: %s\n", strerror(errno));
557
+ return -1;
558
+ }
559
+
560
+ int res = 0, bytes_ret;
561
+ while (1) {
562
+ bytes = 0;
563
+ device_error = idevice_connection_receive_timeout(fdr->connection, buf, bufsize, &bytes, 100);
564
+ #ifdef HAVE_IDEVICE_E_TIMEOUT
565
+ if (device_error == IDEVICE_E_TIMEOUT || (device_error == IDEVICE_E_SUCCESS && !bytes))
566
+ #else
567
+ if (device_error == IDEVICE_E_SUCCESS && !bytes)
568
+ #endif
569
+ {
570
+ //debug("WARNING: Timeout waiting for proxy payload. %p\n", fdr);
571
+ }
572
+ else if (device_error != IDEVICE_E_SUCCESS) {
573
+ error("ERROR: FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error);
574
+ res = -1;
575
+ break;
576
+ }
577
+ if (bytes) {
578
+ debug("FDR %p got payload of %u bytes, now try to proxy it\n", fdr, bytes);
579
+ debug("Sending %u bytes of data\n", bytes);
580
+ sent = 0;
581
+ while (sent < bytes) {
582
+ int s = socket_send(sockfd, buf + sent, bytes - sent);
583
+ if (s < 0) {
584
+ break;
585
+ }
586
+ sent += s;
587
+ }
588
+ if (sent != bytes) {
589
+ error("ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes);
590
+ socket_close(sockfd);
591
+ res = -1;
592
+ break;
593
+ }
594
+ }
595
+ bytes_ret = socket_receive_timeout(sockfd, buf, bufsize, 0, 100);
596
+ if (bytes_ret < 0) {
597
+ if (errno)
598
+ error("ERROR: FDR %p receiving proxy payload failed: %s\n",
599
+ fdr, strerror(errno));
600
+ else
601
+ res = 1; /* close connection if no data with no error */
602
+ break;
603
+ }
604
+
605
+ bytes = bytes_ret;
606
+ if (bytes) {
607
+ debug("FDR %p Received %u bytes reply data,%s sending to device\n",
608
+ fdr, bytes, (bytes ? "" : " not"));
609
+
610
+ sent = 0;
611
+ while (sent < bytes) {
612
+ uint32_t s;
613
+ device_error = idevice_connection_send(fdr->connection, buf + sent, bytes - sent, &s);
614
+ if (device_error != IDEVICE_E_SUCCESS) {
615
+ break;
616
+ }
617
+ sent += s;
618
+ }
619
+ if (device_error != IDEVICE_E_SUCCESS || bytes != sent) {
620
+ error("ERROR: FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes);
621
+ res = -1;
622
+ break;
623
+ }
624
+ } else serial++;
625
+ }
626
+ socket_close(sockfd);
627
+ free(buf);
628
+ return res;
629
+ }
fdr.h ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * fdr.h
3
+ * Functions for handling FDR connections
4
+ *
5
+ * Copyright (c) 2014 BALATON Zoltan. 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
+ #ifndef IDEVICERESTORE_FDR_H
23
+ #define IDEVICERESTORE_FDR_H
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ #include <libimobiledevice/libimobiledevice.h>
30
+ #include "thread.h" /* from libimobiledevice/common */
31
+
32
+ typedef enum {
33
+ FDR_CTRL,
34
+ FDR_CONN
35
+ } fdr_type_t;
36
+
37
+ struct fdr_client {
38
+ idevice_connection_t connection;
39
+ idevice_t device;
40
+ fdr_type_t type;
41
+ };
42
+ typedef struct fdr_client *fdr_client_t;
43
+
44
+ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t *fdr);
45
+ void fdr_disconnect(fdr_client_t fdr);
46
+ void fdr_free(fdr_client_t fdr);
47
+ int fdr_poll_and_handle_message(fdr_client_t fdr);
48
+ void *fdr_listener_thread(void *cdata);
49
+
50
+ #ifdef __cplusplus
51
+ }
52
+ #endif
53
+
54
+ #endif
file_relay.c ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * file_relay.c
3
+ * com.apple.mobile.file_relay service implementation.
4
+ *
5
+ * Copyright (c) 2010 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
+ #include <string.h>
26
+ #include <stdlib.h>
27
+ #include "file_relay.h"
28
+ #include "property_list_service.h"
29
+ #include "common/debug.h"
30
+
31
+ file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client)
32
+ {
33
+ if (!device || !service || service->port == 0 || !client || *client) {
34
+ return FILE_RELAY_E_INVALID_ARG;
35
+ }
36
+
37
+ property_list_service_client_t plistclient = NULL;
38
+ if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
39
+ return FILE_RELAY_E_MUX_ERROR;
40
+ }
41
+
42
+ /* create client object */
43
+ file_relay_client_t client_loc = (file_relay_client_t) malloc(sizeof(struct file_relay_client_private));
44
+ client_loc->parent = plistclient;
45
+
46
+ /* all done, return success */
47
+ *client = client_loc;
48
+ return FILE_RELAY_E_SUCCESS;
49
+ }
50
+
51
+ file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label)
52
+ {
53
+ file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR;
54
+ service_client_factory_start_service(device, FILE_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(file_relay_client_new), &err);
55
+ return err;
56
+ }
57
+
58
+ file_relay_error_t file_relay_client_free(file_relay_client_t client)
59
+ {
60
+ if (!client)
61
+ return FILE_RELAY_E_INVALID_ARG;
62
+
63
+ if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
64
+ return FILE_RELAY_E_UNKNOWN_ERROR;
65
+ }
66
+ free(client);
67
+ return FILE_RELAY_E_SUCCESS;
68
+ }
69
+
70
+ file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout)
71
+ {
72
+ if (!client || !client->parent || !sources || !sources[0]) {
73
+ return FILE_RELAY_E_INVALID_ARG;
74
+ }
75
+ *connection = NULL;
76
+ file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR;
77
+ /* set up request plist */
78
+ plist_t array = plist_new_array();
79
+ int i = 0;
80
+ while (sources[i]) {
81
+ plist_array_append_item(array, plist_new_string(sources[i]));
82
+ i++;
83
+ }
84
+ plist_t dict = plist_new_dict();
85
+ plist_dict_set_item(dict, "Sources", array);
86
+
87
+ if (property_list_service_send_xml_plist(client->parent, dict) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
88
+ debug_info("ERROR: Could not send request to device!");
89
+ err = FILE_RELAY_E_MUX_ERROR;
90
+ goto leave;
91
+ }
92
+ plist_free(dict);
93
+
94
+ dict = NULL;
95
+ if (property_list_service_receive_plist_with_timeout(client->parent, &dict, timeout) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
96
+ debug_info("ERROR: Could not receive answer from device!");
97
+ err = FILE_RELAY_E_MUX_ERROR;
98
+ goto leave;
99
+ }
100
+
101
+ if (!dict) {
102
+ debug_info("ERROR: Did not receive any plist!");
103
+ err = FILE_RELAY_E_PLIST_ERROR;
104
+ goto leave;
105
+ }
106
+
107
+ plist_t error = plist_dict_get_item(dict, "Error");
108
+ if (error) {
109
+ char *errmsg = NULL;
110
+ plist_get_string_val(error, &errmsg);
111
+ if (errmsg) {
112
+ if (!strcmp(errmsg, "InvalidSource")) {
113
+ debug_info("ERROR: One or more given sources are invalid!");
114
+ err = FILE_RELAY_E_INVALID_SOURCE;
115
+ } else if (!strcmp(errmsg, "StagingEmpty")) {
116
+ debug_info("ERROR: StagingEmpty - No data available!");
117
+ err = FILE_RELAY_E_STAGING_EMPTY;
118
+ } else if (!strcmp(errmsg, "PermissionDenied")) {
119
+ debug_info("ERROR: Permission denied.");
120
+ err = FILE_RELAY_E_PERMISSION_DENIED;
121
+ } else {
122
+ debug_info("ERROR: Unknown error '%s'", errmsg);
123
+ }
124
+ free(errmsg);
125
+ } else {
126
+ debug_info("ERROR: Could not get error message!");
127
+ }
128
+ goto leave;
129
+ }
130
+
131
+ plist_t status = plist_dict_get_item(dict, "Status");
132
+ if (!status) {
133
+ debug_info("ERROR: Unexpected plist received!");
134
+ debug_plist(dict);
135
+ err = FILE_RELAY_E_PLIST_ERROR;
136
+ goto leave;
137
+ }
138
+
139
+ char *ack = NULL;
140
+ plist_get_string_val(status, &ack);
141
+ if (!ack) {
142
+ debug_info("ERROR: Could not get 'Acknowledged' string!");
143
+ goto leave;
144
+ }
145
+
146
+ if (strcmp(ack, "Acknowledged") != 0) {
147
+ debug_info("ERROR: Did not receive 'Acknowledged' but '%s'", ack);
148
+ goto leave;
149
+ }
150
+ free(ack);
151
+ err = FILE_RELAY_E_SUCCESS;
152
+
153
+ *connection = client->parent->parent->connection;
154
+
155
+ leave:
156
+ if (dict) {
157
+ plist_free(dict);
158
+ }
159
+ return err;
160
+ }
161
+
162
+ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection)
163
+ {
164
+ return file_relay_request_sources_timeout(client, sources, connection, 60000);
165
+ }
file_relay.h ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * file_relay.h
3
+ * com.apple.mobile.file_relay service header file.
4
+ *
5
+ * Copyright (c) 2010 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
+ #ifndef __FILE_RELAY_H
23
+ #define __FILE_RELAY_H
24
+
25
+ #include "idevice.h"
26
+ #include "libimobiledevice/file_relay.h"
27
+ #include "property_list_service.h"
28
+
29
+ struct file_relay_client_private {
30
+ property_list_service_client_t parent;
31
+ };
32
+
33
+ #endif
file_relay.pxi ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from "libimobiledevice/file_relay.h":
2
+ cdef struct file_relay_client_private:
3
+ pass
4
+ ctypedef file_relay_client_private *file_relay_client_t
5
+ ctypedef char** const_sources_t "const char**"
6
+
7
+ ctypedef enum file_relay_error_t:
8
+ FILE_RELAY_E_SUCCESS = 0
9
+ FILE_RELAY_E_INVALID_ARG = -1
10
+ FILE_RELAY_E_PLIST_ERROR = -2
11
+ FILE_RELAY_E_MUX_ERROR = -3
12
+ FILE_RELAY_E_INVALID_SOURCE = -4
13
+ FILE_RELAY_E_STAGING_EMPTY = -5
14
+ FILE_RELAY_E_PERMISSION_DENIED = -6
15
+ FILE_RELAY_E_UNKNOWN_ERROR = -256
16
+
17
+ file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, file_relay_client_t *client)
18
+ file_relay_error_t file_relay_client_free(file_relay_client_t client)
19
+
20
+ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const_sources_t sources, idevice_connection_t *connection)
21
+
22
+ cdef class FileRelayError(BaseError):
23
+ def __init__(self, *args, **kwargs):
24
+ self._lookup_table = {
25
+ FILE_RELAY_E_SUCCESS: "Success",
26
+ FILE_RELAY_E_INVALID_ARG: "Invalid argument",
27
+ FILE_RELAY_E_PLIST_ERROR: "Property list error",
28
+ FILE_RELAY_E_MUX_ERROR: "MUX error",
29
+ FILE_RELAY_E_INVALID_SOURCE: "Invalid source",
30
+ FILE_RELAY_E_STAGING_EMPTY: "Staging empty",
31
+ FILE_RELAY_E_PERMISSION_DENIED: "Permission denied",
32
+ FILE_RELAY_E_UNKNOWN_ERROR: "Unknown error"
33
+ }
34
+ BaseError.__init__(self, *args, **kwargs)
35
+
36
+ from libc.stdlib cimport *
37
+
38
+ cdef class FileRelayClient(PropertyListService):
39
+ __service_name__ = "com.apple.mobile.file_relay"
40
+ cdef file_relay_client_t _c_client
41
+
42
+ def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs):
43
+ self.handle_error(file_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client))
44
+
45
+ def __dealloc__(self):
46
+ cdef file_relay_error_t err
47
+ if self._c_client is not NULL:
48
+ err = file_relay_client_free(self._c_client)
49
+ self.handle_error(err)
50
+
51
+ cpdef iDeviceConnection request_sources(self, list sources):
52
+ cdef:
53
+ file_relay_error_t err
54
+ Py_ssize_t count = len(sources)
55
+ char** c_sources = <char**>malloc(sizeof(char*) * (count + 1))
56
+ iDeviceConnection conn = iDeviceConnection.__new__(iDeviceConnection)
57
+
58
+ for i, value in enumerate(sources):
59
+ c_sources[i] = value
60
+ c_sources[count] = NULL
61
+
62
+ err = file_relay_request_sources(self._c_client, <const_sources_t>c_sources, &conn._c_connection)
63
+ free(c_sources)
64
+ self.handle_error(err)
65
+ return conn
66
+
67
+ cdef inline BaseError _error(self, int16_t ret):
68
+ return FileRelayError(ret)
fls.c ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * fls.c
3
+ * support for .fls file format (found in .bbfw files)
4
+ *
5
+ * Copyright (c) 2012 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
+ #include <stdio.h>
22
+ #include <stdlib.h>
23
+ #include <string.h>
24
+ #include "fls.h"
25
+ #include "common.h"
26
+
27
+ #ifndef offsetof
28
+ #define offsetof(type, member) __builtin_offsetof (type, member)
29
+ #endif
30
+
31
+ static void fls_parse_elements(fls_file* fls)
32
+ {
33
+ /* FIXME: the following code is not big endian safe */
34
+ if (!fls || !fls->data) {
35
+ return;
36
+ }
37
+ uint32_t offset = 0;
38
+ fls->max_elements = 32;
39
+ fls->elements = (fls_element**)malloc(sizeof(fls_element*) * fls->max_elements);
40
+
41
+ fls_element* cur = NULL;
42
+ do {
43
+ void* p = fls->data + offset;
44
+ uint32_t hdrsize = 0;
45
+ cur = (fls_element*)p;
46
+ if ((offset + cur->size) > fls->size) {
47
+ break;
48
+ }
49
+ fls_element* ne;
50
+ switch (cur->type) {
51
+ case 0x0c:
52
+ {
53
+ hdrsize = offsetof(fls_0c_element, data);
54
+ fls_0c_element* xe = (fls_0c_element*)malloc(sizeof(fls_0c_element));
55
+ memset(xe, '\0', sizeof(fls_0c_element));
56
+ memcpy((void*)xe, p, hdrsize);
57
+ xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
58
+ ne = (fls_element*)xe;
59
+ fls->c_element = xe;
60
+ }
61
+ break;
62
+ case 0x10:
63
+ {
64
+ hdrsize = offsetof(fls_10_element, data);
65
+ fls_10_element* xe = (fls_10_element*)malloc(sizeof(fls_10_element));
66
+ memset(xe, '\0', sizeof(fls_10_element));
67
+ memcpy((void*)xe, p, hdrsize);
68
+ xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
69
+ ne = (fls_element*)xe;
70
+ }
71
+ break;
72
+ case 0x14:
73
+ {
74
+ hdrsize = offsetof(fls_14_element, data);
75
+ fls_14_element* xe = (fls_14_element*)malloc(sizeof(fls_14_element));
76
+ memset(xe, '\0', sizeof(fls_14_element));
77
+ memcpy((void*)xe, p, hdrsize);
78
+ xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
79
+ ne = (fls_element*)xe;
80
+ }
81
+ break;
82
+ default:
83
+ hdrsize = offsetof(fls_element, data);
84
+ ne = (fls_element*)malloc(sizeof(fls_element));
85
+ memset(ne, '\0', sizeof(fls_element));
86
+ ne->type = cur->type;
87
+ ne->size = cur->size;
88
+ ne->data = (ne->size > hdrsize) ? p + hdrsize : NULL;
89
+ break;
90
+ }
91
+ if ((fls->num_elements + 1) > fls->max_elements) {
92
+ fls->max_elements += 10;
93
+ fls->elements = (fls_element**)realloc(fls->elements, sizeof(fls_element*) * fls->max_elements);
94
+ }
95
+ fls->elements[fls->num_elements++] = ne;
96
+ offset += cur->size;
97
+ } while (offset < fls->size);
98
+ if (offset != fls->size) {
99
+ error("ERROR: %s: error parsing elements\n", __func__);
100
+ return;
101
+ }
102
+ }
103
+
104
+ fls_file* fls_parse(unsigned char* data, unsigned int size)
105
+ {
106
+ fls_file* fls = (fls_file*)malloc(sizeof(fls_file));
107
+ if (!fls) {
108
+ return NULL;
109
+ }
110
+ memset(fls, '\0', sizeof(fls_file));
111
+ fls->data = malloc(size);
112
+ fls->size = size;
113
+ memcpy(fls->data, data, size);
114
+ fls_parse_elements(fls);
115
+ return fls;
116
+ }
117
+
118
+ void fls_free(fls_file* fls)
119
+ {
120
+ if (fls) {
121
+ if (fls->num_elements > 0) {
122
+ int i;
123
+ for (i = fls->num_elements-1; i >=0; i--) {
124
+ free(fls->elements[i]);
125
+ }
126
+ free(fls->elements);
127
+ }
128
+ if (fls->data) {
129
+ free(fls->data);
130
+ }
131
+ free(fls);
132
+ }
133
+ }
134
+
135
+ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen)
136
+ {
137
+ /* FIXME: the code in this function is not big endian safe */
138
+ if (!fls || !fls->num_elements) {
139
+ error("ERROR: %s: no data\n", __func__);
140
+ return -1;
141
+ }
142
+ if (!fls->c_element) {
143
+ error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
144
+ return -1;
145
+ }
146
+
147
+ uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10);
148
+ if (datasize != fls->c_element->data_size) {
149
+ error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size);
150
+ return -1;
151
+ }
152
+ uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14);
153
+ if (sigoffset > datasize) {
154
+ error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize);
155
+ return -1;
156
+ }
157
+
158
+ uint32_t oldsiglen = datasize - sigoffset;
159
+ uint32_t newsize = fls->size - oldsiglen + siglen;
160
+
161
+ unsigned int i;
162
+ uint32_t offset = 0;
163
+ void* newdata = malloc(newsize);
164
+ if (!newdata) {
165
+ error("ERROR: %s: out of memory\n", __func__);
166
+ return -1;
167
+ }
168
+ uint32_t hdrsize = 0;
169
+ uint32_t firstpartlen = 0;
170
+ for (i = 0; i < fls->num_elements; i++) {
171
+ switch (fls->elements[i]->type) {
172
+ case 0x0c:
173
+ hdrsize = offsetof(fls_0c_element, data);
174
+ // update offset
175
+ ((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize;
176
+ // copy first part of data
177
+ firstpartlen = fls->elements[i]->size - hdrsize - oldsiglen;
178
+ memcpy(newdata+offset+hdrsize, ((fls_0c_element*)fls->elements[i])->data, firstpartlen);
179
+ // copy new signature data
180
+ memcpy(newdata+offset+hdrsize+firstpartlen, sigdata, siglen);
181
+ ((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize;
182
+ fls->elements[i]->size -= oldsiglen;
183
+ fls->elements[i]->size += siglen;
184
+ ((fls_0c_element*)fls->elements[i])->data_size -= oldsiglen;
185
+ ((fls_0c_element*)fls->elements[i])->data_size += siglen;
186
+ memcpy(newdata+offset+hdrsize+0x10, &(((fls_0c_element*)fls->elements[i])->data_size), 4);
187
+ // copy header
188
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
189
+ break;
190
+ case 0x10:
191
+ hdrsize = offsetof(fls_10_element, data);
192
+ // update offset
193
+ ((fls_10_element*)fls->elements[i])->offset = offset+hdrsize;
194
+ // copy header
195
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
196
+ // copy data
197
+ if (fls->elements[i]->size > hdrsize) {
198
+ memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
199
+ ((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize;
200
+ } else {
201
+ ((fls_10_element*)fls->elements[i])->data = NULL;
202
+ }
203
+ break;
204
+ case 0x14:
205
+ hdrsize = offsetof(fls_14_element, data);
206
+ // update offset
207
+ ((fls_14_element*)fls->elements[i])->offset = offset+hdrsize;
208
+ // copy header
209
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
210
+ // copy data
211
+ if (fls->elements[i]->size > hdrsize) {
212
+ memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
213
+ ((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize;
214
+ } else {
215
+ ((fls_14_element*)fls->elements[i])->data = NULL;
216
+ }
217
+ break;
218
+ default:
219
+ hdrsize = offsetof(fls_element, data);
220
+ // copy header
221
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
222
+ // copy data
223
+ if (fls->elements[i]->size > hdrsize) {
224
+ memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize);
225
+ fls->elements[i]->data = newdata+offset+hdrsize;
226
+ } else {
227
+ fls->elements[i]->data = NULL;
228
+ }
229
+ break;
230
+ }
231
+ offset += fls->elements[i]->size;
232
+ }
233
+ if (fls->data) {
234
+ free(fls->data);
235
+ }
236
+ fls->data = newdata;
237
+ fls->size = newsize;
238
+
239
+ return 0;
240
+ }
241
+
242
+ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size)
243
+ {
244
+ /* FIXME: the code in this function is not big endian safe */
245
+ if (!fls || !fls->num_elements) {
246
+ error("ERROR: %s: no data\n", __func__);
247
+ return -1;
248
+ }
249
+ if (!fls->c_element) {
250
+ error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
251
+ return -1;
252
+ }
253
+
254
+ uint32_t padding = 0;
255
+ if (size%4 != 0) {
256
+ padding = 4-(size%4);
257
+ }
258
+ uint32_t newsize = fls->size + size + padding;
259
+ unsigned int i;
260
+ uint32_t offset = 0;
261
+ void* newdata = malloc(newsize);
262
+ if (!newdata) {
263
+ error("ERROR: %s: out of memory\n", __func__);
264
+ return -1;
265
+ }
266
+ uint32_t hdrsize = 0;
267
+ for (i = 0; i < fls->num_elements; i++) {
268
+ switch (fls->elements[i]->type) {
269
+ case 0x0c:
270
+ hdrsize = offsetof(fls_0c_element, data);
271
+ // update offset
272
+ ((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize;
273
+ // copy ticket data
274
+ memcpy(newdata+offset+hdrsize, data, size);
275
+ if (padding > 0) {
276
+ // padding
277
+ memset(newdata+offset+hdrsize+size, '\xFF', padding);
278
+ }
279
+ // copy remaining data
280
+ memcpy(newdata+offset+hdrsize+size+padding, ((fls_0c_element*)fls->elements[i])->data, fls->elements[i]->size);
281
+ ((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize;
282
+ fls->elements[i]->size += (size + padding);
283
+ ((fls_0c_element*)fls->elements[i])->data_size += (size + padding);
284
+ // copy header
285
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
286
+ break;
287
+ case 0x10:
288
+ hdrsize = offsetof(fls_10_element, data);
289
+ // update offset
290
+ ((fls_10_element*)fls->elements[i])->offset = offset+hdrsize;
291
+ // copy header
292
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
293
+ // copy data
294
+ if (fls->elements[i]->size > hdrsize) {
295
+ memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
296
+ ((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize;
297
+ } else {
298
+ ((fls_10_element*)fls->elements[i])->data = NULL;
299
+ }
300
+ break;
301
+ case 0x14:
302
+ hdrsize = offsetof(fls_14_element, data);
303
+ // update offset
304
+ ((fls_14_element*)fls->elements[i])->offset = offset+hdrsize;
305
+ // copy header
306
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
307
+ // copy data
308
+ if (fls->elements[i]->size > hdrsize) {
309
+ memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
310
+ ((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize;
311
+ } else {
312
+ ((fls_14_element*)fls->elements[i])->data = NULL;
313
+ }
314
+ break;
315
+ default:
316
+ hdrsize = offsetof(fls_element, data);
317
+ // copy header
318
+ memcpy(newdata+offset, fls->elements[i], hdrsize);
319
+ // copy data
320
+ if (fls->elements[i]->size > hdrsize) {
321
+ memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize);
322
+ fls->elements[i]->data = newdata+offset+hdrsize;
323
+ } else {
324
+ fls->elements[i]->data = NULL;
325
+ }
326
+ break;
327
+ }
328
+ offset += fls->elements[i]->size;
329
+ }
330
+ if (fls->data) {
331
+ free(fls->data);
332
+ }
333
+ fls->data = newdata;
334
+ fls->size = newsize;
335
+
336
+ return 0;
337
+ }
338
+
fls.h ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * fls.h
3
+ * support for .fls file format (found in .bbfw files)
4
+ *
5
+ * Copyright (c) 2012 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
+ #ifndef FLS_H
22
+ #define FLS_H
23
+
24
+ #include <stdint.h>
25
+
26
+ struct _fls_element {
27
+ uint32_t type;
28
+ uint32_t size;
29
+ uint32_t empty;
30
+ const unsigned char* data;
31
+ } __attribute__((packed));
32
+ typedef struct _fls_element fls_element;
33
+
34
+ struct _fls_0c_element {
35
+ uint32_t type;
36
+ uint32_t size;
37
+ uint32_t empty;
38
+ uint32_t off_0x0c;
39
+ uint32_t off_0x10;
40
+ uint32_t off_0x14;
41
+ uint32_t off_0x18;
42
+ uint32_t data_size; // size without header
43
+ uint32_t off_0x20;
44
+ uint32_t offset; // absolute offset of data in file
45
+ const unsigned char* data; // data+0x14 contains offset to sig blob
46
+ } __attribute__((packed));
47
+ typedef struct _fls_0c_element fls_0c_element;
48
+
49
+ struct _fls_10_element {
50
+ uint32_t type;
51
+ uint32_t size;
52
+ uint32_t empty;
53
+ uint32_t data_size; // size without header
54
+ uint32_t off_0x10;
55
+ uint32_t offset;
56
+ const unsigned char* data;
57
+ } __attribute__((packed));
58
+ typedef struct _fls_10_element fls_10_element;
59
+
60
+ struct _fls_14_element {
61
+ uint32_t type;
62
+ uint32_t size;
63
+ uint32_t empty;
64
+ uint32_t data_size; // size without header
65
+ uint32_t off_0x10;
66
+ uint32_t offset;
67
+ const unsigned char* data;
68
+ } __attribute__((packed));
69
+ typedef struct _fls_14_element fls_14_element;
70
+
71
+ typedef struct {
72
+ unsigned int num_elements;
73
+ unsigned int max_elements;
74
+ fls_element** elements;
75
+ const fls_0c_element* c_element;
76
+ void* data;
77
+ uint32_t size;
78
+ } fls_file;
79
+
80
+ fls_file* fls_parse(unsigned char* data, unsigned int size);
81
+ void fls_free(fls_file* fls);
82
+ int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size);
83
+ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size);
84
+
85
+ #endif
ftab.c ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * ftab.c
3
+ * Functions for handling the ftab format
4
+ *
5
+ * Copyright (c) 2019 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
+ #include <stdio.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+ #include <stdint.h>
26
+
27
+ #include "ftab.h"
28
+ #include "common.h"
29
+ #include "endianness.h"
30
+
31
+ int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag)
32
+ {
33
+ if (!data || !data_size || !ftab) {
34
+ return -1;
35
+ }
36
+
37
+ if (data_size < sizeof(struct ftab_header)) {
38
+ error("ERROR: %s: Buffer too small for ftab data\n", __func__);
39
+ return -1;
40
+ }
41
+
42
+ struct ftab_header *hdr_ptr = (struct ftab_header*)data;
43
+ if (be32toh(hdr_ptr->magic) != 'ftab') {
44
+ error("ERROR: %s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic));
45
+ return -1;
46
+ }
47
+
48
+ /* copy header */
49
+ ftab_t ftab_new = (ftab_t)calloc(1, sizeof(struct ftab_fmt));
50
+ memcpy(&ftab_new->header, data, sizeof(struct ftab_header));
51
+
52
+ ftab_new->header.always_01 = le32toh(ftab_new->header.always_01);
53
+ ftab_new->header.always_ff = le32toh(ftab_new->header.always_ff);
54
+ ftab_new->header.tag = be32toh(ftab_new->header.tag);
55
+ if (tag) {
56
+ *tag = ftab_new->header.tag;
57
+ }
58
+ ftab_new->header.magic = be32toh(ftab_new->header.magic);
59
+ ftab_new->header.num_entries = le32toh(ftab_new->header.num_entries);
60
+
61
+ /* copy entries */
62
+ ftab_new->entries = (struct ftab_entry*)malloc(sizeof(struct ftab_entry) * ftab_new->header.num_entries);
63
+ memcpy(ftab_new->entries, data + sizeof(struct ftab_header), sizeof(struct ftab_entry) * ftab_new->header.num_entries);
64
+
65
+ /* create data storage */
66
+ ftab_new->storage = (unsigned char**)calloc(ftab_new->header.num_entries, sizeof(unsigned char*));
67
+
68
+ /* fill data storage */
69
+ uint32_t i = 0;
70
+ for (i = 0; i < ftab_new->header.num_entries; i++) {
71
+ ftab_new->entries[i].tag = be32toh(ftab_new->entries[i].tag);
72
+ ftab_new->entries[i].offset = le32toh(ftab_new->entries[i].offset);
73
+ ftab_new->entries[i].size = le32toh(ftab_new->entries[i].size);
74
+
75
+ ftab_new->storage[i] = malloc(ftab_new->entries[i].size);
76
+ memcpy(ftab_new->storage[i], data + ftab_new->entries[i].offset, ftab_new->entries[i].size);
77
+ }
78
+
79
+ *ftab = ftab_new;
80
+
81
+ return 0;
82
+ }
83
+
84
+ int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size)
85
+ {
86
+ if (!ftab || !tag || !data || !data_size) {
87
+ return -1;
88
+ }
89
+
90
+ uint32_t i;
91
+ int res = -1;
92
+ for (i = 0; i < ftab->header.num_entries; i++) {
93
+ if (ftab->entries[i].tag == tag) {
94
+ *data = ftab->storage[i];
95
+ *data_size = ftab->entries[i].size;
96
+ res = 0;
97
+ }
98
+ }
99
+ return res;
100
+ }
101
+
102
+ int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size)
103
+ {
104
+ if (!ftab || !tag || !data || !data_size) {
105
+ return -1;
106
+ }
107
+
108
+ uint32_t new_index = ftab->header.num_entries;
109
+ struct ftab_entry *new_entries = realloc(ftab->entries, sizeof(struct ftab_entry) * (ftab->header.num_entries + 1));
110
+ if (!new_entries) {
111
+ error("ERROR: %s: realloc failed!\n", __func__);
112
+ return -1;
113
+ }
114
+ ftab->entries = new_entries;
115
+ unsigned char **new_storage = realloc(ftab->storage, sizeof(unsigned char*) * (ftab->header.num_entries + 1));
116
+ if (!new_storage) {
117
+ error("ERROR: %s: realloc failed!\n", __func__);
118
+ return -1;
119
+ }
120
+ ftab->storage = new_storage;
121
+
122
+ unsigned char *data_copy = (unsigned char*)malloc(data_size);
123
+ if (!data_copy) {
124
+ return -1;
125
+ }
126
+ memcpy(data_copy, data, data_size);
127
+
128
+ ftab->storage[new_index] = data_copy;
129
+ ftab->entries[new_index].tag = tag;
130
+ ftab->entries[new_index].size = data_size;
131
+ ftab->header.num_entries++;
132
+
133
+ uint32_t off = sizeof(struct ftab_header) + sizeof(struct ftab_entry) * ftab->header.num_entries;
134
+ uint32_t i;
135
+ for (i = 0; i < ftab->header.num_entries; i++) {
136
+ ftab->entries[i].offset = off;
137
+ off += ftab->entries[i].size;
138
+ }
139
+
140
+ return 0;
141
+ }
142
+
143
+ int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size)
144
+ {
145
+ uint32_t i;
146
+ unsigned int total_size = sizeof(struct ftab_header);
147
+ total_size += ftab->header.num_entries * sizeof(struct ftab_entry);
148
+ for (i = 0; i < ftab->header.num_entries; i++) {
149
+ total_size += ftab->entries[i].size;
150
+ }
151
+
152
+ unsigned char *data_out = (unsigned char*)malloc(total_size);
153
+ if (!data_out) {
154
+ error("ERROR: %s: Out of memory?!\n", __func__);
155
+ return -1;
156
+ }
157
+
158
+ struct ftab_header *ftab_header = (struct ftab_header*)data_out;
159
+ memset(ftab_header, '\0', sizeof(struct ftab_header));
160
+ ftab_header->always_01 = htole32(ftab->header.always_01);
161
+ ftab_header->always_ff = htole32(ftab->header.always_ff);
162
+ ftab_header->tag = htobe32(ftab->header.tag);
163
+ ftab_header->magic = htobe32(ftab->header.magic);
164
+ ftab_header->num_entries = htole32(ftab->header.num_entries);
165
+
166
+ for (i = 0; i < ftab->header.num_entries; i++) {
167
+ struct ftab_entry* entry = (struct ftab_entry*)(data_out + sizeof(struct ftab_header) + (sizeof(struct ftab_entry) * i));
168
+ entry->tag = htobe32(ftab->entries[i].tag);
169
+ entry->offset = htole32(ftab->entries[i].offset);
170
+ entry->size = htole32(ftab->entries[i].size);
171
+ entry->pad_0x0C = 0;
172
+ }
173
+
174
+ unsigned char *p = data_out + sizeof(struct ftab_header) + (sizeof(struct ftab_entry) * ftab->header.num_entries);
175
+ for (i = 0; i < ftab->header.num_entries; i++) {
176
+ memcpy(p, ftab->storage[i], ftab->entries[i].size);
177
+ p += ftab->entries[i].size;
178
+ }
179
+
180
+ *data = data_out;
181
+ *data_size = total_size;
182
+
183
+ return 0;
184
+ }
185
+
186
+ int ftab_free(ftab_t ftab)
187
+ {
188
+ if (!ftab) return -1;
189
+ uint32_t i = 0;
190
+ for (i = 0; i < ftab->header.num_entries; i++) {
191
+ free(ftab->storage[i]);
192
+ }
193
+ free(ftab->storage);
194
+ free(ftab->entries);
195
+ free(ftab);
196
+ return 0;
197
+ }