diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..04a4843e2c22e56506466b54a957cf31e5fd451c --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +*.mo +*.mo~ +*.po~ +*.pot~ +*.pyc +*.swp +**/__pycache__ +**/.mypy_cache +/*.apt-sources +/*.build-manifest +/*.buildlog +/*.img +/*.iso +/*.list +/*.packages +/*.rake_tasks~ +/*.vdi +/binary +/cache +/chroot/ +/config/amnesia.local +/config/binary +/config/bootstrap +/config/chroot +/config/common +/config/source +/config/chroot_local-includes/etc/amnesia/environment +/config/chroot_local-includes/etc/amnesia/version +/config/chroot_local-includes/usr/share/doc/Changelog +/config/chroot_local-includes/usr/share/doc/amnesia/Changelog +/config/chroot_local-includes/usr/share/doc/tails/website +/config/chroot_local-includes/usr/share/tails/build/variables +/.lock +/.stage +/source +/vagrant/.vagrant +/vagrant/definitions/squeeze/preseed.cfg +/vagrant/iso +/vagrant/squeeze.box +# Jenkins artifacts directory +/build-artifacts/ + +# Files managed by intltool +/config/chroot_local-includes/etc/skel/Desktop/tails-documentation.desktop +/config/chroot_local-includes/etc/skel/Desktop/Report_an_error.desktop +/config/chroot_local-includes/etc/skel/Desktop/Tails_documentation.desktop +/config/chroot_local-includes/usr/local/share/mime/packages/unlock-veracrypt-volumes.xml +/config/chroot_local-includes/usr/share/applications/org.boum.tails.additional-software-config.desktop +/config/chroot_local-includes/usr/share/applications/tails-documentation.desktop +/config/chroot_local-includes/usr/share/applications/tails-reboot.desktop +/config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop +/config/chroot_local-includes/usr/share/applications/tails-shutdown.desktop +/config/chroot_local-includes/usr/share/applications/tor-browser.desktop +/config/chroot_local-includes/usr/share/applications/tails-about.desktop +/config/chroot_local-includes/usr/share/applications/unlock-veracrypt-volumes.desktop +/config/chroot_local-includes/usr/share/desktop-directories/Tails.directory +/config/chroot_local-includes/usr/share/polkit-1/actions/org.boum.tails.root-terminal.policy +/config/chroot_local-includes/usr/share/polkit-1/actions/org.boum.tails.additional-software.policy +/config/chroot_local-includes/usr/share/tails/unlock-veracrypt-volumes/*.ui +/tmp/ + +# The test suite's local configuration files +/features/config/local.yml +/features/config/*.d/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..a5302b2942f3ed94f28cb1191001eed83e6d46fa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,16 @@ +[submodule "submodules/pythonlib"] + path = submodules/pythonlib + url = https://git-tails.immerda.ch/pythonlib +[submodule "submodules/jenkins-tools"] + path = submodules/jenkins-tools + url = https://git-tails.immerda.ch/jenkins-tools +[submodule "submodules/chutney"] + path = submodules/chutney + url = https://git-tails.immerda.ch/chutney + branch = feature/tails_test_suite +[submodule "submodules/mirror-pool-dispatcher"] + path = submodules/mirror-pool-dispatcher + url = https://git-tails.immerda.ch/mirror-pool-dispatcher +[submodule "submodules/aufs4-standalone"] + path = submodules/aufs4-standalone + url = https://github.com/sfjro/aufs4-standalone.git diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..94a9ed024d3859793618152ea559a168bbcbb5e2 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Changelog b/Changelog new file mode 120000 index 0000000000000000000000000000000000000000..d526672ce2c5ef5c3975be46da86abfdecc43ffb --- /dev/null +++ b/Changelog @@ -0,0 +1 @@ +debian/changelog \ No newline at end of file diff --git a/HACKING.mdwn b/HACKING.mdwn new file mode 120000 index 0000000000000000000000000000000000000000..c1c40d556dcafb10d316118470fc58748ed2559e --- /dev/null +++ b/HACKING.mdwn @@ -0,0 +1 @@ +wiki/src/contribute/how/code/HACKING.mdwn \ No newline at end of file diff --git a/README b/README new file mode 120000 index 0000000000000000000000000000000000000000..4baf2281ff969405a2fa5dd15340f4085698a97c --- /dev/null +++ b/README @@ -0,0 +1 @@ +doc/README \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000000000000000000000000000000000..97e83ab8d7a465220968872bc5f8c2fcfc9ea470 --- /dev/null +++ b/Rakefile @@ -0,0 +1,659 @@ +# -*- coding: utf-8 -*- +# -*- mode: ruby -*- +# vi: set ft=ruby : +# +# Tails: The Amnesic Incognito Live System +# Copyright © 2012 Tails developers +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'date' +require 'libvirt' +require 'open3' +require 'rbconfig' +require 'uri' + +require_relative 'vagrant/lib/tails_build_settings' + +# Path to the directory which holds our Vagrantfile +VAGRANT_PATH = File.expand_path('../vagrant', __FILE__) + +# Branches that are considered 'stable' (used to select SquashFS compression) +STABLE_BRANCH_NAMES = ['stable', 'testing'] + +EXPORTED_VARIABLES = [ + 'MKSQUASHFS_OPTIONS', + 'APT_SNAPSHOTS_SERIALS', + 'TAILS_BUILD_FAILURE_RESCUE', + 'TAILS_DATE_OFFSET', + 'TAILS_MERGE_BASE_BRANCH', + 'TAILS_OFFLINE_MODE', + 'TAILS_PROXY', + 'TAILS_PROXY_TYPE', + 'TAILS_RAM_BUILD', + 'GIT_COMMIT', + 'GIT_REF', + 'BASE_BRANCH_GIT_COMMIT', +] +ENV['EXPORTED_VARIABLES'] = EXPORTED_VARIABLES.join(' ') + +EXTERNAL_HTTP_PROXY = ENV['http_proxy'] + +# In-VM proxy URL +INTERNAL_HTTP_PROXY = "http://#{VIRTUAL_MACHINE_HOSTNAME}:3142" + +ENV['ARTIFACTS'] ||= '.' + +ENV['APT_SNAPSHOTS_SERIALS'] ||= '' + +class CommandError < StandardError + attr_reader :status, :stderr + + def initialize(message = nil, opts = {}) + opts[:status] ||= nil + opts[:stderr] ||= nil + @status = opts[:status] + @stderr = opts[:stderr] + super(message % {status: @status, stderr: @stderr}) + end +end + +def run_command(*args) + Process.wait Kernel.spawn(*args) + if $?.exitstatus != 0 + raise CommandError.new("command #{args} failed with exit status " + + "%{status}", status: $?.exitstatus) + end +end + +def capture_command(*args) + stdout, stderr, proc_status = Open3.capture3(*args) + if proc_status.exitstatus != 0 + raise CommandError.new("command #{args} failed with exit status " + + "%{status}: %{stderr}", + stderr: stderr, status: proc_status.exitstatus) + end + return stdout, stderr +end + +def git_helper(*args) + question = args.first.end_with?('?') + args.first.sub!(/\?$/, '') + status = 0 + stdout = '' + begin + stdout, _ = capture_command('auto/scripts/utils.sh', *args) + rescue CommandError => e + status = e.status + end + if question + return status == 0 + else + return stdout.chomp + end +end + +class VagrantCommandError < CommandError +end + +# Runs the vagrant command, letting stdout/stderr through. Throws an +# exception unless the vagrant command succeeds. +def run_vagrant(*args) + run_command('vagrant', *args, :chdir => './vagrant') +rescue CommandError => e + raise(VagrantCommandError, "'vagrant #{args}' command failed with exit " + + "status #{e.status}") +end + +# Runs the vagrant command, not letting stdout/stderr through, and +# returns [stdout, stderr, Preocess:Status]. +def capture_vagrant(*args) + capture_command('vagrant', *args, :chdir => './vagrant') +rescue CommandError => e + raise(VagrantCommandError, "'vagrant #{args}' command failed with exit " + + "status #{e.status}: #{e.stderr}") +end + +[:run_vagrant, :capture_vagrant].each do |m| + define_method "#{m}_ssh" do |*args| + method(m).call('ssh', '-c', *args, '--', '-q') + end +end + +def vagrant_ssh_config(key) + # Cache results + if $vagrant_ssh_config.nil? + $vagrant_ssh_config = capture_vagrant('ssh-config').first.split("\n") \ + .map { |line| line.strip.split(/\s+/, 2) } .to_h + # The path in the ssh-config output is quoted, which is not what + # is expected outside of a shell, so let's get rid of the quotes. + $vagrant_ssh_config['IdentityFile'].gsub!(/^"|"$/, '') + end + $vagrant_ssh_config[key] +end + +def current_vm_cpus + capture_vagrant_ssh('grep -c "^processor\s*:" /proc/cpuinfo').first.chomp.to_i +end + +def vm_state + out, _ = capture_vagrant('status') + status_line = out.split("\n")[2] + if status_line['not created'] + return :not_created + elsif status_line['shutoff'] + return :poweroff + elsif status_line['running'] + return :running + else + raise "could not determine VM state" + end +end + +def enough_free_host_memory_for_ram_build? + return false unless RbConfig::CONFIG['host_os'] =~ /linux/i + + begin + usable_free_mem = `free`.split[12].to_i + usable_free_mem > VM_MEMORY_FOR_RAM_BUILDS * 1024 + rescue + false + end +end + +def free_vm_memory + capture_vagrant_ssh('free').first.chomp.split[12].to_i +end + +def enough_free_vm_memory_for_ram_build? + free_vm_memory > BUILD_SPACE_REQUIREMENT * 1024 +end + +def enough_free_memory_for_ram_build? + if vm_state == :running + enough_free_vm_memory_for_ram_build? + else + enough_free_host_memory_for_ram_build? + end +end + +def is_release? + git_helper('git_on_a_tag?') +end + +def system_cpus + return nil unless RbConfig::CONFIG['host_os'] =~ /linux/i + + begin + File.read('/proc/cpuinfo').scan(/^processor\s+:/).count + rescue + nil + end +end + +task :parse_build_options do + options = [] + + # Default to in-memory builds if there is enough RAM available + options << 'ram' if enough_free_memory_for_ram_build? + + # Default to build using the in-VM proxy + options << 'vmproxy' + + # Default to fast compression on development branches + options << 'gzipcomp' unless is_release? + + # Default to the number of system CPUs when we can figure it out + cpus = system_cpus + options << "cpus=#{cpus}" if cpus + + options += ENV['TAILS_BUILD_OPTIONS'].split if ENV['TAILS_BUILD_OPTIONS'] + + options.uniq.each do |opt| + case opt + # Memory build settings + when 'ram' + ENV['TAILS_RAM_BUILD'] = '1' + when 'noram' + ENV['TAILS_RAM_BUILD'] = nil + # Bootstrap cache settings + # HTTP proxy settings + when 'extproxy' + abort "No HTTP proxy set, but one is required by TAILS_BUILD_OPTIONS. Aborting." unless EXTERNAL_HTTP_PROXY + ENV['TAILS_PROXY'] = EXTERNAL_HTTP_PROXY + ENV['TAILS_PROXY_TYPE'] = 'extproxy' + when 'vmproxy' + ENV['TAILS_PROXY'] = INTERNAL_HTTP_PROXY + ENV['TAILS_PROXY_TYPE'] = 'vmproxy' + when 'noproxy' + ENV['TAILS_PROXY'] = nil + ENV['TAILS_PROXY_TYPE'] = 'noproxy' + when 'offline' + ENV['TAILS_OFFLINE_MODE'] = '1' + # SquashFS compression settings + when 'gzipcomp' + ENV['MKSQUASHFS_OPTIONS'] = '-comp gzip -Xcompression-level 1' + if is_release? + raise 'We must use the default compression when building releases!' + end + when 'defaultcomp' + ENV['MKSQUASHFS_OPTIONS'] = nil + # Virtual hardware settings + when /machinetype=([a-zA-Z0-9_.-]+)/ + ENV['TAILS_BUILD_MACHINE_TYPE'] = $1 + when /cpus=(\d+)/ + ENV['TAILS_BUILD_CPUS'] = $1 + when /cpumodel=([a-zA-Z0-9_-]+)/ + ENV['TAILS_BUILD_CPU_MODEL'] = $1 + # Git settings + when 'ignorechanges' + ENV['TAILS_BUILD_IGNORE_CHANGES'] = '1' + when /dateoffset=([-+]\d+)/ + ENV['TAILS_DATE_OFFSET'] = $1 + # Developer convenience features + when 'keeprunning' + $keep_running = true + $force_cleanup = false + when 'forcecleanup' + $force_cleanup = true + $keep_running = false + when 'rescue' + $keep_running = true + ENV['TAILS_BUILD_FAILURE_RESCUE'] = '1' + # Jenkins + when 'mergebasebranch' + ENV['TAILS_MERGE_BASE_BRANCH'] = '1' + else + raise "Unknown Tails build option '#{opt}'" + end + end + + if ENV['TAILS_OFFLINE_MODE'] == '1' + if ENV['TAILS_PROXY'].nil? + abort "You must use a caching proxy when building offline" + end + end +end + +task :ensure_clean_repository do + git_status = `git status --porcelain` + unless git_status.empty? + if ENV['TAILS_BUILD_IGNORE_CHANGES'] + $stderr.puts <<-END_OF_MESSAGE.gsub(/^ /, '') + + You have uncommitted changes in the Git repository. They will + be ignored for the upcoming build: + #{git_status} + + END_OF_MESSAGE + else + $stderr.puts <<-END_OF_MESSAGE.gsub(/^ /, '') + + You have uncommitted changes in the Git repository. Due to limitations + of the build system, you need to commit them before building Tails: + #{git_status} + + If you don't care about those changes and want to build Tails nonetheless, + please add `ignorechanges` to the TAILS_BUILD_OPTIONS environment + variable. + + END_OF_MESSAGE + abort 'Uncommitted changes. Aborting.' + end + end +end + +def list_artifacts + user = vagrant_ssh_config('User') + stdout = capture_vagrant_ssh("find '/home/#{user}/amnesia/' -maxdepth 1 " + + "-name 'tails-amd64-*' " + + "-o -name tails-build-env.list").first + stdout.split("\n") +rescue VagrantCommandError + return Array.new +end + +def remove_artifacts + list_artifacts.each do |artifact| + run_vagrant_ssh("sudo rm -f '#{artifact}'") + end +end + +task :ensure_clean_home_directory => ['vm:up'] do + remove_artifacts +end + +task :validate_http_proxy do + if ENV['TAILS_PROXY'] + proxy_host = URI.parse(ENV['TAILS_PROXY']).host + + if proxy_host.nil? + ENV['TAILS_PROXY'] = nil + $stderr.puts "Ignoring invalid HTTP proxy." + return + end + + if ['localhost', '[::1]'].include?(proxy_host) || proxy_host.start_with?('127.0.0.') + abort 'Using an HTTP proxy listening on the loopback is doomed to fail. Aborting.' + end + + $stderr.puts "Using HTTP proxy: #{ENV['TAILS_PROXY']}" + else + $stderr.puts "No HTTP proxy set." + end +end + +task :validate_git_state do + if git_helper('git_in_detached_head?') && not(git_helper('git_on_a_tag?')) + raise 'We are in detached head but the current commit is not tagged' + end +end + +task :setup_environment => ['validate_git_state'] do + ENV['GIT_COMMIT'] ||= git_helper('git_current_commit') + ENV['GIT_REF'] ||= git_helper('git_current_head_name') + if on_jenkins? + jenkins_branch = (ENV['GIT_BRANCH'] || '').sub(/^origin\//, '') + if not(is_release?) && jenkins_branch != ENV['GIT_REF'] + raise "We expected to build the Git ref '#{ENV['GIT_REF']}', but GIT_REF in the environment says '#{jenkins_branch}'. Aborting!" + end + end + + ENV['BASE_BRANCH_GIT_COMMIT'] ||= git_helper('git_base_branch_head') + ['GIT_COMMIT', 'GIT_REF', 'BASE_BRANCH_GIT_COMMIT'].each do |var| + if ENV[var].empty? + raise "Variable '#{var}' is empty, which should not be possible: " + + "either validate_git_state is buggy or the 'origin' remote " + + "does not point to the official Tails Git repository." + end + end +end + +task :maybe_clean_up_builder_vms do + clean_up_builder_vms if $force_cleanup +end + +desc 'Build Tails' +task :build => ['parse_build_options', 'ensure_clean_repository', 'maybe_clean_up_builder_vms', 'validate_git_state', 'setup_environment', 'validate_http_proxy', 'vm:up', 'ensure_clean_home_directory'] do + + begin + if ENV['TAILS_RAM_BUILD'] && not(enough_free_memory_for_ram_build?) + $stderr.puts <<-END_OF_MESSAGE.gsub(/^ /, '') + + The virtual machine is not currently set with enough memory to + perform an in-memory build. Either remove the `ram` option from + the TAILS_BUILD_OPTIONS environment variable, or shut the + virtual machine down using `rake vm:halt` before trying again. + + END_OF_MESSAGE + abort 'Not enough memory for the virtual machine to run an in-memory build. Aborting.' + end + + if ENV['TAILS_BUILD_CPUS'] && current_vm_cpus != ENV['TAILS_BUILD_CPUS'].to_i + $stderr.puts <<-END_OF_MESSAGE.gsub(/^ /, '') + + The virtual machine is currently running with #{current_vm_cpus} + virtual CPU(s). In order to change that number, you need to + stop the VM first, using `rake vm:halt`. Otherwise, please + adjust the `cpus` options accordingly. + + END_OF_MESSAGE + abort 'The virtual machine needs to be reloaded to change the number of CPUs. Aborting.' + end + + exported_env = EXPORTED_VARIABLES.select { |k| ENV[k] }. + collect { |k| "#{k}='#{ENV[k]}'" }.join(' ') + run_vagrant_ssh("#{exported_env} build-tails") + + artifacts = list_artifacts + raise 'No build artifacts were found!' if artifacts.empty? + user = vagrant_ssh_config('User') + hostname = vagrant_ssh_config('HostName') + key_file = vagrant_ssh_config('IdentityFile') + $stderr.puts "Retrieving artifacts from Vagrant build box." + run_vagrant_ssh( + "sudo chown #{user} " + artifacts.map { |a| "'#{a}'" } .join(' ') + ) + fetch_command = [ + 'scp', + '-i', key_file, + # We need this since the user will not necessarily have a + # known_hosts entry. It is safe since an attacker must + # compromise libvirt's network config or the user running the + # command to modify the #{hostname} below. + '-o', 'StrictHostKeyChecking=no', + '-o', 'UserKnownHostsFile=/dev/null', + ] + fetch_command += artifacts.map { |a| "#{user}@#{hostname}:#{a}" } + fetch_command << ENV['ARTIFACTS'] + run_command(*fetch_command) + clean_up_builder_vms unless $keep_running + ensure + clean_up_builder_vms if $force_cleanup + end +end + +def has_box? + not(capture_vagrant('box', 'list').grep(/^#{box_name}\s+\(libvirt,/).empty?) +end + +def domain_name + "#{box_name}_default" +end + +def clean_up_builder_vms + $virt = Libvirt::open("qemu:///system") + + clean_up_domain = Proc.new do |domain| + next if domain.nil? + domain.destroy if domain.active? + domain.undefine + begin + $virt + .lookup_storage_pool_by_name('default') + .lookup_volume_by_name("#{domain.name}.img") + .delete + rescue Libvirt::RetrieveError + # Expected if the pool or disk does not exist + end + end + + # Let's ensure that the VM we are about to create is cleaned up ... + previous_domain = $virt.list_all_domains.find { |d| d.name == domain_name } + if previous_domain && previous_domain.active? + begin + run_vagrant_ssh("mountpoint -q /var/cache/apt-cacher-ng") + rescue VagrantCommandError + # Nothing to unmount. + else + run_vagrant_ssh("sudo systemctl stop apt-cacher-ng.service") + run_vagrant_ssh("sudo umount /var/cache/apt-cacher-ng") + run_vagrant_ssh("sudo sync") + end + end + clean_up_domain.call(previous_domain) + + # ... and the same for any residual VM based on another box (=> + # another domain name) that Vagrant still keeps track of. + old_domain = + begin + old_domain_uuid = + open('vagrant/.vagrant/machines/default/libvirt/id', 'r') { |f| f.read } + .strip + $virt.lookup_domain_by_uuid(old_domain_uuid) + rescue Errno::ENOENT, Libvirt::RetrieveError + # Expected if we don't have vagrant/.vagrant, or if the VM was + # undefined for other reasons (e.g. manually). + nil + end + clean_up_domain.call(old_domain) + + # We could use `vagrant destroy` here but due to vagrant-libvirt's + # upstream issue #746 we then risk losing the apt-cacher-ng data. + # Since we essentially implement `vagrant destroy` without this bug + # above, but in a way so it works even if `vagrant/.vagrant` does + # not exist, let's just do what is safest, i.e. avoiding `vagrant + # destroy`. For details, see the upstream issue: + # https://github.com/vagrant-libvirt/vagrant-libvirt/issues/746 + FileUtils.rm_rf('vagrant/.vagrant') +ensure + $virt.close +end + +desc "Remove all libvirt volumes named tails-builder-* (run at your own risk!)" +task :clean_up_libvirt_volumes do + $virt = Libvirt::open("qemu:///system") + begin + pool = $virt.lookup_storage_pool_by_name('default') + rescue Libvirt::RetrieveError + # Expected if the pool does not exist + else + for disk in pool.list_volumes do + if /^tails-builder-/.match(disk) + begin + pool.lookup_volume_by_name(disk).delete + rescue Libvirt::RetrieveError + # Expected if the disk does not exist + end + end + end + ensure + $virt.close + end +end + +def on_jenkins? + !!ENV['JENKINS_URL'] +end + +desc 'Test Tails' +task :test do + args = ARGV.drop_while { |x| x == 'test' || x == '--' } + if on_jenkins? + args += ['--'] unless args.include? '--' + if not(is_release?) + args += ['--tag', '~@fragile'] + end + base_branch = git_helper('base_branch') + if git_helper('git_only_doc_changes_since?', "origin/#{base_branch}") then + args += ['--tag', '@doc'] + end + end + run_command('./run_test_suite', *args) +end + +desc 'Clean up all build related files' +task :clean_all => ['vm:destroy', 'basebox:clean_all'] + +namespace :vm do + desc 'Start the build virtual machine' + task :up => ['parse_build_options', 'validate_http_proxy', 'setup_environment', 'basebox:create'] do + case vm_state + when :not_created + clean_up_builder_vms + end + begin + run_vagrant('up') + rescue VagrantCommandError => e + clean_up_builder_vms if $force_cleanup + raise e + end + end + + desc 'SSH into the builder VM' + task :ssh do + run_vagrant('ssh') + end + + desc 'Stop the build virtual machine' + task :halt do + run_vagrant('halt') + end + + desc 'Re-run virtual machine setup' + task :provision => ['parse_build_options', 'validate_http_proxy', 'setup_environment'] do + run_vagrant('provision') + end + + desc "Destroy build virtual machine (clean up all files except the vmproxy's apt-cacher-ng data)" + task :destroy do + clean_up_builder_vms + end +end + +namespace :basebox do + + desc 'Create and import the base box unless already done' + task :create do + next if has_box? + $stderr.puts <<-END_OF_MESSAGE.gsub(/^ /, '') + + This is the first time we are using this Vagrant base box so we + will have to bootstrap by building it from scratch. This will + take around 20 minutes (depending on your hardware) plus the + time needed for downloading around 250 MiB of Debian packages. + + END_OF_MESSAGE + box_dir = VAGRANT_PATH + '/definitions/tails-builder' + run_command("#{box_dir}/generate-tails-builder-box.sh") + # Let's use an absolute path since run_vagrant changes the working + # directory but File.delete doesn't + box_path = "#{box_dir}/#{box_name}.box" + run_vagrant('box', 'add', '--name', box_name, box_path) + File.delete(box_path) + end + + def basebox_date(box) + Date.parse(/^tails-builder-[^-]+-[^-]+-(\d{8})/.match(box)[1]) + end + + def baseboxes + capture_vagrant('box', 'list').first.lines + .grep(/^tails-builder-.*/) + .map { |x| x.chomp.sub(/\s.*$/, '') } + end + + def clean_up_basebox(box) + run_vagrant('box', 'remove', '--force', box) + begin + $virt = Libvirt::open("qemu:///system") + $virt + .lookup_storage_pool_by_name('default') + .lookup_volume_by_name("#{box}_vagrant_box_image_0.img") + .delete + rescue Libvirt::RetrieveError + # Expected if the pool or disk does not exist + ensure + $virt.close + end + end + + desc 'Remove all base boxes' + task :clean_all do + baseboxes.each { |box| clean_up_basebox(box) } + end + + desc 'Remove all base boxes older than six months' + task :clean_old do + boxes = baseboxes + # We always want to keep the newest basebox + boxes.sort! { |a, b| basebox_date(a) <=> basebox_date(b) } + boxes.pop + boxes.each do |box| + if basebox_date(box) < Date.today - 365.0/2.0 + clean_up_basebox(box) + end + end + end +end diff --git a/auto/build b/auto/build new file mode 100755 index 0000000000000000000000000000000000000000..7b2a351c185d41cc43258d8f6a596d16e61f1519 --- /dev/null +++ b/auto/build @@ -0,0 +1,156 @@ +#!/bin/bash + +set -e +set -u +set -x + +. "$(dirname $0)/scripts/utils.sh" + +# get $BUILD_BASENAME +. tmp/build_environment + +umask 022 + +### Clone all output, from this point on, to the log file + +BUILD_LOG="${BUILD_BASENAME}.buildlog" +exec > >(tee -a "$BUILD_LOG") +trap "kill -9 $! 2>/dev/null" EXIT HUP INT QUIT TERM +exec 2> >(tee -a "$BUILD_LOG" >&2) +trap "kill -9 $! 2>/dev/null" EXIT HUP INT QUIT TERM + +### functions + +print_iso_size () { + local isofile="$1" + [ -f "$isofile" ] || return 23 + size=$(stat --printf='%s' "$isofile") + echo "I: The ISO is ${size} bytes large." +} + +### Main + +# we require building from git +git rev-parse --is-inside-work-tree &> /dev/null \ + || fatal "${PWD} is not a Git tree." + +. config/amnesia +if [ -e config/amnesia.local ] ; then + . config/amnesia.local +fi + +# a clean starting point +rm -rf cache/stages_rootfs + +# get LB_BINARY_IMAGES +. config/binary + +# get LB_ARCHITECTURE and LB_DISTRIBUTION +. config/bootstrap + +# save variables that are needed by chroot_local-hooks +echo "KERNEL_VERSION=${KERNEL_VERSION}" \ + >> config/chroot_local-includes/usr/share/tails/build/variables +echo "KERNEL_SOURCE_VERSION=${KERNEL_SOURCE_VERSION}" \ + >> config/chroot_local-includes/usr/share/tails/build/variables +echo "LB_DISTRIBUTION=${LB_DISTRIBUTION}" >> config/chroot_local-includes/usr/share/tails/build/variables +echo "POTFILES_DOT_IN='$( + /bin/grep -E --no-filename '[^ #]*\.in$' po/POTFILES.in \ + | sed -e 's,^config/chroot_local-includes,,' | tr "\n" ' ' + )'" \ + >> config/chroot_local-includes/usr/share/tails/build/variables + +# fix permissions on some source files that will be copied as is to the chroot. +# they may be wrong, e.g. if the Git repository was cloned with a strict umask. +chown 0:0 config/chroot_local-includes/etc/resolv.conf +chmod -R go+rX config/binary_local-includes/ +chmod -R go+rX config/chroot_local-includes/etc +chmod 0440 config/chroot_local-includes/etc/sudoers.d/* +chmod go+rX config/chroot_local-includes/lib +chmod go+rX config/chroot_local-includes/lib/live +chmod -R go+rx config/chroot_local-includes/lib/live/config +chmod go+rX config/chroot_local-includes/lib/live/mount +chmod -R go+rX config/chroot_local-includes/lib/systemd +chmod go+rX config/chroot_local-includes/live +chmod -R go+rX config/chroot_local-includes/usr +chmod -R go+rx config/chroot_local-includes/usr/local/bin +chmod -R go+rx config/chroot_local-includes/usr/local/sbin +chmod -R go+rX config/chroot_local-includes/usr/share/doc +chmod -R go+rX config/chroot_local-includes/var +chmod -R go+rX config/chroot_apt +chmod -R go+rX config/chroot_sources + +# normalize file timestamps +find \ + config/binary_local-includes \ + config/chroot_local-includes \ + wiki/src \ + -exec touch --date="@$SOURCE_DATE_EPOCH" '{}' \; + +# build the image + +# we need /debootstrap/deburis to build a manifest of used packages: +DEBOOTSTRAP_OPTIONS="${DEBOOTSTRAP_OPTIONS:-} --keep-debootstrap-dir" + +# we're not ready for merged-/usr yet: Debian#843461, Tails#11903 +DEBOOTSTRAP_OPTIONS="${DEBOOTSTRAP_OPTIONS:-} --no-merged-usr" + +# use our own APT repository's key: +DEBOOTSTRAP_GNUPG_HOMEDIR=$(mktemp -d) +gpg --homedir "$DEBOOTSTRAP_GNUPG_HOMEDIR" \ + --no-tty \ + --import config/chroot_sources/tails.chroot.gpg +DEBOOTSTRAP_GNUPG_KEYRING="$DEBOOTSTRAP_GNUPG_HOMEDIR/pubring.kbx" +[ -e "$DEBOOTSTRAP_GNUPG_KEYRING" ] \ + || fatal "No debootstrap GnuPG keyring was created." +DEBOOTSTRAP_OPTIONS="$DEBOOTSTRAP_OPTIONS --keyring=$DEBOOTSTRAP_GNUPG_KEYRING" + +export DEBOOTSTRAP_OPTIONS + +: ${MKSQUASHFS_OPTIONS:='-comp xz -Xbcj x86 -b 1024K -Xdict-size 1024K -no-exports'} +MKSQUASHFS_OPTIONS="${MKSQUASHFS_OPTIONS} -mem 512M -wildcards -ef chroot/usr/share/tails/build/mksquashfs-excludes" +export MKSQUASHFS_OPTIONS + +# build the doc wiki +./build-website + +# refresh translations of our programs +./refresh-translations || fatal "refresh-translations failed ($?)." + +BUILD_ISO_FILENAME="${BUILD_BASENAME}.iso" +BUILD_MANIFEST="${BUILD_BASENAME}.build-manifest" +BUILD_APT_SOURCES="${BUILD_BASENAME}.apt-sources" +BUILD_PACKAGES="${BUILD_BASENAME}.packages" +BUILD_USB_IMAGE_FILENAME="${BUILD_BASENAME}.img" + +( + echo "Mirrors:" + apt-mirror debian + apt-mirror debian-security + apt-mirror torproject + echo "Additional sources:" + cat config/chroot_sources/*.chroot +) > "$BUILD_APT_SOURCES" + +echo "I: Building ISO image ${BUILD_ISO_FILENAME}..." +time lb build noauto ${@} +[ -e binary.iso ] || fatal "lb build failed ($?)." + +echo "I: ISO image was successfully created" +print_iso_size binary.iso + +echo "I: Hybriding it..." +isohybrid $AMNESIA_ISOHYBRID_OPTS binary.iso || fatal "isohybrid failed" +print_iso_size binary.iso +truncate -s %2048 binary.iso +print_iso_size binary.iso + +echo "I: Renaming generated files..." +mv -i binary.iso "${BUILD_ISO_FILENAME}" +mv -i binary.packages "${BUILD_PACKAGES}" + +echo "I: Generating build manifest..." +generate-build-manifest chroot/debootstrap "${BUILD_MANIFEST}" + +echo "I: Creating USB image ${BUILD_USB_IMAGE_FILENAME}..." +create-usb-image-from-iso "${BUILD_ISO_FILENAME}" diff --git a/auto/clean b/auto/clean new file mode 100755 index 0000000000000000000000000000000000000000..55607bd77327c7844fe1674c1f45c0b10e148c3b --- /dev/null +++ b/auto/clean @@ -0,0 +1,40 @@ +#!/bin/sh + +set -e +set -u +set -x + +for dir in chroot/{dev/pts,proc,sys,var/lib/dpkg} ; do + if mountpoint -q "$dir" ; then + umount "$dir" + fi +done + +lb clean noauto ${@} + +# rm -f build-*.log + +# Remove generated files +rm -f config/binary config/bootstrap config/chroot config/common config/source + +# Remove empty directories in config tree +if ls config/*/ > /dev/null 2>&1 ; then + rmdir --ignore-fail-on-non-empty config/*/ +fi + +# files copied or created in the config stage +rm -f config/chroot_local-includes/etc/amnesia/environment +rm -f config/chroot_local-includes/etc/amnesia/version +rm -f config/chroot_local-includes/usr/share/doc/amnesia/Changelog +for list in config/chroot_local-packageslists/*.list ; do + if [ "$list" != 'config/chroot_local-packageslists/tails-common.list' ]; then + rm -f "$list" + fi +done + +# files copied or created in the build stage +rm -f config/chroot_local-includes/usr/share/tails/build/variables + +# static wiki +rm -rf config/chroot_local-includes/usr/share/doc/tails/website wiki/src/.ikiwiki +find wiki/src -name *.pot -exec rm {} \; diff --git a/auto/config b/auto/config new file mode 100755 index 0000000000000000000000000000000000000000..bb8f6e2fc25e38a9b98b802f22989fbb25aba98b --- /dev/null +++ b/auto/config @@ -0,0 +1,214 @@ +#! /bin/sh +# automatically run by "lb config" + +set -e +set -u +set -x + +. "$(dirname $0)/scripts/utils.sh" + +. config/amnesia +if [ -e config/amnesia.local ] ; then + . config/amnesia.local +fi + +if [ -n "${SOURCE_DATE_EPOCH}" ]; then + CURRENT_EPOCH="$(date --utc +%s)" + if [ "${SOURCE_DATE_EPOCH}" -gt "${CURRENT_EPOCH}" ]; then + fatal "SOURCE_DATE_EPOCH is set before the current time. Exiting." + fi +else + fatal "SOURCE_DATE_EPOCH is not set. Exiting." +fi + +# get git branch or tag so we can set the basename appropriately, i.e.: +# * if we build from a tag: tails-$ARCH-$TAG.iso +# * otherwise: tails-$ARCH-$BRANCH-$VERSION-$TIME-$COMMIT.iso +GIT_BRANCH="$(git_current_branch)" +if [ -n "${GIT_BRANCH}" ]; then + CLEAN_GIT_BRANCH=$(echo "$GIT_BRANCH" | sed 's,/,_,g') + GIT_SHORT_ID="$(git_current_commit --short)" + BUILD_BASENAME="tails-amd64-${CLEAN_GIT_BRANCH}-${AMNESIA_VERSION}-${AMNESIA_NOW}-${GIT_SHORT_ID}" +else + if git_on_a_tag; then + CLEAN_GIT_TAG=$(git_current_tag | tr '/-' '_~') + BUILD_BASENAME="tails-amd64-${CLEAN_GIT_TAG}" + else + # this shouldn't reasonably happen (e.g. only if you checkout a + # tag, remove the tag and then build) + fatal "Neither a Git branch nor a tag, exiting." + fi +fi + +GIT_BASE_BRANCH=$(base_branch) \ + || fatal "GIT_BASE_BRANCH could not be guessed." + +if [ "${TAILS_MERGE_BASE_BRANCH:-}" = 1 ] && \ + ! git_on_a_tag && [ "$GIT_BRANCH" != "$GIT_BASE_BRANCH" ] ; then + [ -n "${BASE_BRANCH_GIT_COMMIT}" ] \ + || fatal "Base branch's top commit is not set." + + echo "I: Merging base branch ${GIT_BASE_BRANCH}" \ + "(at commit ${BASE_BRANCH_GIT_COMMIT})..." + faketime -f "${SOURCE_DATE_FAKETIME}" \ + git merge --no-edit "${BASE_BRANCH_GIT_COMMIT}" \ + || fatal "Failed to merge base branch." + git submodule update --init + + # Adjust BUILD_BASENAME to embed the base branch name and its top commit + CLEAN_GIT_BASE_BRANCH=$(echo "$GIT_BASE_BRANCH" | sed 's,/,_,g') + GIT_BASE_BRANCH_SHORT_ID=$(git rev-parse --verify --short "${BASE_BRANCH_GIT_COMMIT}") + [ -n "${GIT_BASE_BRANCH_SHORT_ID}" ] \ + || fatal "Base branch's top commit short ID could not be guessed." + BUILD_BASENAME="${BUILD_BASENAME}+${CLEAN_GIT_BASE_BRANCH}" + BUILD_BASENAME="${BUILD_BASENAME}@${GIT_BASE_BRANCH_SHORT_ID}" +fi + +# save variables that lb build needs +mkdir -p tmp +echo "BUILD_BASENAME='${BUILD_BASENAME}'" > tmp/build_environment + +# sanity checks +if grep -qs -E '^Pin:\s+release\s+.*a=' config/chroot_apt/preferences ; then + fatal "Found unsupported a= syntax in config/chroot_apt/preferences," \ + "use n= instead. Exiting." +fi +if grep -qs -E '^Pin:\s+release\s+.*o=Debian Backports' \ + config/chroot_apt/preferences ; then + fatal "Found unsupported 'o=Debian Backports' syntax," \ + "in config/chroot_apt/preferences. Use o=Debian instead. Exiting." +fi +if [ $(dpkg --print-architecture) != amd64 ] ; then + fatal "Only amd64 build systems are supported" +fi + +# init variables +RUN_LB_CONFIG="lb config noauto" + +# init config/ with defaults for the target distribution +$RUN_LB_CONFIG --distribution stretch ${@} + +# set up everything for time-based snapshots: +if [ -n "${APT_SNAPSHOTS_SERIALS:-}" ]; then + echo "I: Fixing 'latest' APT snapshots serials to: '${APT_SNAPSHOTS_SERIALS}'." + apt-snapshots-serials prepare-build "${APT_SNAPSHOTS_SERIALS}" +else + apt-snapshots-serials prepare-build +fi +# record what APT snapshots this build is going to use, so that one +# can try to reproduce it more reliably +JENKINS_ENV_PROPERTIES=tails-build-env.list +echo "# This file is in Java property file format" >> "$JENKINS_ENV_PROPERTIES" +echo "# (https://en.wikipedia.org/wiki/.properties)" >> "$JENKINS_ENV_PROPERTIES" +echo "APT_SNAPSHOTS_SERIALS = $(apt-snapshots-serials cat-json tmp/APT_snapshots.d)" \ + >> "$JENKINS_ENV_PROPERTIES" + +DEBIAN_MIRROR="$(apt-mirror debian)" +DEBIAN_SECURITY_MIRROR="$(apt-mirror debian-security)" +TORPROJECT_MIRROR="$(apt-mirror torproject)" + +[ -n "$DEBIAN_MIRROR" ] || fatal "\$DEBIAN_MIRROR is empty" +[ -n "$DEBIAN_SECURITY_MIRROR" ] || fatal "\$DEBIAN_SECURITY_MIRROR is empty" +[ -n "$TORPROJECT_MIRROR" ] || fatal "\$TORPROJECT_MIRROR is empty" + +perl -pi \ + -E \ + "s|^(deb(?:-src)?\s+)https?://ftp[.]us[.]debian[.]org/debian/?(\s+)|\$1$DEBIAN_MIRROR\$2| ; \ + s|^(deb(?:-src)?\s+)https?://deb[.]torproject[.]org/torproject[.]org/?(\s+)|\$1$TORPROJECT_MIRROR\$2|" \ + config/chroot_sources/*.chroot \ + || fatal "APT mirror substitution failed with exit code $?" + +# set Amnesia's general options +$RUN_LB_CONFIG \ + --verbose \ + --apt-recommends false \ + --architecture amd64 \ + --backports false \ + --binary-images iso \ + --binary-indices false \ + --cache false \ + --cache-indices false \ + --cache-packages false \ + --cache-stages false \ + --checksums none \ + --bootappend-live "${AMNESIA_APPEND}" \ + --bootstrap debootstrap \ + --bootstrap-config tails-build-jessie \ + --archive-areas "main contrib non-free" \ + --includes none \ + --iso-application="The Amnesic Incognito Live System" \ + --iso-publisher="https://tails.boum.org/" \ + --iso-volume="TAILS ${AMNESIA_FULL_VERSION}" \ + --linux-flavours amd64 \ + --memtest none \ + --mirror-binary "$DEBIAN_MIRROR" \ + --mirror-bootstrap "$DEBIAN_MIRROR" \ + --mirror-chroot "$DEBIAN_MIRROR" \ + --mirror-binary-security "$DEBIAN_SECURITY_MIRROR" \ + --mirror-chroot-security "$DEBIAN_SECURITY_MIRROR" \ + --packages-lists="standard" \ + --tasks="standard" \ + --linux-packages="linux-image-${KERNEL_VERSION}" \ + --syslinux-menu vesamenu \ + --syslinux-splash data/splash.png \ + --syslinux-timeout 4 \ + --initramfs=live-boot \ + ${@} + +install -d config/chroot_local-includes/etc/amnesia/ + +# environment +TAILS_WIKI_SUPPORTED_LANGUAGES="$(ikiwiki-supported-languages ikiwiki.setup)" +[ -n "$TAILS_WIKI_SUPPORTED_LANGUAGES" ] \ + || fatal "\$TAILS_WIKI_SUPPORTED_LANGUAGES is empty" +echo "TAILS_WIKI_SUPPORTED_LANGUAGES='${TAILS_WIKI_SUPPORTED_LANGUAGES}'" \ + >> config/chroot_local-includes/etc/amnesia/environment + +# version +echo "${AMNESIA_FULL_VERSION}" > config/chroot_local-includes/etc/amnesia/version +if git rev-list HEAD 2>&1 >/dev/null; then + git rev-list HEAD | head -n 1 >> config/chroot_local-includes/etc/amnesia/version +fi +echo "live-build: `dpkg-query -W -f='${Version}\n' live-build`" \ + >> config/chroot_local-includes/etc/amnesia/version +# os-release +cat >> config/chroot_local-includes/etc/os-release <> config/chroot_local-includes/etc/os-release +fi + +# changelog +cp debian/changelog config/chroot_local-includes/usr/share/doc/amnesia/Changelog + +# custom APT sources +tails-custom-apt-sources > config/chroot_sources/tails.chroot \ + || fatal "tails-custom-apt-sources failed with exit code $?" + +# tails-transform-mirror-url and its dependencies +install -m 0755 \ + submodules/mirror-pool-dispatcher/bin/tails-transform-mirror-url \ + config/chroot_local-includes/usr/local/bin/ +install -m 0755 -d config/chroot_local-includes/usr/local/lib/nodejs +install -m 0755 \ + submodules/mirror-pool-dispatcher/lib/js/mirror-dispatcher.js \ + config/chroot_local-includes/usr/local/lib/nodejs/ + +# aufs4-standalone +rm -rf config/chroot_local-includes/usr/src/aufs4-standalone +cp -a submodules/aufs4-standalone config/chroot_local-includes/usr/src/ + +# custom debootstrap script, setting some APT magic to log downloads: +patch \ + --follow-symlinks \ + --output=/usr/share/debootstrap/scripts/tails-build-jessie \ + /usr/share/debootstrap/scripts/jessie \ + data/debootstrap/scripts/jessie.patch +sed -i "s,%%topdir%%,$(pwd)," /usr/share/debootstrap/scripts/tails-build-jessie + +# Make the python library available in Tails +install -d -m 2777 config/chroot_local-includes/tmp/ +cp -r submodules/pythonlib config/chroot_local-includes/tmp/ diff --git a/auto/scripts/apt-mirror b/auto/scripts/apt-mirror new file mode 100755 index 0000000000000000000000000000000000000000..75a6198f2532678f5e31a56a861d74c62ba12f65 --- /dev/null +++ b/auto/scripts/apt-mirror @@ -0,0 +1,72 @@ +#!/bin/bash + +set -e +set -u + +. "$(dirname $0)/utils.sh" + +ARCHIVE="$1" + +output_tagged_snapshot() { + local archive="$1" + local tag="$2" + local snapshot=$(branch_name_to_suite "$tag") + echo "http://tagged.snapshots.deb.tails.boum.org/$snapshot/$archive" +} + +output_time_based_snapshot() { + local archive="$1" + local serial="$2" + echo "http://time-based.snapshots.deb.tails.boum.org/$archive/$serial" +} + +### Sanity checks + +[ -n "$ARCHIVE" ] || exit 1 + +### Main + +SERIAL=$(cat "config/APT_snapshots.d/$ARCHIVE/serial") +RESOLVED_SERIAL=$(cat "tmp/APT_snapshots.d/$ARCHIVE/serial") +BASE_BRANCH=$(base_branch) +CURRENT_BRANCH=$(git_current_branch) + +if [ "$BASE_BRANCH" = stable ] \ + || [ "$BASE_BRANCH" = testing ] \ + || [ "$CURRENT_BRANCH" = feature/buster ] \ + || ( git_on_a_tag && [ "$BASE_BRANCH" = feature/buster ] ) \ +then + case "$ARCHIVE" in + debian-security) + [ "$SERIAL" = latest ] \ + || fatal "APT snapshots are frozen for the debian-security archive," \ + "which should happen neither on feature/buster nor on" \ + "a branch based on $BASE_BRANCH" + ;; + *) + [ "$SERIAL" != latest ] \ + || fatal "APT snapshots are not frozen for the $ARCHIVE archive," \ + "which should happen neither on feature/buster nor on" \ + "a branch based on $BASE_BRANCH" + esac + if version_was_released "$(version_in_changelog)"; then + git_on_a_tag \ + || fatal "Not building from a tag, but last version in changelog" \ + "was released" + output_tagged_snapshot "$ARCHIVE" "$(version_in_changelog)" + else + if [ "$BASE_BRANCH" = stable ] ; then + version_was_released "$(previous_version_in_changelog)" \ + || fatal "None of the two last version in changelog were released" + fi + output_time_based_snapshot "$ARCHIVE" "$RESOLVED_SERIAL" + fi +else + if [ "$BASE_BRANCH" = devel ] || [ "$CURRENT_BRANCH" = feature/buster ]; then + if [ "$SERIAL" != latest ]; then + fatal "APT snapshots are frozen, which should happen neither on" \ + "feature/buster nor on a branch based on the devel one" + fi + fi + output_time_based_snapshot "$ARCHIVE" "$RESOLVED_SERIAL" +fi diff --git a/auto/scripts/apt-snapshots-serials b/auto/scripts/apt-snapshots-serials new file mode 100755 index 0000000000000000000000000000000000000000..9afa6c8bfc0a32aeaca02debaedbd8d3602f66d2 --- /dev/null +++ b/auto/scripts/apt-snapshots-serials @@ -0,0 +1,120 @@ +#!/bin/bash +set -e +set -u + +set -o pipefail + +BASE_URL=http://time-based.snapshots.deb.tails.boum.org/ +CONFIG=config/APT_snapshots.d +SERIAL_ONLY= +APT_SNAPSHOTS_SERIALS= +FREEZE_EXCEPTIONS=debian-security + +get_latest_serial() { + origin=$1 + wget -q $BASE_URL/$origin/project/trace/$origin -O - \ + | awk -F': ' '/^Archive serial: / {print $2}' +} + +if [ $# -eq 0 ]; then + action="cat" + ORIGINS="$(cd ${CONFIG}; ls -d *)" +else + action="${1}" + shift + if [ "${1:-}" = --print-serials-only ]; then + SERIAL_ONLY=yes + shift + fi + if [ "${1:-}" = --freeze-debian-security ]; then + FREEZE_EXCEPTIONS= + shift + fi + case "$action" in + prepare-build) + if [ $# -eq 1 ]; then + APT_SNAPSHOTS_SERIALS="${1}" + shift + fi + ;; + cat-json) + if [ $# -eq 1 ]; then + CONFIG="${1}" + shift + fi + ;; + cat|get-latest|freeze|thaw) + if [ $# -eq 0 ]; then + ORIGINS="$(cd ${CONFIG}; ls -d *)" + else + ORIGINS="${@}" + fi + ;; + esac +fi + +case "$action" in + cat) + for origin in $ORIGINS; do + [ -z "${SERIAL_ONLY}" ] && echo -n "$origin: " + cat "$CONFIG/$origin/serial" + done + ;; + cat-json) + $(dirname "$0")/apt-snapshots-serials-cat-json "$CONFIG" + ;; + get-latest) + for origin in $ORIGINS; do + [ -z "${SERIAL_ONLY}" ] && echo -n "$origin: " + get_latest_serial $origin + done + ;; + freeze) + for origin in $ORIGINS; do + serial_file="$CONFIG/$origin/serial" + git=$(cat $serial_file) + case "$origin" in + ${FREEZE_EXCEPTIONS}) + new=latest + ;; + *) + new=$(get_latest_serial $origin) + esac + printf "Origin $origin:\n old: $git\n new: $new\n" + echo $new > $serial_file + done + printf "\nAll files ($CONFIG/*/serial) have been updated with new serials\n" >&2 + ;; + thaw) + for origin in $ORIGINS; do + serial_file="$CONFIG/$origin/serial" + git=$(cat $serial_file) + printf "Origin $origin:\n old: $git\n new: latest\n" + echo 'latest' > $serial_file + done + ;; + prepare-build) + rm -rf tmp/APT_snapshots.d + mkdir -p tmp + cp -r config/APT_snapshots.d tmp/ + if [ "${APT_SNAPSHOTS_SERIALS}" ]; then + $(dirname "$0")/apt-snapshots-serials-load-json \ + "$APT_SNAPSHOTS_SERIALS" \ + > tmp/cached_APT_snapshots_serials + else + $0 get-latest > tmp/cached_APT_snapshots_serials + fi + for origin_dir in tmp/APT_snapshots.d/*; do + origin=$(basename $origin_dir) + if grep -qs '^latest$' $origin_dir/serial; then + awk -F': ' "/^$origin: / {print \$2}" \ + tmp/cached_APT_snapshots_serials \ + > $origin_dir/serial + fi + done + ;; + *) + printf "unknown action ($action), use either 'cat', 'cat-json', 'get-latest', 'prepare-build', 'freeze' or 'thaw'\n" >&2 + exit 1 + ;; +esac diff --git a/auto/scripts/apt-snapshots-serials-cat-json b/auto/scripts/apt-snapshots-serials-cat-json new file mode 100755 index 0000000000000000000000000000000000000000..9903183b8dcb7c662846f8e5371619ff4f1d49ee --- /dev/null +++ b/auto/scripts/apt-snapshots-serials-cat-json @@ -0,0 +1,23 @@ +#!/usr/bin/ruby +# +# Usage: apt-snapshots-serials-cat-json APT_SNAPSHOTS_CONFIG_DIR +# Example: apt-snapshots-serials-cat-json config/APT_snapshots.d/ + +require 'json' + +usage_str = "Usage: apt-snapshots-serials-cat-json APT_SNAPSHOTS_CONFIG_DIR" +!ARGV.empty? or raise usage_str +config_dir = ARGV[0] +!config_dir.empty? or raise usage_str + +serials = {} + +origins = Dir.glob("#{config_dir}/*").map do |origin_dir| + origin_dir.sub("#{config_dir}/", '') +end + +origins.map do |origin| + serials[origin] = File.open("#{config_dir}/#{origin}/serial") { |f| f.read.chomp } +end + +puts JSON.dump(serials) diff --git a/auto/scripts/apt-snapshots-serials-load-json b/auto/scripts/apt-snapshots-serials-load-json new file mode 100755 index 0000000000000000000000000000000000000000..52b7f18d112768e2661319d34e6cc13e3968a89c --- /dev/null +++ b/auto/scripts/apt-snapshots-serials-load-json @@ -0,0 +1,21 @@ +#!/usr/bin/ruby +# +# Usage: +# +# apt-snapshots-serials-load-json SERIALS_JSON +# +# Example: +# +# apt-snapshots-serials-load-json \ +# '{"torproject":"2017120803","debian-security":"2017120902","debian":"2017120903"}' + +require 'json' + +usage_str = "Usage: apt-snapshots-serials-load-json SERIALS_JSON" +ARGV.size == 1 or raise usage_str +serials = JSON.load(ARGV[0]) + +serials.each { |origin, serial| + serial != 'latest' or raise "Only numeric serials are supported" + puts "#{origin}: #{serial}\n" +} diff --git a/auto/scripts/create-usb-image-from-iso b/auto/scripts/create-usb-image-from-iso new file mode 100755 index 0000000000000000000000000000000000000000..ebc78bf4d50042dd15ecdf134ad3e0888a2b98db --- /dev/null +++ b/auto/scripts/create-usb-image-from-iso @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 + +import argparse +import os +import logging +from contextlib import contextmanager +import tempfile +import time +import subprocess + +import gi +gi.require_version('UDisks', '2.0') +from gi.repository import UDisks, GLib, Gio + + +logger = logging.getLogger(__name__) + +SYSTEM_PARTITION_FLAGS = ( + 1 << 0 | # system partition + 1 << 2 | # legacy BIOS bootable + 1 << 60 | # read-only + 1 << 62 | # hidden + 1 << 63 # do not automount +) + +# EFI System Partition +ESP_GUID = 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' + +PARTITION_LABEL = 'Tails' +FILESYSTEM_LABEL = 'Tails' + +GET_UDISKS_OBJECT_TIMEOUT = 2 + +# The size of the system partition (in MiB) will be: +# +# SYSTEM_PARTITION_ADDITIONAL_SIZE + size of the ISO +# +# SYSTEM_PARTITION_ADDITIONAL_SIZE must be large enough to fit +# the partition table, reserved sectors, and filesystem metadata. +SYSTEM_PARTITION_ADDITIONAL_SIZE = 10 + +# We use the syslinux from the chroot here, because it's the same one +# that will be available to Tails Installer in the running Tails. Using +# the same syslinux version here and in Tails Installer is important to +# prevent issues when upgrading a Tails device via Tails Installer. +CHROOT_SYSLINUX_COM32MODULES_DIR = 'chroot/usr/lib/syslinux/modules/bios' +CHROOT_SYSLINUX_BIN='chroot/usr/bin/syslinux' + +class ImageCreationError(Exception): + pass + + +class ImageCreator(object): + + def __init__(self, iso: str, image: str, free_space: int): + self.iso = iso + self.image = image + self.free_space = free_space + self._loop_device = None # type: str + self._partition = None # type: str + self._system_partition_size = None # type: int + self.iso_mountpoint = None # type: str + + @property + def loop_device(self) -> UDisks.ObjectProxy: + if not self._loop_device: + raise ImageCreationError("Loop device not set up") + return self.try_getting_udisks_object(self._loop_device) + + @property + def partition(self) -> UDisks.ObjectProxy: + if not self._partition: + raise ImageCreationError("Partition not created") + + return self.try_getting_udisks_object(self._partition) + + @property + def system_partition_size(self) -> int: + if self._system_partition_size is None: + self._system_partition_size = get_file_size(self.iso) + SYSTEM_PARTITION_ADDITIONAL_SIZE + + return self._system_partition_size + + def try_getting_udisks_object(self, object_path: str) -> UDisks.Object: + start_time = time.perf_counter() + while time.perf_counter() - start_time < GET_UDISKS_OBJECT_TIMEOUT: + with self.get_udisks_client() as udisks_client: + udisks_object = udisks_client.get_object(object_path) + if udisks_object: + return udisks_object + time.sleep(0.1) + raise ImageCreationError("Couldn't get UDisksObject for path '%s' (timeout: %s)" % + (object_path, GET_UDISKS_OBJECT_TIMEOUT)) + + @contextmanager + def get_udisks_client(self): + client = UDisks.Client().new_sync() + yield client + client.settle() + + def create_image(self): + self.create_empty_image() + + with self.setup_loop_device(): + self.create_gpt() + self.create_partition() + # udisks' create_partition function seems to ignore arg_type + # in Stretch, so we set it via sgdisk. + # XXX:Buster: Remove set_partition_type + self.set_partition_type() + self.set_partition_flags() + # XXX: Rescan? + self.format_partition() + with self.mount_iso(): + self.extract_iso() + self.adjust_syslinux_configuration() + self.install_mbr() + self.copy_syslinux_modules() + + # This sleep is a workaround for a race condition which causes the + # syslinux installation to return without errors, even though the + # bootloader isn't actually installed + # XXX: Investigate and report this race condition + # Might it be https://bugs.chromium.org/p/chromium/issues/detail?id=508713 ? + time.sleep(1) + self.install_syslinux() + self.set_guids() + self.set_fsuuid() + + def extract_iso(self): + logger.info("Extracting ISO contents to the partition") + for root, dirs, files in os.walk(self.iso_mountpoint): + for d in sorted(dirs): + with set_env("MTOOLS_SKIP_CHECK", "1"): + execute(['mmd', + "-i", self.partition.props.block.props.device, + "::%s" % os.path.join(os.path.relpath(root, start=self.iso_mountpoint), d)]) + for f in sorted(files): + with set_env("MTOOLS_SKIP_CHECK", "1"): + execute(['mcopy', + "-i", self.partition.props.block.props.device, + os.path.join(root, f), + "::%s" % os.path.join(os.path.relpath(root, start=self.iso_mountpoint), f)]) + + def create_empty_image(self): + logger.info("Creating empty image %r", self.image) + image_size = self.system_partition_size + self.free_space + execute(["dd", "if=/dev/zero", "of=%s" % self.image, "bs=1M", "count=%s" % image_size]) + + @contextmanager + def setup_loop_device(self): + logger.info("Setting up loop device") + with self.get_udisks_client() as udisks_client: + manager = udisks_client.get_manager() + + image_fd = os.open(self.image, os.O_RDWR) + resulting_device, fd_list = manager.call_loop_setup_sync( + arg_fd=GLib.Variant('h', 0), + arg_options=GLib.Variant('a{sv}', None), + fd_list=Gio.UnixFDList.new_from_array([image_fd]), + ) + + if not resulting_device: + raise ImageCreationError("Failed to set up loop device") + + logger.info("Loop device: %r", resulting_device) + self._loop_device = resulting_device + + try: + yield + finally: + logger.info("Tearing down loop device") + self.loop_device.props.loop.call_delete_sync( + arg_options=GLib.Variant('a{sv}', None), + ) + + @contextmanager + def mount_iso(self): + with tempfile.TemporaryDirectory() as mountpoint: + logger.info("Mounting ISO on %s" % mountpoint) + execute(['mount', '-o', 'loop,ro', self.iso, mountpoint]) + self.iso_mountpoint = mountpoint + try: + yield mountpoint + finally: + logger.info("Unmounting ISO") + execute(['umount', mountpoint]) + + def create_gpt(self): + logger.info("Creating GPT") + self.loop_device.props.block.call_format_sync( + arg_type='gpt', + arg_options=GLib.Variant('a{sv}', None) + ) + + def create_partition(self): + logger.info("Creating partition") + partition = self.loop_device.props.partition_table.call_create_partition_sync( + arg_offset=0, + arg_size=self.system_partition_size * 2**20, + arg_type=ESP_GUID, + arg_name=PARTITION_LABEL, + arg_options=GLib.Variant('a{sv}', None) + ) + # XXX: Tails Installer ignores GLib errors here + + logger.info("Partition: %r", partition) + self._partition = partition + + def set_partition_flags(self): + # We use sgdisk directly instead of udisks' set_flags method, because the + # latter sometimes resets the partition type / partition table type + # before Buster's udisks2 + libblockdev 2.15-1 + # (https://github.com/storaged-project/udisks/issues/418) + execute(["/sbin/sgdisk", "--attributes=1:=:%x" % SYSTEM_PARTITION_FLAGS, self.image]) + + def set_partition_type(self): + execute(["/sbin/sgdisk", "--typecode=1:%s" % ESP_GUID, self.image]) + + def format_partition(self): + logger.info("Formatting partition") + execute([ + 'mkfs.msdos', + '-v', + # Use constants for normally randomly generated or time-based data + # such as volume ID and creation time + '--invariant', + # Fill all 11 chars of the volume label to avoid any uninitialized + # memory from sneaking in + '-n', 'TAILS' + 6 * ' ', + self.partition.props.block.props.device, + ]) + + def adjust_syslinux_configuration(self): + logger.info("Adjusting syslinux configuration") + with set_env("MTOOLS_SKIP_CHECK", "1"): + execute(['mren', "-i", self.partition.props.block.props.device, + "::isolinux", "::syslinux"]) + execute(['mren', "-i", self.partition.props.block.props.device, + "::syslinux/isolinux.cfg", "::syslinux/syslinux.cfg"]) + + def install_mbr(self): + logger.info("Installing MBR") + mbr_path = os.path.join(self.iso_mountpoint, "utils/mbr/mbr.bin") + execute(["dd", "bs=440", "count=1", "conv=notrunc", + "if=%s" % mbr_path, "of=%s" % self.image]) + + # Ensure the syslinux modules come from the same package as the + # binary we'll use in install_syslinux, i.e. the system's one + # and not the one that's in the ISO; otherwise their ABI may + # be incompatible + def copy_syslinux_modules(self): + logger.info("Copying syslinux modules to device") + + syslinux_dir = os.path.join(self.iso_mountpoint, 'isolinux') + com32modules = [f for f in os.listdir(syslinux_dir) if f.endswith('.c32')] + + for module in sorted(com32modules): + src_path = os.path.join(CHROOT_SYSLINUX_COM32MODULES_DIR, module) + if not os.path.isfile(src_path): + raise ImageCreationError("Could not find the '%s' COM32 module" % module) + + logger.debug('Copying %s to the device' % src_path) + with set_env("MTOOLS_SKIP_CHECK", "1"): + execute(['mcopy', '-D', 'o', + '-i', self.partition.props.block.props.device, + src_path, + "::%s" % os.path.join('syslinux', module)]) + + def install_syslinux(self): + logger.info("Installing bootloader") + # We install syslinux directly on the image. Installing it on the loop + # device would cause this issue: + # https://bugs.chromium.org/p/chromium/issues/detail?id=508713#c8 + execute([ + CHROOT_SYSLINUX_BIN, + '--offset', str(self.partition.props.partition.props.offset), + '--directory', '/syslinux/', + '--install', self.image + ]) + + def set_guids(self): + logger.info("Setting disk and partition GUID") + execute(["/sbin/sgdisk", "--disk-guid", "17B81DA0-8B1E-4269-9C39-FE5C7B9B58A3", + "--partition-guid", "1:34BF027A-8001-4B93-8243-1F9D3DCE7DE7", self.image]) + + def set_fsuuid(self): + """Set a fixed filesystem UUID aka. FAT Volume ID / serial number""" + logger.info("Setting filesystem UUID") + with set_env("MTOOLS_SKIP_CHECK", "1"): + execute(["mlabel", "-i", self.partition.props.block.props.device, + "-N", "a69020d2", + # Otherwise mlabel -N will remove the pre-existing label + "::%s" % FILESYSTEM_LABEL]) + + +def execute(cmd: list): + logger.info("Executing '%s'" % ' '.join(cmd)) + subprocess.check_call(cmd) + + +@contextmanager +def set_env(name: str, value: str): + old_value = os.getenv(name) + os.putenv(name, value) + try: + yield + finally: + if old_value is not None: + os.putenv(name, value) + else: + os.unsetenv(name) + + +def get_file_size(path: str) -> int: + """Returns the size of a file in MiB""" + size_in_bytes = os.path.getsize(path) + return round(size_in_bytes // 1024 ** 2) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("ISO", help="Path to the ISO") + parser.add_argument("-d", "--directory", default=".", help="Output directory for the resulting image (the current directory by default)") + parser.add_argument("--free-space", type=int, default=0, help="Additional free space (for a persistent volume) in MiB") + args = parser.parse_args() + if not args.ISO.endswith(".iso"): + parser.error("Input file is not an ISO (no .iso extension)") + + if os.geteuid() != 0: + raise PermissionError("This script must be run as root") + + logging.basicConfig(level=logging.INFO) + logging.getLogger('sh').setLevel(logging.WARNING) + + iso = args.ISO + image = os.path.realpath(os.path.join(args.directory, os.path.basename(iso).replace(".iso", ".img"))) + + image_creator = ImageCreator(iso, image, args.free_space) + image_creator.create_image() + + +if __name__ == "__main__": + main() diff --git a/auto/scripts/generate-build-manifest b/auto/scripts/generate-build-manifest new file mode 100755 index 0000000000000000000000000000000000000000..87982816a8fe43242c93a5aecdfa62638e22584c --- /dev/null +++ b/auto/scripts/generate-build-manifest @@ -0,0 +1,118 @@ +#!/usr/bin/perl +# © 2015 Cyril Brulebois , for the Tails project. +# © 2016 Tails developers + +use strict; +use warnings; +use File::Slurp; +use List::MoreUtils qw(uniq); +use YAML::XS; + + +# NOTE: For reference, the first one is generated by debootstrap +# (>= 1.0.73), while the other two are generated by the apt-get +# wrapper installed in the chroot during the build. +my %package_type = qw( + deburis binary + binuris binary + srcuris source +); + +### Various usability checks: +sub usage { + die "Usage: $0 debootstrap-dir manifest-file"; +} + +my $debootstrap = shift @ARGV + or usage; +my $manifest = shift @ARGV + or usage; + +if (! -d $debootstrap) { + print "E: $debootstrap isn't a directory\n"; + usage; +} + +if (-f "$debootstrap/unknown") { + print "E: actions unsupported by the apt-get wrapper were logged ", + "in $debootstrap/unknown. Aborting."; + exit 1; +} + +my $extra_packages_file = 'config/build-manifest-extra-packages.yml'; +my $extra_packages; + +if (-e $extra_packages_file) { + my $yaml = read_file($extra_packages_file); + my $extra_packages_data = Load $yaml + or die "E: failed to load $extra_packages_file: $!"; + $extra_packages = $extra_packages_data->{packages}; +} + +### Read (package, version, uri) tuples and generate a single (package, version) list: +my $data; +foreach my $type (keys %package_type) { + my $path = "$debootstrap/$type"; + if (! -f $path ) { + print "E: $path is missing, wrong debootstrap-dir parameter? (got: $debootstrap)\n"; + usage; + } + print "I: processing $path\n"; + foreach my $line (read_file($path)) { + chomp $line; + my ($package, $version, $uri) = split / /, $line; + # Store package_version_arch to ease sort+uniq for deduplication: + my $arch = 'source'; + if ($package_type{$type} eq 'binary') { + if ($uri =~ /_([^_]+)\.deb$/) { + $arch = $1; + } + else { + die "unable to determine architecture for uri=$uri"; + } + } + push @{ $data->{ packages_tmp }->{ $package_type{$type} } }, "${package}_${version}_${arch}"; + } + + # Add extra packages + if ($extra_packages->{$package_type{$type}}) { + foreach my $pkginfo (@{ $extra_packages->{$package_type{$type}} }) { + my $package = $pkginfo->{package}; + my $version = $pkginfo->{version}; + my $arch = $package_type{$type} eq 'binary' + ? $pkginfo->{arch} + : 'source'; + push @{ $data->{ packages_tmp }->{ $package_type{$type} } }, + "${package}_${version}_${arch}"; + } + } +} + +### Extract list of (origin, reference) from the build configuration +### (the resolved serials, stored under tmp by "apt-snapshots-serials prepare-build"): +my %origin_reference; +while (my $origin_dir = glob('tmp/APT_snapshots.d/*')) { + my $origin_name = $origin_dir; + $origin_name =~ s{\A tmp/APT_snapshots[.]d/}{}xms; + $origin_reference{$origin_name} = read_file("$origin_dir/serial"); + chomp $origin_reference{$origin_name}; + $data->{origin_references}->{ $origin_name }->{reference} = $origin_reference{ $origin_name } || 'unknown'; +} + +### Deduplicate: +foreach my $type (uniq values %package_type) { + foreach my $entry (uniq sort @{ $data->{ packages_tmp }->{ $type } }) { + if ($entry =~ m{^(.+)_(.+)_(.+)$}) { + my ($package, $version, $arch) = ($1, $2, $3); + my $item = { package => $package, version => $version, arch => $arch, }; + # Reduce clutter: + delete $item->{arch} + if $type eq 'source'; + push @{ $data->{ packages }->{ $type } }, $item; + } + } +} +delete $data->{ packages_tmp }; + +my $yaml = Dump $data; +write_file($manifest, $yaml); diff --git a/auto/scripts/ikiwiki-supported-languages b/auto/scripts/ikiwiki-supported-languages new file mode 100755 index 0000000000000000000000000000000000000000..be02187cb54d626f372362e4a6f5b99f8ecbdb67 --- /dev/null +++ b/auto/scripts/ikiwiki-supported-languages @@ -0,0 +1,69 @@ +#!/usr/bin/perl + +=head1 NAME + +ikiwiki-supported-languages - extract languages supported by a given ikwiki + +=head1 SYNOPSIS + +B YAML_IKIWIKI_SETUP_FILE + +=head1 USAGE + +The ikiwiki setup file passed as an argument must be in YAML format. +See http://ikiwiki.info/tips/yaml_setup_files/ if you want to convert yours. + +The ikiwiki po plugin must be enabled and properly configured. + +=head1 AUTHOR + +Tails developers + +=head1 LICENSE AND COPYRIGHT + +Copyright (C) 2011 Tails developers + +Licensed under the GNU GPL version 3 or any later version. + +=cut + +use strict; +use warnings; +use 5.10.1; + +use IkiWiki::Plugin::po; +use YAML::Syck; +$YAML::Syck::ImplicitUnicode = 1; + +sub usage { + "Usage: ikiwiki-supported-languages YAML_IKIWIKI_SETUP_FILE"; +} +my $setupfile = shift; +defined $setupfile || die(usage()); +$setupfile ne '' || die(usage()); +-e $setupfile || die "File '$setupfile' does not exist."; +-f $setupfile || die "File '$setupfile' is not a regular file."; + +my $config = LoadFile($setupfile); +ref($config) && ref($config) eq 'HASH' + || die "Could not load '$setupfile'. Is it really YAML?"; + +for (qw{add_plugins po_master_language po_slave_languages}) { + exists($config->{$_}) && defined($config->{$_}) + || die "$_ is not set"; +} + +grep { $_ eq 'po' } $config->{add_plugins} + || die "The po plugin is disabled."; + +ref($config->{po_slave_languages}) && ref($config->{po_slave_languages}) eq 'ARRAY' + || die "Invalid po_slave_languages format."; + +my @supported_lang_codes; +for ($config->{po_master_language}, @{$config->{po_slave_languages}}) { + my ($code, $name) = IkiWiki::Plugin::po::splitlangpair($_); + defined $code && $code ne '' || die "invalid language format: '$_'"; + push @supported_lang_codes, $code; +} + +say join(' ', @supported_lang_codes); diff --git a/auto/scripts/tails-custom-apt-sources b/auto/scripts/tails-custom-apt-sources new file mode 100755 index 0000000000000000000000000000000000000000..b3c1856923f88d89d3f62ed3ba70e604bbd6d3ed --- /dev/null +++ b/auto/scripts/tails-custom-apt-sources @@ -0,0 +1,49 @@ +#!/bin/bash + +set -e +set -u + +. "$(dirname $0)/utils.sh" + +APT_MIRROR_URL="http://deb.tails.boum.org/" +DEFAULT_COMPONENTS="main contrib non-free" + +output_apt_binary_source() { + local suite="$1" + local components="${2:-$DEFAULT_COMPONENTS}" + + echo "deb $APT_MIRROR_URL $suite $components" +} + +output_overlay_apt_binary_sources() { + for suite in $(ls config/APT_overlays.d) ; do + output_apt_binary_source "$suite" + done +} + +### Sanity checks + +[ -d config/APT_overlays.d ] || fatal 'config/APT_overlays.d/ does not exist' +[ -e config/base_branch ] || fatal 'config/base_branch does not exist' + +[ "$(cat config/base_branch | wc -l)" -eq 1 ] \ + || fatal 'config/base_branch must contain exactly one line' + +if on_base_branch && ! [ "$(base_branch)" = "$(git_current_branch)" ] ; then + echo "base_branch: $(base_branch)" >&2 + echo "current_branch: $(git_current_branch)" >&2 + fatal "In a base branch, config/base_branch must match the current branch." +fi + +### Main + +if version_was_released "$(version_in_changelog)"; then + if [ -n "$(ls config/APT_overlays.d)" ]; then + fatal 'config/APT_overlays.d/ must be empty while releasing' + fi + output_apt_binary_source "$(branch_name_to_suite "$(version_in_changelog)")" +else + output_apt_binary_source "$(branch_name_to_suite "$(base_branch)")" + output_overlay_apt_binary_sources +fi + diff --git a/auto/scripts/update-acng-config b/auto/scripts/update-acng-config new file mode 100755 index 0000000000000000000000000000000000000000..5e5695e4b1f49636ec130329d3dd29fa0f77dc33 --- /dev/null +++ b/auto/scripts/update-acng-config @@ -0,0 +1,84 @@ +#!/bin/bash + +set -e +set -u +set -o pipefail + +list_origins () { + ( + cd config/APT_snapshots.d/ + ls --color=never -1 | grep -v --line-regexp '\.placeholder' + ) +} + +print_tagged_snapshots_pool_url () { + origin="$1" + version="$2" + printf \ + 'http://tagged.snapshots.deb.tails.boum.org/%s/%s/pool/\n' \ + "$version" "$origin" +} + +conf=/etc/apt-cacher-ng/tails-snapshots.conf +for origin in $(list_origins) ; do + [ "$origin" != .placeholder ] || continue + origin_without_dashes=$(echo "$origin" | sed -e 's,-,,g') + echo "Remap-tailssnapshots${origin_without_dashes}pool: file:tails-time-based-snapshots-$origin-pool.list file:tails-tagged-snapshots-$origin-pool.list" +done > "$conf" +chmod 644 "$conf" + +# Generate .list files for time-based snapshots +for origin in $(list_origins) ; do + list="/etc/apt-cacher-ng/tails-time-based-snapshots-$origin-pool.list" + current_year=$(date '+%Y') + for year in $(seq $(($current_year - 1)) $(($current_year + 1))) ; do + for month in $(seq 1 12); do + # We need the config file to contain _at least_ everything + # that can possibly exists, and we don't care if it has some extra + # lines, so to simplify we do as if each month had 31 days. + for day in $(seq 1 31) ; do + for n in $(seq 1 4) ; do + printf 'http://time-based.snapshots.deb.tails.boum.org/%s/%04u%02u%02u%02u/pool/\n' \ + "$origin" "$year" "$month" "$day" "$n" + done + done + done + done \ + > "$list" + chmod 644 "$list" +done + +# Generate .list files for tagged snapshots +for origin in $(list_origins) ; do + list="/etc/apt-cacher-ng/tails-tagged-snapshots-$origin-pool.list" + # We need the config file to contain _at least_ everything + # that can possibly exists, and we don't care if it has some extra + # lines, so here we try to build the smallest possible superset of + # all realistic Tails version numbers; it could certainly be a tiny + # bit smaller, at the cost of more assumptions (=> more risk of not + # including some version number we'll end up using) or of more + # code complexity (=> higher maintenance cost). + # + # XXX: Stretch: bump the end of the range of major versions + for major in $(seq 2 3) ; do + for minor in $(seq 0 32); do + for suffix in "" alpha beta rc ; do + for suffix_n in "" $(seq 1 8); do + if [ -z "$suffix" ]; then + version="${major}.${minor}" + elif [ -z "$suffix_n" ]; then + version="${major}.${minor}-${suffix}" + else + version="${major}.${minor}-${suffix}${suffix_n}" + fi + print_tagged_snapshots_pool_url "$origin" "$version" + done + done + for emergency in $(seq 1 4) ; do + version="${major}.${minor}.${emergency}" + print_tagged_snapshots_pool_url "$origin" "$version" + done + done + done > "$list" + chmod 644 "$list" +done diff --git a/auto/scripts/utils.sh b/auto/scripts/utils.sh new file mode 100755 index 0000000000000000000000000000000000000000..1e7286a017645b5872766e1dcf6de836c13af777 --- /dev/null +++ b/auto/scripts/utils.sh @@ -0,0 +1,138 @@ +# This library is meant to be used in bash, with "set -e" and "set -u". + +BASE_BRANCHES="stable testing devel feature/buster" + +# Returns "" if in undetached head +git_current_branch() { + local git_ref + if git_ref="$(git symbolic-ref HEAD 2>/dev/null)"; then + echo "${git_ref#refs/heads/}" + else + echo "" + fi +} + +git_in_detached_head() { + [ -z "$(git_current_branch)" ] +} + +# Returns "" if ref does not exist +git_commit_from_ref() { + git rev-parse --verify "${@}" 2>/dev/null || : +} + +git_current_commit() { + git_commit_from_ref "${@}" HEAD +} + +# Returns "" if not a tag +git_tag_from_commit() { + git describe --tags --exact-match "${1}" 2>/dev/null || : +} + +# Returns "" if not on a tag +git_current_tag() { + git_tag_from_commit $(git_current_commit) +} + +# Try to describe what currently is checked out. Returns "" if we are +# in detached HEAD, otherwise, in order, the tag pointing to HEAD, or +# the current branch. +git_current_head_name() { + local ret + ret="$(git_current_tag)" + if [ -z "${ret}" ]; then + ret="$(git_current_branch)" + fi + echo "${ret}" +} + +git_on_a_tag() { + [ -n "$(git_current_tag)" ] +} + +git_only_doc_changes_since() { + local commit non_doc_diff + commit="$(git_commit_from_ref ${1})" + non_doc_diff="$(git diff \ + ${commit}... \ + -- \ + '*' \ + ':!/wiki' \ + ':!/ikiwiki.setup' \ + ':!/ikiwiki-cgi.setup' \ + ':!*.po' \ + )" + + [ -z "${non_doc_diff}" ] +} + +base_branch() { + cat config/base_branch | head -n1 +} + +base_branches() { + echo ${BASE_BRANCHES} +} + +on_base_branch() { + for base_branch in $BASE_BRANCHES ; do + if [ "$(git_current_branch)" = "${base_branch}" ] ; then + return 0 + fi + done + + return 1 +} + +# Returns the top commit ref of the base branch +git_base_branch_head() { + git_commit_from_ref "${@}" origin/"$(base_branch)" +} + +branch_name_to_suite() { + local branch="$1" + + echo "$branch" | sed -e 's,[^.a-z0-9-],-,ig' | tr '[A-Z]' '[a-z]' +} + +fatal() { + echo "E: $*" >&2 + exit 1 +} + +git_tag_exists() { + local tag="$1" + + test -n "$(git tag -l "$tag")" +} + +version_was_released() { + local version="$1" + + version="$(echo "$version" | tr '~' '-')" + git_tag_exists "$version" +} + +version_in_changelog() { + dpkg-parsechangelog | awk '/^Version: / { print $2 }' +} + +previous_version_in_changelog() { + dpkg-parsechangelog --offset 1 --count 1 | awk '/^Version: / { print $2 }' +} + +# Make it so that when this script is called, any function defined in +# this script can be invoked via arguments, e.g.: +# +# $ auto/scripts/utils.sh git_commit_from_ref 3.0-beta2 +# eca83a88a9dd958b16b4d5b04fea3ea503a3815d +# +if grep -q __utils_sh_magic_5773fa52-0d1a-11e7-a606-0021ccc177a7 "${0}" && [ -n "${1}" ]; then + if grep -q "^${1}() {$" "${0}"; then + eval "\"\${@}\"" + else + echo "unknown shell function: ${1}" >&2 + exit 1 + fi +fi diff --git a/bin/add-APT-overlay b/bin/add-APT-overlay new file mode 100755 index 0000000000000000000000000000000000000000..455087254f7233dc4e972dcb4ee97c8c0b355d64 --- /dev/null +++ b/bin/add-APT-overlay @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e +set -u +set -x + +GIT_TOPLEVEL_DIR=$(git rev-parse --show-toplevel) +. "$GIT_TOPLEVEL_DIR"/auto/scripts/utils.sh + +OVERLAY=$(branch_name_to_suite $(git_current_branch)) +OVERLAY_FILE="${GIT_TOPLEVEL_DIR}/config/APT_overlays.d/${OVERLAY}" +TICKET=$(git_current_branch | perl -p -E 's/.*?(\d{4,6}).*/$1/') + +touch "${OVERLAY_FILE}" +git add "${OVERLAY_FILE}" +git commit -m "Enable the ${OVERLAY} APT overlay (refs: #${TICKET})." +git show diff --git a/bin/delete-merged-git-branches b/bin/delete-merged-git-branches new file mode 100755 index 0000000000000000000000000000000000000000..03ea380e5d8daee36fd87ca6bc26514c562ea787 --- /dev/null +++ b/bin/delete-merged-git-branches @@ -0,0 +1,59 @@ +#!/usr/bin/python3 + +import argparse +import pprint +import sys + +from distutils.util import strtobool +from tailslib.git import Git + +# Functions + + +def yes_no_input(prompt, default=True): + if default: + options = 'Y/n' + else: + options = 'N/y' + sys.stdout.write('%s [%s] ' % (prompt, options)) + while True: + answer = input().lower() + if len(answer) == 0: + return default + else: + try: + return strtobool(answer) + except ValueError: + print("Please respond with 'y' or 'n'.") + + +# Parse command-line arguments + +parser = argparse.ArgumentParser(description='Delete merged Git branches.') +parser.add_argument('--repo', type=str, dest='repo', + help='Path to an up-to-date (bare) Tails Git repository.') +parser.add_argument('--remote', type=str, dest='remote', default='origin', + help='Push to the specified remote instead of "origin".') +parser.add_argument('--batch', type=bool, dest='batch', + nargs='?', const=True, default=False, + help='Assume "yes" as answer to all prompts.') +args = parser.parse_args() + + +# Main + +pp = pprint.PrettyPrinter() +tailsgit = Git(args.repo) +branches_to_delete = tailsgit.branches_to_delete() + +if not branches_to_delete: + print("No branch to delete was found.") + sys.exit(0) + +print("The following branches will be deleted:") +pp.pprint(sorted(branches_to_delete)) +if not args.batch \ + and not yes_no_input("Remove these branches?", default=False): + sys.exit(0) + +tailsgit.push(args.remote, [':%s' % branch for branch in branches_to_delete]) diff --git a/bin/doc-impacted-by b/bin/doc-impacted-by new file mode 100755 index 0000000000000000000000000000000000000000..911d005aedafa35bf2bb7e66c047607fd6d7089a --- /dev/null +++ b/bin/doc-impacted-by @@ -0,0 +1,275 @@ +#!/usr/bin/env ruby +# coding: utf-8 +require 'deep_merge' +require 'git' +require 'optparse' +require 'yaml' + +require 'test/unit' +Test::Unit.run = true +include Test::Unit::Assertions + +# The Ruby Git module we use needs the Git root directory, and this +# prevents it from being able to run the command below. +GIT_DIR = `git rev-parse --show-toplevel`.chomp +assert_equal(0, $?.exitstatus) +DEFAULT_RELATIONSHIP_FILE = "#{GIT_DIR}/doc-source-relationships.yml" + +class Object + def arrayify + self.instance_of?(Array) ? self : [self] + end +end + +class Array + def glob(glob) + self.select do |e| + e.instance_of?(String) && File.fnmatch(glob, e, File::FNM_EXTGLOB) + end + end +end + +def parse_argv! + options = Hash.new + opt_parser = OptionParser.new do |opts| + opts.banner = "Usage: [OPTION]... COMMITISH1 COMMITISH2 MANIFEST1 MANIFEST2" + opts.separator "" + opts.separator "Produces a list of documentation pages that might need " \ + "attention due to the changes from COMMITISH1 to " \ + "COMMITISH2. The corresponding .build-manifest files must " \ + "be passed as MANIFEST1 and MANIFEST2." + opts.separator "" + opts.separator "Example:" + opts.separator " bin/doc-impacted-by 3.0 3.2 " \ + "tails-amd64-3.0.build-manifest " \ + "tails-amd64-3.2.build-manifest" + opts.separator "" + opts.separator "Options:" + + opts.on("-h", "--help", "Show this message") do + puts opts + exit + end + + opts.on("-f PATH", "--relationship-file=PATH", + "Use a custom PATH for the doc-source relationship description " + + "file (default: #{File.basename(DEFAULT_RELATIONSHIP_FILE)} in " + + "the Git root)") do |path| + options['relationship-file'] = path + end + + opts.on("-s", "--skip-packages", "Skip looking at packages, " + + "only look at Git") do + options['skip-packages'] = true + end + end + parameters = opt_parser.parse(ARGV) + req_nr_parameters = options['skip-packages'] ? 2 : 4 + assert_equal(req_nr_parameters, parameters.size, + "You must pass exactly #{req_nr_parameters} parameters") + return [options, parameters] +end + +# From a .build-manifest, from its list of packages, generate a +# Hash mapping `package` to a Hash containing the remaining package +# fields from the .build-manifest (e.g. `arch`, `version`). +def read_package_manifest_file_as_package_map(path) + package_manifest = YAML.load(File.read(path)) + packages = package_manifest['packages']['binary'] + + package_manifest['packages']['source'] + packages.map do |entry| + [ + entry['package'], + entry.clone.delete_if { |k, _| k == 'package' } + ] + end + .to_h +end + +def canonicalize_relationship(orig_entry) + entry = orig_entry.clone + field_abbreviations = { + 'file' => 'files', + 'package' => 'packages', + 'page' => 'pages', + 'test' => 'tests', + } + fields = field_abbreviations.values + field_abbreviations.each do |short, long| + next unless entry.has_key?(short) + assert(not(entry.has_key?(long)), + "contains both '#{long}' and its abbreviation '#{short}'") + v = entry[short] + entry.delete(short) + entry[long] = v + end + assert(entry.has_key?('pages'), + "lacks the obligatory 'pages' field") + assert(entry.keys.size > 1, + "entries with only a 'pages' field are meaningless") + # Note: `(a - b).empty?` <==> "a is a subset of b?" + assert((entry.keys - fields).empty?, + "contains invalid fields: #{entry.keys - fields}") + fields.each do |field| + next unless entry.has_key?(field) + entry[field] = entry[field].arrayify + end + return entry +rescue Exception => e + STDERR.puts 'Problematic entry:' + STDERR.puts YAML.dump([orig_entry]) + STDERR.puts + raise e +end + +# Reads the `relationship_file` and returns a "documentation impact +# map", a Hash which maps all documentation pages to the sources it is +# impacted by. +def read_relationship_file_as_impact_map(relationship_file) + impact_map = Hash.new + relationships = YAML.load(File.read(relationship_file)) + relationships.map { |e| canonicalize_relationship(e) } .each do |entry| + entry['pages'].each do |page| + source_files = entry.clone.delete_if { |k, _| k == 'pages' } + impact_map.deep_merge({page => source_files}) + end + end + return impact_map +end + +# Given the "documentation impact map" and the "old" and "new" state, +# look at the changes between "old" and "new" and find which +# documentation pages are impacted. The return value is a mapping +# from each affected documentation page to the list of "reasons", +# explanations how the sources impact the page. +def find_impacted_docs(impact_map, + old_commit, new_commit, + old_manifest, new_manifest) + git = Git.open(GIT_DIR) + git_diff = git.diff(old_commit, new_commit) + # Create the list of all wiki files, and use it as an approximation + # of all documentation pages. It's a super set, so it only impacts + # performance when we search in it later. Ideally we'd like to do + # something like `git.object(new_commit).path('wiki/src')` but the + # Git module we use seem to not support listing files at a certain + # commit. + git_cmd_wiki_files = "git ls-tree -r --full-tree " + + "--name-only #{new_commit} -- wiki/src" + doc_pages = `#{git_cmd_wiki_files}`.chomp.split("\n") + assert_equal(0, $?.exitstatus, "Error: `git ls-tree` failed") + + old_packages = old_manifest.keys + new_packages = new_manifest.keys + removed_packages = old_packages - new_packages + introduced_packages = new_packages - old_packages + updated_packages = (new_packages & old_packages).select do |package| + old_manifest[package] != new_manifest[package] + end + + impacted_docs = Hash.new + impact_map.each do |page, sources| + file_paths = [] + package_globs = [] + test_paths = [] + sources.each do |type, source| + case type + when 'packages' + package_globs = source + when 'tests' + test_paths = source.map { |path| "features/#{path}" } + when 'files' + file_paths = source + else + raise "Unknown field '#{type}' in impact map; this should not " + + "happen, and probably means canonicalize_relationship() " + + "is buggy" + end + end + all_source_file_paths = file_paths + test_paths + doc_pages.glob("wiki/src/#{page}.{html,mdwn}").each do |page_path| + all_source_file_paths.each do |source_path| + # Git::Diff#path() alters the object so it cannot be used for a + # successive call for another path. + _git_diff = git_diff.clone + source_path_diff = _git_diff.path(source_path) + if source_path_diff.size > 0 + changed_files = source_path_diff.map { |file| file.path } + reasons = changed_files.map do |path| + "Changes in source file: #{path}" + end + impacted_docs.deep_merge({page_path => reasons}) + end + end + package_globs.each do |package_glob| + reasons = [] + removed_impacted_packages = removed_packages.glob(package_glob) + introduced_impacted_packages = introduced_packages.glob(package_glob) + updated_impacted_packages = updated_packages.glob(package_glob) + reasons += removed_impacted_packages.map do |package| + "Removed package: #{package}" + end + reasons += introduced_impacted_packages.map do |package| + "Introduced package: #{package}" + end + reasons += updated_impacted_packages.map do |package| + old = old_manifest[package] + new = new_manifest[package] + assert_not_equal( + old, new, + "'#{package}' has identical data in both manifests so it is " + + "a bug that we ended up here" + ) + package_changes = old_manifest[package].keys.sort.map do |key| + old_val = old[key] + new_val = new[key] + old_val != new_val ? "#{old_val} → #{new_val}" : nil + end + .compact.join(', ') + "Updated package: #{package} (#{package_changes})" + end + impacted_docs.deep_merge({page_path => reasons}) unless reasons.empty? + end + end + end + return impacted_docs +end + +# Main + +options, parameters = parse_argv! +relationship_file = options['relationship-file'] || DEFAULT_RELATIONSHIP_FILE +old_commit, new_commit, old_manifest_path, new_manifest_path = parameters + +impact_map = read_relationship_file_as_impact_map(relationship_file) +if options['skip-packages'] + old_manifest = Hash.new + new_manifest = Hash.new +else + old_manifest = read_package_manifest_file_as_package_map(old_manifest_path) + new_manifest = read_package_manifest_file_as_package_map(new_manifest_path) +end +impacted_docs = find_impacted_docs( + impact_map, + old_commit, new_commit, + old_manifest, new_manifest +) + +if impacted_docs.size > 0 + result = + impacted_docs.sort.map do |page, reasons| + "#{page}\n" + + reasons.sort.map do |reason| + "- #{reason}" + end + .join("\n") + end + .join("\n\n") + + puts "The following documentation pages need investigation:" + puts + puts result +end +if options['skip-packages'] + STDERR.puts "Warning! The --skip-packages option makes this " + + "report incomplete!" +end diff --git a/bin/idf-content b/bin/idf-content new file mode 100755 index 0000000000000000000000000000000000000000..dbdf32868780fd7cd7a5f229158db4e017e6ea7a --- /dev/null +++ b/bin/idf-content @@ -0,0 +1,76 @@ +#! /usr/bin/python3 + +import hashlib +import io +import json +import sys + +from pathlib import Path, PurePath + +def sha256_file(filename): + sha256 = hashlib.sha256() + with io.open(filename, mode="rb") as fd: + content = fd.read() + sha256.update(content) + return sha256.hexdigest() + +def to_json(data): + return json.dumps(data, indent=4, sort_keys=True) + +def target_file_url(channel, filename): + basename = PurePath(filename).name + return '%(baseurl)s/%(channel)s/%(subdir)s/%(basename)s' % { + 'baseurl': 'http://dl.amnesia.boum.org/tails', + 'channel': channel, + 'subdir': PurePath(basename).stem, + 'basename': basename, + } + +def idf_content(build_target, channel, product_name, version, img, iso): + return to_json({ + 'build_target': build_target, + 'channel': channel, + 'product-name': product_name, + 'installations': [{ + 'version': version, + 'installation-paths': [ + { + 'type': 'img', + 'target-files': [{ + 'url': target_file_url(channel, img), + 'sha256': sha256_file(img), + 'size': Path(img).stat().st_size, + }], + }, + { + 'type': 'iso', + 'target-files': [{ + 'url': target_file_url(channel, iso), + 'sha256': sha256_file(iso), + 'size': Path(iso).stat().st_size, + }], + }, + ], + }], + }) + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--build-target', dest='build_target', default='amd64') + parser.add_argument('--channel', default='stable') + parser.add_argument('--product-name', dest='product_name', default='Tails') + parser.add_argument('--version', default=None, required=True, + help='Version of Tails .') + parser.add_argument('--img', default=None, required=True, + help='Path to the USB image.') + parser.add_argument('--iso', default=None, required=True, + help='Path to the ISO file.') + args = parser.parse_args() + + print(idf_content(build_target=args.build_target, + channel=args.channel, + product_name=args.product_name, + version=args.version, + img=args.img, + iso=args.iso)) diff --git a/bin/import-package b/bin/import-package new file mode 100755 index 0000000000000000000000000000000000000000..b675a018ae7f07893a9391f3cdf8a8c65fad1d0e --- /dev/null +++ b/bin/import-package @@ -0,0 +1,84 @@ +#!/bin/sh + +# Usage: ./bin/import-package SOURCE_PACKAGE +# +# This script automates a part of the process to grant a freeze exception +# to a Debian package: +# https://tails.boum.org/contribute/APT_repository/time-based_snapshots/#freeze-exception +# +# It imports the specified source package, and all binary packages built +# from it, into the Tails custom APT repository's $TARGET_DIST suite. +# +# Packages are downloaded with APT in a pbuilder chroot environment. +# To choose the Debian distribution packages must be pulled from +# (or whatever other options you want to pass to pbuilder), +# use $PBUILDER_OPTIONS: its value will be passed to the pbuilder command-line. +# +# If $TARGET_DIST is unset, packages are added to the APT suite +# corresponding to the current Git branch. +# +# Example: +# +# PBUILDER_OPTIONS='--basetgz /var/cache/pbuilder/base-sid-amd64.tgz' \ +# TARGET_DIST='testing' \ +# ./bin/import-package libgsecuredelete + +set -x +set -e +set -u + +SRC_PKG="$1" + +GIT_TOPLEVEL_DIR=$(git rev-parse --show-toplevel) +. "$GIT_TOPLEVEL_DIR"/auto/scripts/utils.sh +PBUILDER_OPTIONS="${PBUILDER_OPTIONS:-}" +TARGET_DIST="${TARGET_DIST:-$(branch_name_to_suite $(git_current_branch))}" +REMOTE_USER_AT_HOST='reprepro@incoming.deb.tails.boum.org' + +umask 0022 +WORKDIR=$(mktemp -d) + +trap "rm -r $WORKDIR" EXIT HUP INT QUIT TERM + +( + cd "$WORKDIR" + + # download source and binary packages + cat > script < /etc/apt/sources.list.d/tmp-deb.list +sed --regexp-extended -e 's,^deb(\s+),deb-src\1,' \ + /etc/apt/sources.list.d/tmp-deb.list \ + > /etc/apt/sources.list.d/tmp-deb-src.list +apt-get update +apt-get install dctrl-tools + +cd '$WORKDIR' +ORIG_OWNER=\$(stat --format='%u:%g' '$WORKDIR') +# allow APT 1.1+ to drop privileges +if getent passwd _apt >/dev/null 2>&1 ; then + chown _apt '$WORKDIR' +fi +apt-get --download-only source '$SRC_PKG' +apt-get download \ + \$(grep-aptavail -S '$SRC_PKG' --exact-match -s Package --no-field-names) +chown "\$ORIG_OWNER" '$WORKDIR' +EOF + chmod 755 script + sudo pbuilder execute --bindmounts "$WORKDIR" $PBUILDER_OPTIONS -- script + rm script + + REMOTE_WORKDIR=$(ssh "$REMOTE_USER_AT_HOST" mktemp -d) + scp * "$REMOTE_USER_AT_HOST":"$REMOTE_WORKDIR"/ + ssh "$REMOTE_USER_AT_HOST" \ + "reprepro includedsc '$TARGET_DIST' '$REMOTE_WORKDIR'/*.dsc && \ + reprepro includedeb '$TARGET_DIST' '$REMOTE_WORKDIR'/*.deb && \ + rm -r '$REMOTE_WORKDIR'" +) diff --git a/bin/pre-commit-translation b/bin/pre-commit-translation new file mode 100755 index 0000000000000000000000000000000000000000..965322525223575d9764b98b67d7de59494dba40 --- /dev/null +++ b/bin/pre-commit-translation @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Copy this hook to .git/hooks/pre-commit +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. + +set -e +set -u + +path=$(git rev-parse --show-toplevel) + +# If we try to commit po files, check that they do not contain errors. +if ! "${path}/submodules/jenkins-tools/slaves/lint_po" --cached; then + echo + echo "The po files you're trying to commit contain errors. Please fix them and try again." + echo + exit 1 +fi diff --git a/bin/sanity-check-website b/bin/sanity-check-website new file mode 100755 index 0000000000000000000000000000000000000000..0e725d6741a002361d2bbcf598fd39855586587e --- /dev/null +++ b/bin/sanity-check-website @@ -0,0 +1,94 @@ +#!/usr/bin/env ruby +require 'date' + +require 'test/unit' +Test::Unit.run = true +include Test::Unit::Assertions + +# Force UTF-8. Ruby will default to the system locale, and if it is +# non-UTF-8, String-methods will fail when operating on non-ASCII +# strings. +Encoding.default_external = Encoding::UTF_8 +Encoding.default_internal = Encoding::UTF_8 + +GIT_DIR=`git rev-parse --show-toplevel` +assert_equal( + 0, $?.exitstatus, + "Failed to find Tails' Git root; this command must be run " + + "inside Tails Git repo" +) + +def rfc2822_date?(date) + !!DateTime.rfc2822(date) +rescue ArgumentError + false +end + +def page_meta_date_is_ok?(path) + meta_date_post_re = /^\[\[!meta\s+date="(?.*)"\]\]$/ + success = true + content_lines = File.new(path).read.split("\n") + matches = content_lines.grep(meta_date_post_re) + if matches.size != 1 + STDERR.puts "#{path}: has #{matches.size} well-formed 'meta date' " + + "directives (must be 1)" + success = false + else + meta_date_line = matches.first + m = meta_date_post_re.match(meta_date_line) + meta_date = m['date'] + if not(rfc2822_date?(meta_date)) + STDERR.puts "#{path}: 'meta date' directive contains non-rfc2822 " + + "date: #{meta_date}" + success = false + end + end + return success +end + +def po_file_meta_date_is_ok?(path) + meta_date_po_re_str = '\[\[!meta\s+date=\\\"(?.*)\\\"\]\]\\\n' + success = true + content_lines = File.new(path).read.split("\n") + matches = content_lines.grep(Regexp.new("^msgid \"#{meta_date_po_re_str}\"$")) + if matches.size != 1 + STDERR.puts "#{path}: has #{matches.size} 'meta date' msgid:s (must be 1)" + success = false + else + msgid = matches.first + msgid_index = content_lines.find_index(msgid) + msgstr_index = msgid_index + 1 + msgstr_line = content_lines[msgstr_index] + m = Regexp.new("^msgstr \"(?:#{meta_date_po_re_str})?\"$").match(msgstr_line) + if m.nil? + STDERR.puts "#{path}: the 'meta date' msgid is not followed by a msgstr" + success = false + elsif m['date'] + meta_date = m['date'] + if not(rfc2822_date?(meta_date)) + STDERR.puts "#{path}: 'meta date' msgstr contains non-rfc2822 " + + "date: #{meta_date}" + success = false + end + end + end + return success +end + +# Main + +success = true + +meta_date_sorted_pages = + Dir.glob('wiki/src/{news,security,security/audits}/*.{mdwn,html}') - [ + 'wiki/src/security/audits.mdwn', + ] + +meta_date_sorted_pages.each do |post_path| + success = false unless page_meta_date_is_ok?(post_path) + Dir.glob(post_path.sub(/.(html|mdwn)$/, '') + '.*.po').each do |po_path| + success = false unless po_file_meta_date_is_ok?(po_path) + end +end + +exit(success) diff --git a/bin/tag-apt-snapshots b/bin/tag-apt-snapshots new file mode 100755 index 0000000000000000000000000000000000000000..c67a7806b5bdacf49094ed97a26ba0cbceb3d38c --- /dev/null +++ b/bin/tag-apt-snapshots @@ -0,0 +1,54 @@ +#!/bin/sh + +set -e +set -u + +TIME_BASED_SNAPSHOTS_HOST='apt.lizard' +TIME_BASED_SNAPSHOTS_USER='reprepro-time-based-snapshots' +TIME_BASED_SNAPSHOTS_USER_AT_HOST="${TIME_BASED_SNAPSHOTS_USER}@${TIME_BASED_SNAPSHOTS_HOST}" + +fail_with_usage() { + echo "$(basename $0) BUILD_MANIFEST TAG" >&2 +} + +[ $# -eq 2 ] || fail_with_usage + +BUILD_MANIFEST="$1" +TAG="$2" + +[ -r "$BUILD_MANIFEST" ] || fail_with_usage +[ -n "$TAG" ] || fail_with_usage + +echo "I: Preparing a workspace on ${TIME_BASED_SNAPSHOTS_HOST}" +ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" install -d '$HOME'/tmp +REMOTE_BUILD_MANIFEST=$(ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" \ + mktemp --tmpdir='$HOME'/tmp) +REMOTE_DEST_DIR=$(ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" \ + mktemp -d --tmpdir='$HOME'/tmp) + +echo "I: Sending build manifest to ${TIME_BASED_SNAPSHOTS_HOST}" +scp "$BUILD_MANIFEST" \ + "${TIME_BASED_SNAPSHOTS_USER_AT_HOST}:${REMOTE_BUILD_MANIFEST}" + +echo "I: Preparing reprepro configuration" +ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" \ + tails-prepare-tagged-apt-snapshot-import \ + "$REMOTE_BUILD_MANIFEST" \ + "$REMOTE_DEST_DIR" + +echo "I: Pulling packages from the time-based snapshots into the tagged ones" +for archive in $(ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" \ + ls "$REMOTE_DEST_DIR") ; do + echo "I: - $archive" + ssh "$TIME_BASED_SNAPSHOTS_USER_AT_HOST" \ + reprepro --basedir "${REMOTE_DEST_DIR}/${archive}" update +done + +echo "I: Publishing the tagged APT snapshot" +ssh "${TIME_BASED_SNAPSHOTS_USER}@${TIME_BASED_SNAPSHOTS_HOST}" \ + sudo -n /usr/local/sbin/tails-publish-tagged-apt-snapshot \ + "$REMOTE_DEST_DIR" "$TAG" + +echo "I: Cleaning up" +ssh "${TIME_BASED_SNAPSHOTS_USER}@${TIME_BASED_SNAPSHOTS_HOST}" \ + rm "$REMOTE_BUILD_MANIFEST" diff --git a/build-website b/build-website new file mode 100755 index 0000000000000000000000000000000000000000..f5001d0858aa9d4ca0dd31f1747afd7d9c1af4f7 --- /dev/null +++ b/build-website @@ -0,0 +1,28 @@ +#!/bin/sh + +set -e +set -u + +FATAL_SANITY_CHECK=yes + +# Parse arguments aimed at this wrapper, and drop them from $@ so we +# can pass it on to ikiwiki. +for arg in "${@}"; do + shift + if [ "${arg}" = --non-fatal-sanity-check ]; then + FATAL_SANITY_CHECK=no + continue + fi + set -- "${@}" "${arg}" +done + +git_dir="$(git rev-parse --show-toplevel)" +if ! "${git_dir}/bin/sanity-check-website" ; then + if [ "${FATAL_SANITY_CHECK}" != no ]; then + echo "Some pages in our wiki are bad! Please fix them or re-run" \ + "with the --non-fatal-sanity-check option" >&2 + exit 1 + fi +fi + +ikiwiki -setup ikiwiki.setup -refresh "$@" diff --git a/config/APT_overlays.d/.placeholder b/config/APT_overlays.d/.placeholder new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/config/APT_snapshots.d/.placeholder b/config/APT_snapshots.d/.placeholder new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/config/APT_snapshots.d/debian-security/serial b/config/APT_snapshots.d/debian-security/serial new file mode 100644 index 0000000000000000000000000000000000000000..a0f9a4b4bc907de626292ea1edbab06250694827 --- /dev/null +++ b/config/APT_snapshots.d/debian-security/serial @@ -0,0 +1 @@ +latest diff --git a/config/APT_snapshots.d/debian/serial b/config/APT_snapshots.d/debian/serial new file mode 100644 index 0000000000000000000000000000000000000000..17f525aceb0240a65fce25e1113c7b799663d266 --- /dev/null +++ b/config/APT_snapshots.d/debian/serial @@ -0,0 +1 @@ +2019061901 diff --git a/config/APT_snapshots.d/torproject/serial b/config/APT_snapshots.d/torproject/serial new file mode 100644 index 0000000000000000000000000000000000000000..462eb2fd192ad1fdf54782419b49b866fe922c43 --- /dev/null +++ b/config/APT_snapshots.d/torproject/serial @@ -0,0 +1 @@ +2019060802 diff --git a/config/amnesia b/config/amnesia new file mode 100644 index 0000000000000000000000000000000000000000..03023eb98c2fabfca6cef3d6c098603552c793aa --- /dev/null +++ b/config/amnesia @@ -0,0 +1,51 @@ +# -*- mode: sh; -*- + +# Configuration file for the Amnesia live system +# +# You'd better never directly edit this file: rather put your custom +# variable assignments in a new file called 'amnesia.local', in the +# same directory as this one. The values found in the '.local' file +# will override the ones from this one. +# +# These configuration files are actually shell scripts, and are +# sourced by various other scripts. + +export SOURCE_DATE_EPOCH="$(date --utc --date="$(dpkg-parsechangelog --show-field=Date)" +%s)" +export SOURCE_DATE_YYYYMMDD="$(date --utc --date="$(dpkg-parsechangelog --show-field=Date)" +%Y%m%d)" +export SOURCE_DATE_FAKETIME="$(date --utc --date="$(dpkg-parsechangelog --show-field=Date)" '+%Y-%m-%d %H:%M:%S')" + +# Base for the string that will be passed to "lb config --bootappend-live" +# FIXME: see [[bugs/sdmem_on_eject_broken_for_CD]] for explanation why we +# need to set block.events_dfl_poll_msecs +AMNESIA_APPEND="live-media=removable nopersistence noprompt timezone=Etc/UTC block.events_dfl_poll_msecs=1000 splash noautologin module=Tails slab_nomerge slub_debug=FZP mce=0 vsyscall=none page_poison=1 mds=full,nosmt union=aufs" + +# Options passed to isohybrid +AMNESIA_ISOHYBRID_OPTS="-h 255 -s 63 --id 42 --verbose" + +# Kernel version +KERNEL_VERSION='4.19.0-5' +KERNEL_SOURCE_VERSION=$( + echo "$KERNEL_VERSION" \ + | perl -p -E 's{\A (\d+ [.] \d+) [.] .*}{$1}xms' +) + +### You should not have to change anything below this line #################### + +# sanity checks +if [ ! -x "`which dpkg-parsechangelog`" ]; then + echo "could not find dpkg-parsechangelog, please apt-get install dpkg-dev" >&2 + exit 2 +fi + +# Compute the current Amnesia's version once for all +AMNESIA_NOW="`date --utc '+%Y%m%dT%H%MZ'`" +AMNESIA_VERSION="`dpkg-parsechangelog -SVersion`" +AMNESIA_FULL_VERSION="${AMNESIA_VERSION} - ${SOURCE_DATE_YYYYMMDD}" + +# Developpers' data used by git-dch, debcommit and friends in the release script +AMNESIA_DEV_FULLNAME='Tails developers' +AMNESIA_DEV_EMAIL="tails@boum.org" +AMNESIA_DEV_KEYID="A490 D0F4 D311 A415 3E2B B7CA DBB8 02B2 58AC D84F" + +# Used to set a custom home page if the distribution is UNRELEASED +TAILS_DISTRIBUTION="`dpkg-parsechangelog -SDistribution`" diff --git a/config/base_branch b/config/base_branch new file mode 100644 index 0000000000000000000000000000000000000000..2bf5ad0447d3370461c6f32a0a5bc8a3177376aa --- /dev/null +++ b/config/base_branch @@ -0,0 +1 @@ +stable diff --git a/config/binary_local-hooks/05-check_initramfs-size b/config/binary_local-hooks/05-check_initramfs-size new file mode 100755 index 0000000000000000000000000000000000000000..a5466e985ca37732292ced39c3660d556d1706df --- /dev/null +++ b/config/binary_local-hooks/05-check_initramfs-size @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'checking the size of the initramfs')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/common config/binary +Set_defaults + +Echo_message "checking the size of the initramfs" + +INITRAMFS=$(readlink --canonicalize binary/live/initrd.img) +MAX_SIZE=$((35 * 1024 * 1024)) # in bytes +ACTUAL_SIZE=$(stat --format='%s' "$INITRAMFS") +if [ "$ACTUAL_SIZE" -gt "$MAX_SIZE" ]; then + echo "E: initramfs is larger ($ACTUAL_SIZE bytes) than the maximum allowed ($MAX_SIZE)" >&2 + exit 1 +fi diff --git a/config/binary_local-hooks/10-syslinux_customize b/config/binary_local-hooks/10-syslinux_customize new file mode 100755 index 0000000000000000000000000000000000000000..6d71ef69accd0b357cb02508edee375ba6a8ec78 --- /dev/null +++ b/config/binary_local-hooks/10-syslinux_customize @@ -0,0 +1,65 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'removing buggy syslinux help')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/common config/binary +Set_defaults + +if [ "${LB_BOOTLOADER}" != "syslinux" ] +then + exit 0 +fi + +# Setting boot method specific variables +case "${LB_BINARY_IMAGES}" in + iso|iso-hybrid) + SYSLINUX_PATH="binary/isolinux" + ;; + usb-hdd) + SYSLINUX_PATH="binary/syslinux" + ;; +esac + +Echo_message "customize buggy syslinux help" + +# Remove help menu entry from menu.cfg (and every line after) +CFG_FILE="${SYSLINUX_PATH}/menu.cfg" +perl -pni -E 'exit if m{^label[[:blank:]]+help$}' "${CFG_FILE}" + +Echo_message "customize syslinux menu" + +sed -i -e "s/Boot menu//" "${CFG_FILE}" +sed -i -e "s/menu label Live/menu label Tails/" "${SYSLINUX_PATH}"/live*.cfg +sed -i -r -e 's/(menu label .* )\(failsafe\)/\1(Troubleshooting Mode)/' \ + "${SYSLINUX_PATH}"/live*.cfg +sed -i -r -e 's/(append .*)/\1\n\tsysappend 0x40000/g' "${SYSLINUX_PATH}"/live*.cfg + +cat > "${SYSLINUX_PATH}/tails.cfg" << EOF +menu color sel * #ffffffff #55555555 * +menu color hotsel 1;7;37;40 #ffffffff #22222222 * + +menu width 53 +menu vshift 12 +menu rows 7 +menu helpmsgrow 15 +menu cmdlinerow 13 +menu timeoutrow 16 +menu tabmsgrow 18 +EOF + +sed -i -e '/^include stdmenu\.cfg/a include tails.cfg' "${CFG_FILE}" + +# no need to use absolute paths to find splash images +sed -e 's,/isolinux/,,' -i "${SYSLINUX_PATH}/stdmenu.cfg" + +# remove useless files that break incremental upgrades +rm "${SYSLINUX_PATH}"/{exithelp,prompt}.cfg diff --git a/config/binary_local-hooks/20-syslinux_detect_cpu b/config/binary_local-hooks/20-syslinux_detect_cpu new file mode 100755 index 0000000000000000000000000000000000000000..0aa98e640a9be56c2d5f23ac054259e6d2209769 --- /dev/null +++ b/config/binary_local-hooks/20-syslinux_detect_cpu @@ -0,0 +1,88 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'adding CPU autodetection to the syslinux menu')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/bootstrap config/common config/binary +Set_defaults + +# Safeguards +[ "${LB_BOOTLOADER}" = "syslinux" ] || exit 0 +[ "${LB_ARCHITECTURE}" = "amd64" ] || exit 0 + +# Seems like we'll have work to do +Echo_message "adding CPU autodetection to the syslinux menu" + +# Setting boot method specific variables +case "${LB_BINARY_IMAGES}" in + iso|iso-hybrid) + SYSLINUX_PATH="binary/isolinux" + SYSLINUX_CFG="${SYSLINUX_PATH}/isolinux.cfg" + ;; + usb-hdd) + SYSLINUX_PATH="binary/syslinux" + SYSLINUX_CFG="${SYSLINUX_PATH}/syslinux.cfg" + ;; +esac + +# Setting variables +SYSLINUX_LIVE_CFG="${SYSLINUX_PATH}/live.cfg" +SYSLINUX_MENU_CFG="${SYSLINUX_PATH}/menu.cfg" + +# Checking depends +Check_package chroot/usr/bin/syslinux syslinux + +# Restoring cache +Restore_cache cache/packages_binary + +# Installing depends +Install_package + +# Copy necessary syslinux modules +for module in cat.c32 ifcpu64.c32 +do + cp "chroot/usr/lib/syslinux/modules/bios/${module}" "${SYSLINUX_PATH}/" +done + +# Saving cache +Save_cache cache/packages_binary + +# Removing depends +Remove_package + +# Replace syslinux.cfg with autodetection "code" +cat > "${SYSLINUX_CFG}" < "${SYSLINUX_PATH}/live64.cfg" + +# Don't load live.cfg from menu.cfg: +# syslinux_cfg automatically loads arch-specific menus +sed -i -e '/^include live\.cfg/d' "${SYSLINUX_MENU_CFG}" diff --git a/config/binary_local-hooks/30-syslinux_fixup b/config/binary_local-hooks/30-syslinux_fixup new file mode 100755 index 0000000000000000000000000000000000000000..e545ca33a408c3d79c59aa5934b0de66428f9e2f --- /dev/null +++ b/config/binary_local-hooks/30-syslinux_fixup @@ -0,0 +1,38 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'fixing syslinux installation')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/bootstrap config/common config/binary +Set_defaults + +# Safeguards +[ "${LB_BOOTLOADER}" = "syslinux" ] || exit 0 +[ "${LB_ARCHITECTURE}" = "amd64" ] || exit 0 + +# Seems like we'll have work to do +Echo_message "fixing syslinux installation" + +# Setting boot method specific variables +case "${LB_BINARY_IMAGES}" in + iso|iso-hybrid) + SYSLINUX_PATH="binary/isolinux" + ;; + usb-hdd) + SYSLINUX_PATH="binary/syslinux" + ;; +esac + +# Main +for module in ldlinux libcom32 libutil +do + cp chroot/usr/lib/syslinux/modules/bios/"${module}.c32" "$SYSLINUX_PATH" +done diff --git a/config/binary_local-hooks/40-include_syslinux_in_ISO_filesystem b/config/binary_local-hooks/40-include_syslinux_in_ISO_filesystem new file mode 100755 index 0000000000000000000000000000000000000000..7927fde3c212e6666540f62ce86ccfd5f7e50ad1 --- /dev/null +++ b/config/binary_local-hooks/40-include_syslinux_in_ISO_filesystem @@ -0,0 +1,58 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'including syslinux in the ISO filesystem')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/bootstrap config/common config/binary +Set_defaults + +# Safeguards +[ "${LB_BOOTLOADER}" = "syslinux" ] || exit 0 +[ "${LB_ARCHITECTURE}" = "amd64" ] || exit 0 + +# Seems like we'll have work to do +Echo_message 'including syslinux in the ISO filesystem' + +### Functions + +syslinux_deb_version_in_chroot () { + chroot chroot dpkg-query -W -f='${Version}\n' syslinux +} + +### Variables +LINUX_BINARY_UTILS_DIR='binary/utils/linux' +WIN32_BINARY_UTILS_DIR='binary/utils/win32' +BINARY_MBR_DIR='binary/utils/mbr' +CHROOT_SYSLINUX_BIN='chroot/usr/bin/syslinux' +CHROOT_SYSLINUX_MBR='chroot/usr/lib/SYSLINUX/gptmbr.bin' +CHROOT_TEMP_APT_SOURCES='chroot/etc/apt/sources.list.d/tmp-deb-src.list' + +### Main +mkdir -p "$LINUX_BINARY_UTILS_DIR" "$WIN32_BINARY_UTILS_DIR" "$BINARY_MBR_DIR" +cp "$CHROOT_SYSLINUX_BIN" "$LINUX_BINARY_UTILS_DIR/" +cp "$CHROOT_SYSLINUX_MBR" "$BINARY_MBR_DIR/mbr.bin" + +cat chroot/etc/apt/sources.list chroot/etc/apt/sources.list.d/*.list \ + | grep --extended-regexp --invert-match \ + 'file:/root/local-packages' \ + | grep --extended-regexp --invert-match \ + '^deb\s+http://tagged\.snapshots\.deb\.tails\.boum.org/[^/]+/torproject(/|\s)' \ + | grep --extended-regexp --invert-match \ + '^deb\s+http://time-based\.snapshots\.deb\.tails\.boum.org/torproject/' \ + | sed --regexp-extended -e 's,^deb(\s+),deb-src\1,' \ + > "$CHROOT_TEMP_APT_SOURCES" +Chroot chroot apt-get --yes update +Chroot chroot apt-get --yes install dpkg-dev +Chroot chroot apt-get source syslinux="$(syslinux_deb_version_in_chroot)" +cp chroot/syslinux-*/bios/win32/syslinux.exe "$WIN32_BINARY_UTILS_DIR/" +rm -r chroot/syslinux* +rm "$CHROOT_TEMP_APT_SOURCES" +Chroot chroot apt-get --yes purge dpkg-dev make # dpkg-dev depends on make diff --git a/config/binary_local-hooks/50-grub-efi-ia32 b/config/binary_local-hooks/50-grub-efi-ia32 new file mode 100755 index 0000000000000000000000000000000000000000..6ca3c764fc4b606aa67d4bdc0d99936ac7d9e7f0 --- /dev/null +++ b/config/binary_local-hooks/50-grub-efi-ia32 @@ -0,0 +1,87 @@ +#! /bin/sh + +# Some of this file was adapted from the Debian Installer's +# build/util/efi-image, which is: +# +# Copyright (C) 2010, 2011 Canonical Ltd. +# Author: Colin Watson +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +set -e +set -x + +platform="i386-efi" +outdir="binary/EFI/BOOT/grub/$platform" +efi_name="IA32" + +grub_cpmodules () { + if [ -z "$1" ] || [ -z "$2" ]; then + echo "usage: $0 OUTPUT-DIRECTORY GRUB-PLATFORM" + return 1 + fi + + outdir="$1" + platform="$2" + + # Copy over GRUB modules, except for those already built in. + cp -a "chroot/usr/lib/grub/$platform"/*.lst "$outdir/" + for x in "chroot/usr/lib/grub/$platform"/*.mod; do + # Some of these exclusions are based on knowledge of module + # dependencies. + case $(basename "$x" .mod) in + configfile|search|search_fs_file|search_fs_uuid|search_label|tar|part_gpt|linux|gzio) + # included in boot image + ;; + affs|afs|afs_be|befs|befs_be|minix|nilfs2|sfs|zfs|zfsinfo) + # unnecessary filesystem modules + ;; + example_functional_test|functional_test|hello) + # other cruft + ;; + *) + cp -a "$x" "$outdir/" + ;; + esac + done +} + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'including GRUB EFI for ia32 in the ISO filesystem')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/bootstrap config/common config/binary +Set_defaults + +# Safeguards +[ "${LB_ARCHITECTURE}" = "amd64" ] || exit 0 + +# Seems like we'll have work to do +Echo_message 'including GRUB EFI for ia32 in the ISO filesystem' + +# Build the core image +Chroot chroot grub-mkimage -O "$platform" \ + -o "/tmp/BOOT$efi_name.EFI" -p "/efi/boot/grub" \ + search configfile normal tar fat part_gpt linux \ + gzio +mv "chroot/tmp/BOOT$efi_name.EFI" "binary/EFI/BOOT/BOOT$efi_name.EFI" + +mkdir -p "$outdir" +grub_cpmodules "$outdir" "$platform" diff --git a/config/binary_local-hooks/99-syslinux_uefi b/config/binary_local-hooks/99-syslinux_uefi new file mode 100755 index 0000000000000000000000000000000000000000..791c88968160d8a76f09ce5e533e16ef5e7427f4 --- /dev/null +++ b/config/binary_local-hooks/99-syslinux_uefi @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e + +# Including common functions +. "${LB_BASE:-/usr/share/live/build}"/scripts/build.sh + +# Setting static variables +DESCRIPTION="$(Echo 'installing syslinux UEFI bootloader')" +HELP="" +USAGE="${PROGRAM}" + +# Reading configuration files +Read_conffiles config/all config/bootstrap config/common config/binary +Set_defaults + +# Safeguards +[ "${LB_BOOTLOADER}" = "syslinux" ] || exit 0 +[ "${LB_ARCHITECTURE}" = "amd64" ] || exit 0 + +# Seems like we'll have work to do +Echo_message "installing syslinux UEFI bootloader" + +# Setting boot method specific variables +case "${LB_BINARY_IMAGES}" in + iso|iso-hybrid) + SYSLINUX_PATH="binary/isolinux" + ;; + usb-hdd) + SYSLINUX_PATH="binary/syslinux" + ;; +esac + +# Main +mkdir -p binary/EFI/BOOT +cp chroot/usr/lib/SYSLINUX.EFI/efi64/syslinux.efi binary/EFI/BOOT/BOOTX64.EFI +cp chroot/usr/share/tails/bootx64.png binary/EFI/BOOT/BOOTX64.PNG +cp "$SYSLINUX_PATH"/* binary/EFI/BOOT/ +mv binary/EFI/BOOT/isolinux.cfg binary/EFI/BOOT/syslinux.cfg +cp -f chroot/usr/lib/syslinux/modules/efi64/* binary/EFI/BOOT/ +sed -r -i -e 's,^(menu background splash\.png)$,\#\1,' binary/EFI/BOOT/stdmenu.cfg diff --git a/config/binary_local-includes/EFI/BOOT/grub/grub.cfg b/config/binary_local-includes/EFI/BOOT/grub/grub.cfg new file mode 100644 index 0000000000000000000000000000000000000000..7a5f5a79b7805138eeb3409d152848e2c331caec --- /dev/null +++ b/config/binary_local-includes/EFI/BOOT/grub/grub.cfg @@ -0,0 +1,22 @@ +function load_video { + if [ x$feature_all_video_module = xy ]; then + insmod all_video + else + insmod efi_gop + insmod efi_uga + insmod ieee1275_fb + insmod vbe + insmod vga + insmod video_bochs + insmod video_cirrus + fi +} + +set linux_gfx_mode= +export linux_gfx_mode +load_video + +insmod syslinuxcfg +insmod cpuid +echo "Loading syslinux configuration..." +syslinux_configfile /efi/boot/syslinux.cfg diff --git a/config/binary_local-includes/isolinux/sorry32.txt b/config/binary_local-includes/isolinux/sorry32.txt new file mode 100644 index 0000000000000000000000000000000000000000..8941a282a1a256ca5c5ce86aaf7ae3689d56c6ce --- /dev/null +++ b/config/binary_local-includes/isolinux/sorry32.txt @@ -0,0 +1,12 @@ + + + +We are sorry! + +Tails can not work on this computer: +Tails now requires a 64-bit computer. + +For more information, see: +https://tails.boum.org/doc/about/requirements/ + + diff --git a/config/binary_local-includes/live/Tails.module b/config/binary_local-includes/live/Tails.module new file mode 100644 index 0000000000000000000000000000000000000000..6def2a095fcb192fabc901f3ef10bcbdf517c31d --- /dev/null +++ b/config/binary_local-includes/live/Tails.module @@ -0,0 +1 @@ +filesystem.squashfs diff --git a/config/binary_rootfs/squashfs.sort b/config/binary_rootfs/squashfs.sort new file mode 100644 index 0000000000000000000000000000000000000000..d5d2b9c04a52358c95564dfbe97f84809213eafc --- /dev/null +++ b/config/binary_rootfs/squashfs.sort @@ -0,0 +1,4319 @@ +bin/sed 32767 +etc/ld.so.cache 32766 +bin/rm 32765 +bin/setupcon 32764 +bin/dash 32763 +etc/default/console-setup 32762 +etc/default/keyboard 32761 +bin/uname 32760 +bin/ls 32759 +bin/stty 32758 +bin/egrep 32757 +bin/grep 32756 +etc/apparmor/parser.conf 32755 +etc/apparmor/subdomain.conf 32754 +etc/apparmor.d/torbrowser.Browser.plugin-container 32751 +etc/apparmor.d/tunables/global 32750 +etc/apparmor.d/tunables/home 32749 +etc/apparmor.d/tunables/home.d/site.local 32748 +etc/apparmor.d/tunables/home.d/tails 32747 +etc/apparmor.d/tunables/home.d/ubuntu 32746 +etc/apparmor.d/tunables/multiarch 32745 +etc/apparmor.d/tunables/multiarch.d/site.local 32744 +etc/apparmor.d/tunables/proc 32743 +etc/apparmor.d/tunables/alias 32742 +etc/apparmor.d/tunables/alias.d/tails 32741 +etc/apparmor.d/tunables/kernelvars 32740 +etc/apparmor.d/tunables/xdg-user-dirs 32739 +etc/apparmor.d/tunables/xdg-user-dirs.d/site.local 32738 +etc/apparmor.d/tunables/torbrowser 32737 +etc/apparmor.d/abstractions/gnome 32736 +etc/apparmor.d/abstractions/base 32735 +etc/apparmor.d/abstractions/fonts 32734 +etc/apparmor.d/abstractions/X 32733 +etc/apparmor.d/abstractions/freedesktop.org 32732 +etc/apparmor.d/abstractions/xdg-desktop 32731 +etc/apparmor.d/abstractions/user-tmp 32730 +etc/apparmor.d/abstractions/wayland 32729 +etc/apparmor.d/abstractions/audio 32728 +bin/cat 32723 +etc/console-setup/cached_setup_font.sh 32722 +etc/console-setup/cached_setup_terminal.sh 32720 +bin/chmod 32718 +bin/kbd_mode 32717 +bin/setfont 32716 +bin/gzip 32715 +lib/x86_64-linux-gnu/ld-2.24.so 32714 +lib/x86_64-linux-gnu/libc-2.24.so 32713 +lib/x86_64-linux-gnu/libpcre.so.3.13.3 32712 +lib/x86_64-linux-gnu/libdl-2.24.so 32711 +lib/x86_64-linux-gnu/libpthread-2.24.so 32710 +etc/sysctl.conf 32709 +sbin/apparmor_parser 32708 +lib/x86_64-linux-gnu/libm-2.24.so 32707 +etc/apparmor.d/usr.bin.evince 32706 +etc/apparmor.d/abstractions/bash 32705 +etc/apparmor.d/abstractions/cups-client 32704 +etc/apparmor.d/abstractions/dbus 32703 +etc/apparmor.d/abstractions/dbus-strict 32702 +etc/apparmor.d/abstractions/dbus-session 32701 +etc/apparmor.d/abstractions/dbus-session-strict 32700 +etc/apparmor.d/abstractions/dbus-accessibility 32699 +etc/apparmor.d/abstractions/dbus-accessibility-strict 32698 +etc/apparmor.d/abstractions/evince 32697 +etc/apparmor.d/abstractions/p11-kit 32696 +etc/apparmor.d/abstractions/ubuntu-helpers 32695 +etc/apparmor.d/abstractions/private-files 32694 +etc/apparmor.d/local/usr.bin.evince 32693 +etc/apparmor.d/abstractions/ibus 32692 +etc/apparmor.d/abstractions/nameservice 32691 +etc/apparmor.d/abstractions/nis 32690 +etc/apparmor.d/abstractions/ldapclient 32689 +etc/apparmor.d/abstractions/ssl_certs 32688 +etc/apparmor.d/abstractions/winbind 32687 +etc/apparmor.d/abstractions/likewise 32686 +etc/apparmor.d/abstractions/mdns 32685 +etc/apparmor.d/abstractions/kerberosclient 32684 +etc/apparmor.d/abstractions/ubuntu-browsers 32683 +etc/apparmor.d/abstractions/ubuntu-console-browsers 32682 +etc/apparmor.d/abstractions/ubuntu-email 32681 +etc/apparmor.d/abstractions/ubuntu-console-email 32680 +etc/apparmor.d/abstractions/ubuntu-media-players 32679 +etc/apparmor.d/abstractions/ubuntu-gnome-terminal 32678 +usr/lib/locale/aa_DJ.utf8/LC_COLLATE 32677 +usr/lib/locale/aa_DJ.utf8/LC_CTYPE 32676 +bin/loadkeys 32673 +usr/lib/locale/aa_ET/LC_NUMERIC 32672 +lib/live/mount/overlay/etc/console-setup/cached_UTF-8_del.kmap.gz 32671 +etc/console-setup/cached_UTF-8_del.kmap.gz 32670 +usr/lib/locale/en_US.utf8/LC_IDENTIFICATION 32669 +usr/lib/locale/chr_US/LC_MEASUREMENT 32668 +usr/lib/locale/chr_US/LC_TELEPHONE 32667 +usr/lib/locale/en_US.utf8/LC_ADDRESS 32666 +usr/lib/locale/chr_US/LC_NAME 32665 +usr/lib/locale/chr_US/LC_PAPER 32664 +usr/lib/locale/en_AG/LC_MESSAGES/SYS_LC_MESSAGES 32663 +usr/lib/locale/chr_US/LC_MONETARY 32662 +usr/lib/locale/en_US.utf8/LC_TIME 32661 +etc/apparmor.d/usr.bin.irssi 32660 +etc/apparmor.d/abstractions/perl 32659 +etc/apparmor.d/abstractions/wutmp 32658 +etc/apparmor.d/local/usr.bin.irssi 32657 +usr/share/apparmor-features/features 32654 +usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache 32653 +etc/apparmor.d/usr.bin.onioncircuits 32652 +etc/apparmor.d/abstractions/python 32651 +etc/apparmor.d/local/usr.bin.onioncircuits 32650 +lib/live/config/0001-sane-clock 32647 +lib/x86_64-linux-gnu/libselinux.so.1 32646 +etc/amnesia/version 32645 +bin/date 32644 +usr/share/zoneinfo/UCT 32643 +lib/live/config/0010-debconf 32642 +lib/live/config/0020-hostname 32640 +etc/hostname 32639 +etc/hosts 32638 +bin/hostname 32636 +bin/touch 32635 +lib/live/config/0030-live-debconfig_passwd 32633 +lib/live/config/0030-user-setup 32632 +usr/bin/debconf-set-selections 32629 +usr/bin/perl 32628 +lib/x86_64-linux-gnu/libcrypt-2.24.so 32627 +etc/perl/sitecustomize.pl 32626 +usr/share/perl/5.24.1/warnings.pm 32625 +usr/share/perl/5.24.1/strict.pm 32624 +usr/share/perl5/Debconf/Db.pm 32623 +usr/share/perl5/Debconf/Log.pm 32622 +usr/share/perl/5.24.1/base.pm 32621 +usr/share/perl/5.24.1/vars.pm 32620 +usr/share/perl/5.24.1/warnings/register.pm 32619 +usr/share/perl/5.24.1/Exporter.pm 32618 +usr/share/perl5/Debconf/Config.pm 32617 +usr/share/perl5/Debconf/Question.pm 32616 +usr/share/perl5/Debconf/Template.pm 32615 +usr/lib/x86_64-linux-gnu/perl/5.24.1/POSIX.pm 32614 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Fcntl.pm 32613 +usr/share/perl/5.24.1/XSLoader.pm 32612 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Fcntl/Fcntl.so 32611 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/POSIX/POSIX.so 32610 +usr/share/perl/5.24.1/Tie/Hash.pm 32609 +usr/share/perl/5.24.1/Carp.pm 32608 +usr/share/perl/5.24.1/Exporter/Heavy.pm 32607 +usr/share/perl/5.24.1/FileHandle.pm 32606 +usr/lib/x86_64-linux-gnu/perl/5.24.1/IO/File.pm 32605 +usr/share/perl/5.24.1/Symbol.pm 32604 +usr/share/perl/5.24.1/SelectSaver.pm 32603 +usr/lib/x86_64-linux-gnu/perl/5.24.1/IO/Seekable.pm 32602 +usr/lib/x86_64-linux-gnu/perl/5.24.1/IO/Handle.pm 32601 +usr/lib/x86_64-linux-gnu/perl/5.24.1/IO.pm 32600 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/IO/IO.so 32599 +usr/share/perl5/Debconf/Gettext.pm 32598 +usr/lib/x86_64-linux-gnu/perl5/5.24/Locale/gettext.pm 32597 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Encode.pm 32596 +usr/share/perl/5.24.1/constant.pm 32595 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Encode/Alias.pm 32594 +usr/share/perl/5.24.1/bytes.pm 32593 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Encode/Encode.so 32592 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Encode/Config.pm 32591 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Encode/Encoding.pm 32590 +usr/lib/x86_64-linux-gnu/perl/5.24.1/DynaLoader.pm 32589 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Config.pm 32588 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Locale/gettext/gettext.so 32587 +usr/share/perl/5.24.1/Text/Wrap.pm 32586 +usr/share/perl/5.24.1/Text/Tabs.pm 32585 +usr/lib/x86_64-linux-gnu/perl/5.24.1/re.pm 32584 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/re/re.so 32583 +usr/share/perl5/Debconf/Iterator.pm 32582 +usr/share/perl5/Debconf/Base.pm 32581 +usr/share/perl/5.24.1/fields.pm 32580 +usr/share/perl5/Debconf/Encoding.pm 32579 +usr/lib/x86_64-linux-gnu/perl5/5.24/Text/Iconv.pm 32578 +usr/share/perl/5.24.1/AutoLoader.pm 32577 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Text/Iconv/Iconv.so 32576 +usr/bin/locale 32575 +usr/share/perl5/Text/WrapI18N.pm 32574 +usr/lib/x86_64-linux-gnu/perl5/5.24/Text/CharWidth.pm 32573 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Text/CharWidth/CharWidth.so 32572 +usr/share/perl/5.24.1/overload.pm 32571 +usr/share/perl/5.24.1/overloading.pm 32570 +usr/share/perl5/Debconf/Priority.pm 32569 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Hash/Util.pm 32568 +usr/lib/x86_64-linux-gnu/perl5/5.24/Scalar/Util.pm 32567 +usr/lib/x86_64-linux-gnu/perl5/5.24/List/Util.pm 32566 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/List/Util/Util.so 32565 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Hash/Util/Util.so 32564 +etc/nsswitch.conf 32563 +lib/x86_64-linux-gnu/libnss_compat-2.24.so 32562 +lib/x86_64-linux-gnu/libnsl-2.24.so 32561 +lib/x86_64-linux-gnu/libnss_nis-2.24.so 32560 +lib/x86_64-linux-gnu/libnss_files-2.24.so 32559 +usr/share/perl5/Debconf/DbDriver.pm 32556 +usr/share/perl/5.24.1/Getopt/Long.pm 32555 +etc/debconf.conf 32554 +usr/share/perl5/Debconf/DbDriver/File.pm 32553 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Cwd.pm 32552 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Cwd/Cwd.so 32551 +usr/share/perl5/Debconf/DbDriver/Cache.pm 32550 +usr/share/perl5/Debconf/Format/822.pm 32549 +usr/share/perl5/Debconf/Format.pm 32548 +usr/share/perl5/Debconf/DbDriver/Stack.pm 32545 +usr/share/perl5/Debconf/DbDriver/Copy.pm 32544 +usr/lib/user-setup/user-setup-apply 32539 +usr/share/debconf/confmodule 32538 +usr/share/debconf/frontend 32537 +usr/share/perl5/Debconf/AutoSelect.pm 32536 +usr/share/perl5/Debconf/ConfModule.pm 32535 +usr/share/perl/5.24.1/IPC/Open2.pm 32534 +usr/share/perl/5.24.1/IPC/Open3.pm 32533 +usr/share/perl5/Debconf/FrontEnd/Noninteractive.pm 32532 +usr/share/perl5/Debconf/FrontEnd.pm 32531 +usr/lib/user-setup/functions.sh 32530 +sbin/shadowconfig 32529 +usr/sbin/pwck 32528 +etc/login.defs 32527 +usr/sbin/grpck 32526 +usr/sbin/pwconv 32521 +etc/.pwd.lock 32520 +usr/sbin/grpconv 32515 +bin/chown 32502 +usr/bin/cut 32501 +usr/bin/dpkg-query 32499 +var/lib/dpkg/status 32498 +var/lib/dpkg/triggers/File 32497 +var/lib/dpkg/triggers/Unincorp 32496 +usr/bin/dpkg 32495 +etc/dpkg/dpkg.cfg.d/pkg-config-hook-config 32494 +etc/dpkg/dpkg.cfg 32493 +usr/sbin/usermod 32492 +lib/x86_64-linux-gnu/libaudit.so.1.0.0 32491 +usr/lib/x86_64-linux-gnu/libsemanage.so.1 32490 +lib/x86_64-linux-gnu/libcap-ng.so.0.0.0 32489 +lib/x86_64-linux-gnu/libsepol.so.1 32488 +lib/x86_64-linux-gnu/libbz2.so.1.0.4 32487 +usr/lib/x86_64-linux-gnu/libustr-1.0.so.1.0.4 32486 +usr/sbin/adduser 32473 +usr/share/perl5/Debian/AdduserCommon.pm 32472 +usr/lib/x86_64-linux-gnu/perl/5.24.1/I18N/Langinfo.pm 32471 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/I18N/Langinfo/Langinfo.so 32470 +etc/adduser.conf 32469 +usr/sbin/groupadd 32468 +usr/sbin/useradd 32463 +etc/default/useradd 32462 +var/log/faillog 32447 +var/log/lastlog 32445 +usr/bin/find 32435 +lib/live/mount/overlay/etc/skel/.config/autostart/end-profile.desktop 32434 +etc/skel/.config/autostart/end-profile.desktop 32433 +etc/skel/.config/Trolltech.conf 32432 +etc/skel/.config/keepassx/keepassx2.ini 32431 +etc/skel/.bash_logout 32430 +etc/skel/.bashrc 32429 +etc/skel/.electrum/config 32428 +etc/skel/.gnome2/accels/.placeholder 32427 +etc/skel/.gnome2/keyrings/default 32426 +etc/skel/.gnome2/keyrings/tails.keyring 32425 +etc/skel/.gnome2_private/.placeholder 32424 +etc/skel/.gnupg/dirmngr.conf 32423 +etc/skel/.gnupg/gpg-agent.conf 32422 +etc/skel/.gnupg/gpg.conf 32421 +etc/skel/.local/share/applications/mimeapps.list 32420 +etc/skel/.monkeysphere/monkeysphere.conf 32419 +etc/skel/.mozilla/firefox/bookmarks/places.sqlite 32418 +etc/skel/.poedit/config 32417 +etc/skel/.profile 32416 +etc/skel/.purple/accounts.xml 32415 +etc/skel/.purple/blist.xml 32414 +etc/skel/.purple/prefs.xml 32413 +etc/skel/.tor-browser/profile.default/chrome/userChrome.css 32412 +etc/skel/.tor-browser/profile.default/prefs.js 32411 +etc/skel/.xsessionrc 32410 +etc/skel/Desktop/Report_an_error.desktop 32409 +etc/skel/Desktop/tails-documentation.desktop 32408 +usr/bin/chfn 32403 +lib/x86_64-linux-gnu/libpam.so.0.83.1 32402 +lib/x86_64-linux-gnu/libpam_misc.so.0.82.0 32401 +etc/pam.d/chfn 32400 +lib/x86_64-linux-gnu/security/pam_rootok.so 32399 +etc/pam.d/common-auth 32398 +lib/x86_64-linux-gnu/security/pam_unix.so 32397 +lib/x86_64-linux-gnu/security/pam_deny.so 32396 +lib/x86_64-linux-gnu/security/pam_permit.so 32395 +etc/pam.d/common-account 32394 +etc/pam.d/common-session 32393 +lib/x86_64-linux-gnu/security/pam_systemd.so 32392 +etc/pam.d/other 32391 +etc/pam.d/common-password 32390 +usr/bin/gpasswd 32383 +etc/apparmor.d/usr.bin.totem 32370 +etc/apparmor.d/abstractions/dconf 32369 +etc/apparmor.d/abstractions/totem 32368 +etc/apparmor.d/abstractions/gstreamer 32367 +etc/apparmor.d/abstractions/private-files-strict 32366 +etc/apparmor.d/local/usr.bin.totem 32365 +lib/live/config/0040-sudo 32333 +lib/live/config/0050-locales 32332 +lib/live/config/0060-locales-all 32331 +lib/live/config/0070-tzdata 32328 +etc/timezone 32327 +usr/sbin/dpkg-reconfigure 32325 +var/lib/dpkg/info/format 32324 +var/lib/dpkg/info/tzdata.templates 32323 +var/lib/dpkg/info/tzdata.config 32322 +usr/bin/head 32321 +usr/share/perl5/Debconf/Element/Noninteractive/Select.pm 32320 +usr/share/perl5/Debconf/Element/Noninteractive.pm 32319 +usr/share/perl5/Debconf/Element.pm 32318 +var/lib/dpkg/info/tzdata.postinst 32317 +bin/ln 32316 +bin/mv 32315 +lib/x86_64-linux-gnu/libacl.so.1.1.0 32314 +lib/x86_64-linux-gnu/libattr.so.1.1.0 32313 +bin/which 32312 +lib/live/config/0080-gdm3 32310 +lib/live/config/0085-sddm 32309 +lib/live/config/0090-kdm 32308 +lib/live/config/0100-lightdm 32307 +lib/live/config/0110-lxdm 32306 +lib/live/config/0120-nodm 32305 +lib/live/config/0130-slim 32304 +lib/live/config/0140-xinit 32303 +lib/live/config/0150-keyboard-configuration 32302 +lib/live/config/1000-remount-procfs 32301 +bin/mount 32300 +lib/x86_64-linux-gnu/libmount.so.1.1.0 32299 +lib/x86_64-linux-gnu/libblkid.so.1.1.0 32298 +lib/x86_64-linux-gnu/librt-2.24.so 32297 +lib/x86_64-linux-gnu/libuuid.so.1.3.0 32296 +etc/fstab 32294 +lib/live/config/1020-gnome-panel-data 32290 +lib/live/config/1030-gnome-power-manager 32289 +usr/bin/sudo 32288 +lib/x86_64-linux-gnu/libutil-2.24.so 32287 +usr/lib/sudo/libsudo_util.so.0.0.0 32286 +usr/lib/sudo/sudoers.so 32285 +etc/sudoers 32284 +etc/sudoers.d/README 32283 +etc/sudoers.d/always-ask-password 32282 +etc/sudoers.d/tails-greeter-cryptsetup 32281 +etc/sudoers.d/tails-greeter-live-persist 32280 +etc/sudoers.d/tails-greeter-umount 32279 +etc/sudoers.d/zzz_boot_profile 32278 +etc/sudoers.d/zzz_gdm 32277 +etc/sudoers.d/zzz_halt 32276 +etc/sudoers.d/zzz_persistence-setup 32275 +etc/sudoers.d/zzz_tails-additional-software 32274 +etc/sudoers.d/zzz_tails-debugging-info 32273 +etc/sudoers.d/zzz_unsafe-browser 32272 +etc/sudoers.d/zzz_upgrade 32271 +etc/host.conf 32270 +etc/resolv.conf 32269 +etc/pam.d/sudo 32268 +etc/pam.d/common-session-noninteractive 32267 +lib/live/config/1040-gnome-screensaver 32265 +lib/live/config/1050-kaboom 32264 +lib/live/config/1060-kde-services 32263 +lib/live/config/1080-policykit 32262 +lib/live/config/1090-ssl-cert 32261 +usr/sbin/make-ssl-cert 32260 +bin/bash 32259 +lib/x86_64-linux-gnu/libtinfo.so.5.9 32258 +bin/mktemp 32257 +usr/share/ssl-cert/ssleay.cnf 32256 +usr/bin/openssl 32255 +etc/apparmor.d/usr.bin.totem-previewers 32254 +usr/lib/x86_64-linux-gnu/libssl.so.1.1 32253 +usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 32252 +etc/apparmor.d/local/usr.bin.totem-previewers 32251 +etc/ssl/openssl.cnf 32248 +lib/live/config/1110-anacron 32244 +lib/live/config/1120-util-linux 32243 +lib/live/config/1130-login 32241 +lib/live/config/1140-xserver-xorg 32237 +usr/bin/lspci 32236 +lib/x86_64-linux-gnu/libpci.so.3.5.2 32235 +usr/bin/tr 32234 +lib/x86_64-linux-gnu/libkmod.so.2.3.1 32233 +lib/x86_64-linux-gnu/libz.so.1.2.8 32232 +lib/x86_64-linux-gnu/libresolv-2.24.so 32231 +lib/x86_64-linux-gnu/libudev.so.1.6.13 32230 +usr/bin/mawk 32229 +etc/apparmor.d/usr.sbin.apt-cacher-ng 32228 +etc/apparmor.d/local/usr.sbin.apt-cacher-ng 32227 +etc/apparmor.d/usr.sbin.avahi-daemon 32224 +etc/apparmor.d/abstractions/consoles 32223 +etc/apparmor.d/local/usr.sbin.avahi-daemon 32222 +lib/udev/hwdb.bin 32219 +usr/share/live/config/xserver-xorg/intel.ids 32218 +usr/share/live/config/xserver-xorg/qxl.ids 32217 +lib/live/config/1160-openssh-server 32216 +lib/live/config/1170-xfce4-panel 32215 +lib/live/config/1180-xscreensaver 32214 +lib/live/config/1190-broadcom-sta 32213 +lib/live/config/1500-reconfigure-APT 32212 +lib/live/config/1600-undivert-APT 32190 +usr/bin/dpkg-divert 32189 +usr/bin/apt-get.real 32185 +lib/live/config/2000-aesthetics 32183 +lib/live/config/2000-import-gnupg-key 32182 +usr/bin/gpg 32180 +usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6 32179 +lib/x86_64-linux-gnu/libgcrypt.so.20.1.6 32178 +lib/x86_64-linux-gnu/libreadline.so.7.0 32177 +usr/lib/x86_64-linux-gnu/libassuan.so.0.7.3 32176 +lib/x86_64-linux-gnu/libgpg-error.so.0.21.0 32175 +usr/share/doc/tails/website/tails-accounting.key 32174 +usr/bin/gpg-agent 32173 +usr/lib/x86_64-linux-gnu/libnpth.so.0.0.6 32172 +etc/apparmor.d/usr.sbin.cupsd 32171 +etc/apparmor.d/abstractions/authentication 32170 +etc/apparmor.d/abstractions/smbpass 32169 +etc/apparmor.d/local/usr.sbin.cupsd 32168 +etc/apparmor.d/usr.sbin.haveged 32165 +etc/apparmor.d/local/usr.sbin.haveged 32164 +etc/apparmor.d/usr.sbin.tcpdump 32161 +etc/apparmor.d/local/usr.sbin.tcpdump 32160 +usr/share/doc/tails/website/tails-bugs.key 32157 +usr/share/doc/tails/website/tails-email.key 32156 +usr/share/doc/tails/website/tails-foundations.key 32155 +usr/share/doc/tails/website/tails-mirrors.key 32154 +usr/share/doc/tails/website/tails-press.key 32153 +usr/share/doc/tails/website/tails-signing.key 32152 +etc/apparmor.d/usr.sbin.traceroute 32151 +etc/apparmor.d/local/usr.sbin.traceroute 32150 +usr/share/doc/tails/website/tails-sysadmins.key 32147 +usr/bin/wc 32128 +etc/default/networking 32127 +etc/default/haveged 32126 +sbin/ifup 32124 +lib/live/mount/overlay/etc/network/interfaces 32122 +etc/network/interfaces 32121 +bin/run-parts 32119 +etc/network/if-pre-up.d/ethtool 32118 +etc/macchanger/ifupdown.sh 32117 +etc/default/macchanger 32116 +etc/network/if-pre-up.d/wireless-tools 32113 +sbin/iwconfig 32112 +lib/x86_64-linux-gnu/libiw.so.30 32111 +bin/kmod 32110 +lib/modprobe.d/aliases.conf 32109 +etc/modprobe.d/all-net-blacklist.conf 32108 +etc/modprobe.d/amd64-microcode-blacklist.conf 32107 +lib/modprobe.d/fbdev-blacklist.conf 32106 +etc/modprobe.d/intel-microcode-blacklist.conf 32105 +etc/modprobe.d/loop.conf 32104 +lib/modules/4.19.0-5-amd64/modules.softdep 32103 +etc/modprobe.d/no-bluetooth.conf 32102 +etc/modprobe.d/no-conntrack-helper.conf 32101 +etc/modprobe.d/no-mei.conf 32100 +etc/modprobe.d/no-n-hdlc.conf 32099 +etc/modprobe.d/no-pc-speaker.conf 32098 +lib/modprobe.d/systemd.conf 32097 +etc/modprobe.d/uncommon-network-protocols.conf 32096 +lib/modules/4.19.0-5-amd64/modules.dep.bin 32095 +lib/modules/4.19.0-5-amd64/modules.alias.bin 32094 +lib/modules/4.19.0-5-amd64/modules.symbols.bin 32093 +lib/modules/4.19.0-5-amd64/modules.builtin.bin 32092 +etc/wpa_supplicant/ifupdown.sh 32091 +etc/wpa_supplicant/functions.sh 32090 +bin/ip 32089 +etc/network/if-up.d/ethtool 32088 +etc/network/if-up.d/upstart 32087 +lib/lsb/init-functions 32086 +lib/lsb/init-functions.d/20-left-info-blocks 32085 +lib/lsb/init-functions.d/40-systemd 32084 +bin/systemctl 32083 +lib/x86_64-linux-gnu/liblzma.so.5.2.2 32082 +usr/lib/x86_64-linux-gnu/liblz4.so.1.7.1 32081 +bin/readlink 32080 +lib/lsb/init-functions.d/99-plymouth 32079 +bin/plymouth 32078 +lib/x86_64-linux-gnu/libply.so.4.0.0 32077 +usr/sbin/haveged 32076 +usr/lib/x86_64-linux-gnu/libhavege.so.1.1.0 32075 +lib/live/config/2010-pidgin 32068 +usr/local/bin/lc.py 32067 +usr/bin/python3.5 32066 +lib/x86_64-linux-gnu/libexpat.so.1.6.2 32065 +usr/local/lib/python3.5/dist-packages/easy-install.pth 32026 +usr/local/lib/python3.5/dist-packages/Tailslib-0.1-py3.5.egg 32023 +usr/lib/python3.5/optparse.py 32020 +usr/lib/python3.5/textwrap.py 32017 +usr/lib/python3.5/gettext.py 32004 +usr/lib/python3.5/copy.py 31981 +usr/lib/python3.5/lib-dynload/_hashlib.cpython-35m-x86_64-linux-gnu.so 31970 +usr/share/tails/firstnames.txt 31969 +usr/bin/od 31968 +usr/bin/expr 31967 +usr/bin/bc 31966 +lib/live/config/2030-systemd 31964 +bin/systemd-machine-id-setup 31963 +lib/systemd/libsystemd-shared-241.so 31962 +lib/x86_64-linux-gnu/libcap.so.2.25 31961 +lib/x86_64-linux-gnu/libcryptsetup.so.4.7.0 31960 +usr/lib/x86_64-linux-gnu/libip4tc.so.0.1.0 31959 +lib/x86_64-linux-gnu/libseccomp.so.2.3.1 31958 +lib/x86_64-linux-gnu/libidn.so.11.6.16 31957 +lib/x86_64-linux-gnu/libdevmapper.so.1.02.1 31956 +lib/live/mount/overlay/etc/machine-id 31955 +etc/machine-id 31954 +bin/journalctl 31953 +usr/lib/systemd/catalog/systemd.be.catalog 31952 +usr/lib/systemd/catalog/systemd.be@latin.catalog 31951 +usr/lib/systemd/catalog/systemd.bg.catalog 31950 +usr/lib/systemd/catalog/systemd.catalog 31949 +usr/lib/systemd/catalog/systemd.de.catalog 31948 +usr/lib/systemd/catalog/systemd.fr.catalog 31947 +usr/lib/systemd/catalog/systemd.it.catalog 31946 +usr/lib/systemd/catalog/systemd.pl.catalog 31945 +usr/lib/systemd/catalog/systemd.pt_BR.catalog 31944 +usr/lib/systemd/catalog/systemd.ru.catalog 31943 +usr/lib/systemd/catalog/systemd.zh_CN.catalog 31942 +usr/lib/systemd/catalog/systemd.zh_TW.catalog 31941 +lib/live/config/3000-tps-media-directory 31939 +usr/bin/install 31938 +lib/live/config/7000-debug 31936 +lib/live/config/8000-rootpw 31935 +lib/live/config/9000-hosts-file 31934 +etc/live/config.d/hostname.conf 31933 +lib/live/config/9980-permissions 31932 +lib/live/config/9990-hooks 31930 +lib/live/config/9999-unset-user-account-comment 31929 +lib/systemd/systemd-udevd 31923 +etc/udev/udev.conf 31922 +lib/systemd/network/99-default.link 31921 +etc/udev/rules.d/00-mac-spoof.rules 31920 +lib/udev/rules.d/40-usb_modeswitch.rules 31919 +lib/udev/rules.d/50-firmware.rules 31918 +lib/udev/rules.d/50-udev-default.rules 31917 +lib/udev/rules.d/55-dm.rules 31916 +lib/udev/rules.d/56-hpmud.rules 31915 +lib/udev/rules.d/56-lvm.rules 31914 +lib/udev/rules.d/60-block.rules 31913 +lib/udev/rules.d/60-cdrom_id.rules 31912 +lib/udev/rules.d/60-crda.rules 31911 +lib/udev/rules.d/60-drm.rules 31910 +lib/udev/rules.d/60-evdev.rules 31909 +lib/udev/rules.d/60-fuse.rules 31908 +lib/udev/rules.d/60-gobi-loader.rules 31907 +lib/udev/rules.d/60-input-id.rules 31906 +lib/udev/rules.d/60-libgphoto2-6.rules 31905 +lib/udev/rules.d/60-libsane.rules 31904 +lib/udev/rules.d/60-open-vm-tools.rules 31903 +lib/udev/rules.d/60-persistent-alsa.rules 31902 +lib/udev/rules.d/60-persistent-input.rules 31901 +lib/udev/rules.d/60-persistent-storage-dm.rules 31900 +lib/udev/rules.d/60-persistent-storage-tape.rules 31899 +lib/udev/rules.d/60-persistent-storage.rules 31898 +lib/udev/rules.d/60-persistent-v4l.rules 31897 +lib/udev/rules.d/60-scdaemon.rules 31896 +lib/udev/rules.d/60-sensor.rules 31895 +lib/udev/rules.d/60-serial.rules 31894 +lib/udev/rules.d/60-virtualbox-guest-utils.rules 31893 +lib/udev/rules.d/61-gnome-settings-daemon-rfkill.rules 31892 +lib/udev/rules.d/64-btrfs.rules 31891 +lib/udev/rules.d/64-xorg-xkb.rules 31890 +lib/udev/rules.d/65-libwacom.rules 31889 +lib/udev/rules.d/66-bilibop.rules 31888 +lib/udev/rules.d/69-cd-sensors.rules 31887 +lib/udev/rules.d/69-libmtp.rules 31886 +lib/udev/rules.d/69-lvm-metad.rules 31885 +lib/udev/rules.d/70-debian-uaccess.rules 31884 +lib/udev/rules.d/70-joystick.rules 31883 +lib/udev/rules.d/70-mouse.rules 31882 +lib/udev/rules.d/70-power-switch.rules 31881 +etc/udev/rules.d/70-protect-boot-medium-for-udisks.rules 31880 +lib/udev/rules.d/70-spice-vdagentd.rules 31879 +lib/udev/rules.d/70-touchpad.rules 31878 +lib/udev/rules.d/70-uaccess.rules 31877 +lib/udev/rules.d/71-seat.rules 31876 +lib/udev/rules.d/73-seat-late.rules 31875 +lib/udev/rules.d/73-special-net-names.rules 31874 +lib/udev/rules.d/73-usb-net-by-mac.rules 31873 +lib/udev/rules.d/75-net-description.rules 31872 +lib/udev/rules.d/75-probe_mtd.rules 31871 +lib/udev/rules.d/77-mm-cinterion-port-types.rules 31870 +lib/udev/rules.d/77-mm-dell-port-types.rules 31869 +lib/udev/rules.d/77-mm-ericsson-mbm.rules 31868 +lib/udev/rules.d/77-mm-haier-port-types.rules 31867 +lib/udev/rules.d/77-mm-huawei-net-port-types.rules 31866 +lib/udev/rules.d/77-mm-longcheer-port-types.rules 31865 +lib/udev/rules.d/77-mm-mtk-port-types.rules 31864 +lib/udev/rules.d/77-mm-nokia-port-types.rules 31863 +lib/udev/rules.d/77-mm-pcmcia-device-blacklist.rules 31862 +lib/udev/rules.d/77-mm-platform-serial-whitelist.rules 31861 +lib/udev/rules.d/77-mm-qdl-device-blacklist.rules 31860 +lib/udev/rules.d/77-mm-simtech-port-types.rules 31859 +lib/udev/rules.d/77-mm-telit-port-types.rules 31858 +lib/udev/rules.d/77-mm-usb-device-blacklist.rules 31857 +lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules 31856 +lib/udev/rules.d/77-mm-x22x-port-types.rules 31855 +lib/udev/rules.d/77-mm-zte-port-types.rules 31854 +lib/udev/rules.d/78-sound-card.rules 31853 +lib/udev/rules.d/80-debian-compat.rules 31852 +lib/udev/rules.d/80-drivers.rules 31851 +lib/udev/rules.d/80-ifupdown.rules 31850 +lib/udev/rules.d/80-libinput-device-groups.rules 31849 +lib/udev/rules.d/80-mm-candidate.rules 31848 +lib/udev/rules.d/80-udisks2.rules 31847 +lib/udev/rules.d/84-nm-drivers.rules 31846 +lib/udev/rules.d/85-hdparm.rules 31845 +lib/udev/rules.d/85-hwclock.rules 31844 +lib/udev/rules.d/85-nm-unmanaged.rules 31843 +lib/udev/rules.d/85-regulatory.rules 31842 +lib/udev/rules.d/90-alsa-restore.rules 31841 +lib/udev/rules.d/90-console-setup.rules 31840 +lib/udev/rules.d/90-libinput-model-quirks.rules 31839 +lib/udev/rules.d/90-pulseaudio.rules 31838 +lib/udev/rules.d/92-libccid.rules 31837 +lib/udev/rules.d/95-cd-devices.rules 31836 +lib/udev/rules.d/95-upower-csr.rules 31835 +lib/udev/rules.d/95-upower-hid.rules 31834 +lib/udev/rules.d/95-upower-wup.rules 31833 +etc/udev/rules.d/99-hide-TailsData.rules 31832 +lib/udev/rules.d/99-laptop-mode.rules 31831 +etc/udev/rules.d/99-make-removable-devices-user-writable.rules 31830 +lib/udev/rules.d/99-systemd.rules 31829 +lib/udev/rules.d/99-vmware-scsi-udev.rules 31828 +sbin/plymouthd 31825 +lib/x86_64-linux-gnu/libply-splash-core.so.4.0.0 31824 +usr/bin/dbus-daemon 31822 +usr/sbin/cupsd 31821 +usr/sbin/pcscd 31820 +etc/adjtime 31819 +lib/udev/lmt-udev 31817 +etc/init.d/speech-dispatcher 31815 +usr/sbin/memlockd 31812 +lib/x86_64-linux-gnu/libdbus-1.so.3.14.16 31811 +usr/sbin/ModemManager 31809 +etc/default/cron 31808 +usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22 31807 +lib/x86_64-linux-gnu/libsystemd.so.0.25.0 31806 +usr/sbin/cron 31805 +etc/init.d/rng-tools 31802 +etc/default/rng-tools 31801 +etc/crontab 31795 +usr/lib/x86_64-linux-gnu/libmm-glib.so.0.3.0 31786 +usr/local/lib/initramfs-restore 31778 +lib/systemd/systemd-user-sessions 31776 +usr/lib/accountsservice/accounts-daemon 31774 +lib/x86_64-linux-gnu/libgcc_s.so.1 31772 +lib/x86_64-linux-gnu/libapparmor.so.1.4.0 31770 +usr/share/dbus-1/system.conf 31769 +usr/share/dbus-1/system.d/org.freedesktop.hostname1.conf 31768 +lib/modules/4.19.0-5-amd64/kernel/drivers/cpufreq/acpi-cpufreq.ko 31760 +usr/share/dbus-1/system.d/org.freedesktop.locale1.conf 31759 +usr/share/dbus-1/system.d/org.freedesktop.login1.conf 31758 +usr/share/dbus-1/system.d/org.freedesktop.network1.conf 31757 +usr/share/dbus-1/system.d/org.freedesktop.resolve1.conf 31756 +lib/modules/4.19.0-5-amd64/kernel/drivers/cpufreq/pcc-cpufreq.ko 31754 +lib/systemd/system-preset/90-systemd.preset 31750 +usr/local/bin/tails-get-bootinfo 31746 +usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.5000.3 31744 +usr/share/dbus-1/system.d/org.freedesktop.systemd1.conf 31742 +usr/share/dbus-1/system.d/org.freedesktop.timedate1.conf 31741 +usr/share/dbus-1/system.d/org.freedesktop.timesync1.conf 31740 +etc/dbus-1/system.d/com.hp.hplip.conf 31739 +etc/dbus-1/system.d/com.redhat.NewPrinterNotification.conf 31738 +etc/dbus-1/system.d/com.redhat.PrinterDriversInstaller.conf 31737 +etc/dbus-1/system.d/gdm.conf 31736 +etc/dbus-1/system.d/nm-dispatcher.conf 31735 +etc/dbus-1/system.d/org.freedesktop.Accounts.conf 31734 +etc/dbus-1/system.d/org.freedesktop.ColorManager.conf 31733 +etc/dbus-1/system.d/org.freedesktop.ModemManager1.conf 31732 +etc/dbus-1/system.d/org.freedesktop.NetworkManager.conf 31731 +etc/dbus-1/system.d/org.freedesktop.PolicyKit1.conf 31730 +etc/dbus-1/system.d/org.freedesktop.UDisks2.conf 31729 +etc/dbus-1/system.d/org.freedesktop.UPower.conf 31728 +etc/dbus-1/system.d/org.opensuse.CupsPkHelper.Mechanism.conf 31727 +lib/modules/4.19.0-5-amd64/kernel/drivers/input/evdev.ko 31718 +etc/default/speech-dispatcher 31717 +usr/lib/x86_64-linux-gnu/libgudev-1.0.so.0.2.0 31716 +usr/lib/x86_64-linux-gnu/libqmi-glib.so.5.1.0 31715 +usr/bin/env 31714 +etc/dbus-1/system.d/pulseaudio-system.conf 31713 +etc/dbus-1/system.d/wpa_supplicant.conf 31712 +lib/modules/4.19.0-5-amd64/kernel/drivers/acpi/battery.ko 31707 +lib/modules/4.19.0-5-amd64/kernel/drivers/acpi/ac.ko 31684 +usr/lib/x86_64-linux-gnu/libmbim-glib.so.4.2.0 31682 +etc/default/locale 31681 +usr/lib/x86_64-linux-gnu/libpolkit-gobject-1.so.0.0.0 31680 +usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5000.3 31679 +usr/local/lib/onion-grater 31676 +usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.5000.3 31675 +lib/systemd/system/systemd-backlight@.service 31674 +usr/local/lib/tails-shell-library/tor.sh 31673 +lib/modules/4.19.0-5-amd64/kernel/net/rfkill/rfkill.ko 31655 +lib/modules/4.19.0-5-amd64/kernel/sound/soundcore.ko 31653 +lib/modules/4.19.0-5-amd64/kernel/sound/core/snd.ko 31652 +lib/x86_64-linux-gnu/libglib-2.0.so.0.5000.3 31651 +usr/share/dbus-1/system-services/com.hp.hplip.service 31648 +usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service 31647 +usr/share/dbus-1/system-services/fi.w1.wpa_supplicant1.service 31646 +usr/share/dbus-1/system-services/org.freedesktop.Accounts.service 31645 +usr/share/dbus-1/system-services/org.freedesktop.ColorManager.service 31644 +usr/share/dbus-1/system-services/org.freedesktop.ModemManager1.service 31643 +usr/share/dbus-1/system-services/org.freedesktop.PolicyKit1.service 31642 +usr/share/dbus-1/system-services/org.freedesktop.UDisks2.service 31641 +usr/share/dbus-1/system-services/org.freedesktop.UPower.service 31640 +usr/share/dbus-1/system-services/org.freedesktop.hostname1.service 31639 +usr/share/dbus-1/system-services/org.freedesktop.locale1.service 31638 +usr/share/dbus-1/system-services/org.freedesktop.login1.service 31637 +usr/share/dbus-1/system-services/org.freedesktop.network1.service 31636 +usr/share/dbus-1/system-services/org.freedesktop.nm_dispatcher.service 31635 +usr/share/dbus-1/system-services/org.freedesktop.resolve1.service 31634 +usr/share/dbus-1/system-services/org.freedesktop.systemd1.service 31633 +usr/share/dbus-1/system-services/org.freedesktop.timedate1.service 31632 +usr/share/dbus-1/system-services/org.freedesktop.timesync1.service 31631 +usr/share/dbus-1/system-services/org.opensuse.CupsPkHelper.Mechanism.service 31630 +usr/local/lib/tails-set-wireless-devices-state 31607 +etc/X11/default-display-manager 31581 +etc/memlockd.cfg 31577 +usr/lib/x86_64-linux-gnu/libffi.so.6.0.4 31573 +usr/bin/ldd 31568 +lib/systemd/systemd-logind 31566 +lib/modules/4.19.0-5-amd64/kernel/net/wireless/cfg80211.ko 31561 +lib/modules/4.19.0-5-amd64/kernel/drivers/memstick/core/memstick.ko 31558 +lib/modules/4.19.0-5-amd64/kernel/drivers/mfd/lpc_ich.ko 31553 +lib/modules/4.19.0-5-amd64/kernel/drivers/memstick/host/rtsx_pci_ms.ko 31552 +bin/true 31548 +lib/modules/4.19.0-5-amd64/kernel/drivers/char/nvram.ko 31547 +lib/modules/4.19.0-5-amd64/kernel/sound/core/snd-timer.ko 31546 +lib/modules/4.19.0-5-amd64/kernel/sound/core/snd-pcm.ko 31545 +usr/sbin/laptop_mode 31539 +usr/share/gdm/generate-config 31535 +usr/bin/tail 31533 +usr/bin/unmkinitramfs 31532 +lib/modules/4.19.0-5-amd64/kernel/drivers/scsi/sg.ko 31531 +lib/modules/4.19.0-5-amd64/kernel/drivers/platform/x86/thinkpad_acpi.ko 31530 +usr/share/tor/tor-service-defaults-torrc 31529 +usr/lib/python3.5/argparse.py 31522 +lib/udev/ata_id 31521 +usr/bin/getopt 31520 +etc/laptop-mode/conf.d/ac97-powersave.conf 31519 +etc/laptop-mode/conf.d/auto-hibernate.conf 31518 +etc/laptop-mode/conf.d/battery-level-polling.conf 31517 +etc/laptop-mode/conf.d/bluetooth.conf 31516 +etc/laptop-mode/conf.d/configuration-file-control.conf 31515 +etc/laptop-mode/conf.d/cpufreq.conf 31514 +etc/laptop-mode/conf.d/cpuhotplug.conf 31513 +etc/laptop-mode/conf.d/dpms-standby.conf 31512 +etc/laptop-mode/conf.d/eee-superhe.conf 31511 +lib/modules/4.19.0-5-amd64/kernel/drivers/platform/x86/wmi-bmof.ko 31510 +lib/modules/4.19.0-5-amd64/kernel/drivers/firmware/efi/efivars.ko 31509 +usr/bin/dconf 31508 +usr/lib/x86_64-linux-gnu/libdconf.so.1.0.0 31507 +lib/modules/4.19.0-5-amd64/kernel/sound/core/snd-hwdep.ko 31506 +etc/systemd/logind.conf 31505 +usr/lib/systemd/logind.conf.d/lower-NAutoVTs.conf 31504 +lib/modules/4.19.0-5-amd64/kernel/drivers/input/serio/serio_raw.ko 31503 +etc/laptop-mode/conf.d/ethernet.conf 31502 +etc/laptop-mode/conf.d/exec-commands.conf 31501 +etc/laptop-mode/conf.d/hal-polling.conf 31500 +lib/modules/4.19.0-5-amd64/kernel/sound/hda/snd-hda-core.ko 31499 +etc/laptop-mode/conf.d/intel-hda-powersave.conf 31498 +etc/laptop-mode/conf.d/intel-sata-powermgmt.conf 31497 +etc/laptop-mode/conf.d/intel_pstate.conf 31496 +etc/laptop-mode/conf.d/kbd-backlight.conf 31495 +etc/laptop-mode/conf.d/lcd-brightness.conf 31494 +etc/laptop-mode/conf.d/nmi-watchdog.conf 31493 +etc/laptop-mode/conf.d/pcie-aspm.conf 31492 +etc/laptop-mode/conf.d/radeon-dpm.conf 31491 +etc/laptop-mode/conf.d/runtime-pm.conf 31490 +etc/laptop-mode/conf.d/sched-mc-power-savings.conf 31489 +etc/laptop-mode/conf.d/sched-smt-power-savings.conf 31488 +etc/laptop-mode/conf.d/start-stop-programs.conf 31487 +etc/laptop-mode/conf.d/terminal-blanking.conf 31486 +etc/laptop-mode/conf.d/vgaswitcheroo.conf 31485 +etc/laptop-mode/conf.d/video-out.conf 31484 +etc/laptop-mode/conf.d/wireless-ipw-power.conf 31483 +etc/laptop-mode/conf.d/wireless-iwl-power.conf 31482 +etc/laptop-mode/conf.d/wireless-power.conf 31481 +etc/laptop-mode/laptop-mode.conf 31480 +lib/modules/4.19.0-5-amd64/kernel/drivers/input/joydev.ko 31475 +bin/dd 31468 +etc/gdm3/greeter.dconf-defaults 31458 +bin/echo 31454 +lib/udev/hwclock-set 31452 +bin/sleep 31448 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/events/intel/intel-rapl-perf.ko 31447 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/events/intel/intel-uncore.ko 31446 +lib/udev/hdparm 31445 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/events/intel/intel-cstate.ko 31444 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/crypto/ghash-clmulni-intel.ko 31442 +usr/share/gdm/dconf/50-tails 31440 +usr/share/gdm/dconf/00-upstream-settings 31439 +usr/share/gdm/dconf/locks/00-upstream-settings-locks 31438 +lib/hdparm/hdparm-functions 31436 +lib/modules/4.19.0-5-amd64/kernel/sound/pci/hda/snd-hda-codec.ko 31435 +lib/modules/4.19.0-5-amd64/kernel/drivers/firmware/efi/efi-pstore.ko 31433 +sbin/killall5 31432 +usr/lib/x86_64-linux-gnu/gio/modules/giomodule.cache 31431 +usr/lib/x86_64-linux-gnu/gio/modules/libgvfsdbus.so 31430 +usr/lib/x86_64-linux-gnu/gvfs/libgvfscommon.so 31429 +etc/shells 31428 +etc/hdparm.conf 31427 +bin/udevadm 31426 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/crypto/crc32-pclmul.ko 31362 +lib/modules/4.19.0-5-amd64/kernel/sound/pci/hda/snd-hda-intel.ko 31361 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/crypto/crct10dif-pclmul.ko 31360 +lib/live/mount/overlay/var/log/wtmp 31301 +var/log/wtmp 31300 +lib/modules/4.19.0-5-amd64/kernel/virt/lib/irqbypass.ko 31299 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/kvm/kvm.ko 31298 +bin/chgrp 31252 +lib/modules/4.19.0-5-amd64/kernel/sound/pci/hda/snd-hda-codec-generic.ko 31192 +sbin/ethtool 31133 +usr/bin/flock 31120 +bin/kill 31066 +lib/modules/4.19.0-5-amd64/kernel/drivers/watchdog/iTCO_vendor_support.ko 31061 +lib/modules/4.19.0-5-amd64/kernel/drivers/watchdog/iTCO_wdt.ko 31060 +lib/udev/ifupdown-hotplug 31059 +lib/udev/libinput-device-group 31057 +usr/lib/x86_64-linux-gnu/libwacom.so.2.5.0 31056 +lib/modules/4.19.0-5-amd64/kernel/sound/pci/hda/snd-hda-codec-conexant.ko 31055 +lib/live/mount/overlay/etc/console-setup/cached_Uni1-Fixed16.psf.gz 31047 +etc/console-setup/cached_Uni1-Fixed16.psf.gz 31046 +lib/modules/4.19.0-5-amd64/kernel/arch/x86/kvm/kvm-intel.ko 31045 +usr/sbin/gdm3 31042 +usr/lib/python3.5/ipaddress.py 31039 +usr/lib/x86_64-linux-gnu/libX11.so.6.3.0 31035 +usr/lib/x86_64-linux-gnu/libXau.so.6.0.0 31034 +lib/modules/4.19.0-5-amd64/kernel/drivers/hwmon/coretemp.ko 31033 +lib/udev/libinput-model-quirks 31032 +usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0 31031 +usr/lib/x86_64-linux-gnu/libXdmcp.so.6.0.0 31030 +lib/x86_64-linux-gnu/libwrap.so.0.7.6 31029 +lib/modules/4.19.0-5-amd64/kernel/drivers/thermal/intel_powerclamp.ko 31028 +lib/x86_64-linux-gnu/libprocps.so.6.0.0 31027 +lib/x86_64-linux-gnu/libbsd.so.0.8.3 31024 +lib/modules/4.19.0-5-amd64/kernel/drivers/thermal/x86_pkg_temp_thermal.ko 31021 +lib/modules/4.19.0-5-amd64/kernel/sound/pci/hda/snd-hda-codec-hdmi.ko 31020 +bin/loginctl 31016 +etc/gdm3/daemon.conf 31015 +lib/modules/4.19.0-5-amd64/kernel/drivers/powercap/intel_rapl.ko 31014 +usr/share/gdm/gdm.schemas 31013 +usr/lib/python3/dist-packages/psutil/__init__.py 31006 +usr/sbin/alsactl 31003 +usr/lib/x86_64-linux-gnu/libasound.so.2.0.0 31001 +sbin/crda 30997 +lib/crda/libreg.so 30989 +lib/x86_64-linux-gnu/libnl-genl-3.so.200.22.0 30987 +usr/share/alsa/alsa.conf 30980 +lib/x86_64-linux-gnu/libnl-3.so.200.22.0 30977 +usr/share/alsa/alsa.conf.d/pulse.conf 30974 +etc/asound.conf 30973 +usr/lib/x86_64-linux-gnu/alsa-lib/libasound_module_conf_pulse.so 30972 +usr/lib/x86_64-linux-gnu/libpulse.so.0.20.1 30971 +lib/crda/regulatory.bin 30970 +lib/crda/pubkeys/benh@debian.org.key.pub.pem 30969 +usr/lib/python3.5/__future__.py 30968 +usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-10.0.so 30967 +usr/lib/python3.5/contextlib.py 30965 +usr/lib/x86_64-linux-gnu/libX11-xcb.so.1.0.0 30962 +usr/lib/x86_64-linux-gnu/libICE.so.6.3.0 30961 +usr/lib/x86_64-linux-gnu/libSM.so.6.0.1 30960 +bin/mkdir 30959 +usr/lib/x86_64-linux-gnu/libXtst.so.6.1.0 30958 +usr/lib/x86_64-linux-gnu/libsndfile.so.1.0.27 30956 +usr/lib/x86_64-linux-gnu/libasyncns.so.0.3.1 30949 +usr/bin/logger 30946 +usr/lib/x86_64-linux-gnu/libXext.so.6.4.0 30943 +usr/lib/x86_64-linux-gnu/libXi.so.6.1.0 30932 +usr/lib/x86_64-linux-gnu/libFLAC.so.8.3.0 30930 +usr/lib/python3/dist-packages/psutil/_common.py 30929 +usr/bin/basename 30928 +usr/lib/x86_64-linux-gnu/libogg.so.0.8.2 30925 +usr/lib/x86_64-linux-gnu/libvorbis.so.0.4.8 30924 +usr/lib/x86_64-linux-gnu/libvorbisenc.so.2.0.11 30923 +usr/lib/x86_64-linux-gnu/libcairo.so.2.11400.8 30922 +bin/df 30921 +usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3600.5 30920 +usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0.4000.5 30919 +usr/lib/x86_64-linux-gnu/libXcomposite.so.1.0.0 30918 +usr/lib/x86_64-linux-gnu/libXdamage.so.1.1.0 30917 +usr/share/laptop-mode-tools/modules/sched-mc-power-savings 30916 +usr/lib/x86_64-linux-gnu/libXfixes.so.3.1.0 30915 +usr/lib/x86_64-linux-gnu/libcairo-gobject.so.2.11400.8 30914 +usr/lib/x86_64-linux-gnu/libatk-1.0.so.0.22209.1 30913 +usr/lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0.0.0 30912 +usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0 30911 +usr/share/laptop-mode-tools/modules/sched-smt-power-savings 30910 +usr/lib/x86_64-linux-gnu/libwayland-cursor.so.0.0.0 30909 +usr/lib/x86_64-linux-gnu/libwayland-egl.so.1.0.0 30908 +usr/lib/x86_64-linux-gnu/libwayland-client.so.0.3.0 30907 +usr/lib/x86_64-linux-gnu/libepoxy.so.0.0.0 30906 +usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0.4000.5 30905 +usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.4000.5 30904 +usr/lib/x86_64-linux-gnu/libfontconfig.so.1.8.0 30903 +usr/lib/x86_64-linux-gnu/libfreetype.so.6.12.3 30902 +usr/lib/x86_64-linux-gnu/libXinerama.so.1.0.0 30901 +usr/lib/x86_64-linux-gnu/libXrandr.so.2.2.0 30900 +usr/lib/x86_64-linux-gnu/libXcursor.so.1.0.2 30899 +usr/lib/x86_64-linux-gnu/libpixman-1.so.0.34.0 30898 +usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0 30897 +usr/lib/x86_64-linux-gnu/libxcb-shm.so.0.0.0 30896 +usr/lib/x86_64-linux-gnu/libxcb-render.so.0.0.0 30895 +usr/lib/x86_64-linux-gnu/libXrender.so.1.3.0 30894 +usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0.5000.3 30893 +usr/lib/x86_64-linux-gnu/libatspi.so.0.0.1 30892 +usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.10400.2 30891 +usr/share/laptop-mode-tools/modules/start-stop-programs 30890 +usr/lib/x86_64-linux-gnu/libthai.so.0.3.0 30888 +usr/lib/x86_64-linux-gnu/libgraphite2.so.3.0.1 30887 +usr/lib/x86_64-linux-gnu/libdatrie.so.1.3.3 30886 +usr/share/laptop-mode-tools/modules/syslog-conf 30885 +usr/lib/gnome-session/gnome-session-check-accelerated 30883 +usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2200.11 30882 +usr/lib/x86_64-linux-gnu/libgdk-3.so.0.2200.11 30881 +usr/share/laptop-mode-tools/modules/terminal-blanking 30880 +etc/bilibop/bilibop.conf 30879 +usr/share/laptop-mode-tools/modules/vgaswitcheroo 30875 +lib/bilibop/test 30872 +usr/share/laptop-mode-tools/modules/video-out 30871 +lib/bilibop/common.sh 30870 +usr/share/laptop-mode-tools/modules/wireless-ipw-power 30869 +usr/share/locale/en/LC_MESSAGES/gtk30.mo 30868 +usr/share/laptop-mode-tools/modules/wireless-iwl-power 30867 +usr/share/laptop-mode-tools/modules/wireless-power 30866 +sbin/iw 30865 +usr/share/locale/en/LC_MESSAGES/gtk30-properties.mo 30860 +var/tmp/unmkinitramfs_LnkVyR 30851 +usr/share/laptop-mode-tools/modules/pcie-aspm 30850 +usr/share/laptop-mode-tools/modules/radeon-dpm 30849 +usr/share/laptop-mode-tools/modules/runtime-pm 30848 +usr/share/laptop-mode-tools/modules/ac97-powersave 30847 +usr/share/laptop-mode-tools/modules/battery-level-polling 30846 +usr/share/laptop-mode-tools/modules/bluetooth 30845 +usr/share/laptop-mode-tools/modules/configuration-file-control 30844 +usr/share/laptop-mode-tools/modules/cpufreq 30843 +usr/share/laptop-mode-tools/modules/cpuhotplug 30842 +usr/share/laptop-mode-tools/modules/dpms-standby 30841 +usr/share/laptop-mode-tools/modules/eee-superhe 30840 +usr/share/laptop-mode-tools/modules/ethernet 30839 +usr/share/laptop-mode-tools/modules/exec-commands 30838 +usr/share/laptop-mode-tools/modules/hal-polling 30837 +usr/share/laptop-mode-tools/modules/hdparm 30836 +usr/share/laptop-mode-tools/modules/intel-hda-powersave 30835 +usr/share/laptop-mode-tools/modules/intel-sata-powermgmt 30834 +usr/share/laptop-mode-tools/modules/intel_pstate 30833 +usr/share/laptop-mode-tools/modules/kbd-backlight 30832 +usr/share/laptop-mode-tools/modules/laptop-mode 30831 +sbin/blockdev 30830 +usr/share/laptop-mode-tools/modules/lcd-brightness 30829 +usr/share/laptop-mode-tools/modules/nmi-watchdog 30828 +usr/lib/x86_64-linux-gnu/libGL.so.1.7.0 30823 +usr/lib/x86_64-linux-gnu/libGLX.so.0.0.0 30822 +usr/lib/x86_64-linux-gnu/libGLdispatch.so.0.0.0 30821 +usr/lib/x86_64-linux-gnu/libGLX_mesa.so.0.0.0 30820 +usr/lib/x86_64-linux-gnu/libxcb-dri3.so.0.0.0 30819 +usr/lib/x86_64-linux-gnu/libxcb-xfixes.so.0.0.0 30818 +usr/lib/x86_64-linux-gnu/libxcb-present.so.0.0.0 30817 +usr/lib/x86_64-linux-gnu/libxcb-sync.so.1.0.0 30816 +usr/lib/x86_64-linux-gnu/libxshmfence.so.1.0.0 30815 +usr/lib/x86_64-linux-gnu/libglapi.so.0.0.0 30814 +usr/lib/x86_64-linux-gnu/libxcb-glx.so.0.0.0 30813 +usr/lib/x86_64-linux-gnu/libxcb-dri2.so.0.0.0 30812 +usr/lib/x86_64-linux-gnu/libXxf86vm.so.1.0.0 30811 +usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0 30810 +etc/drirc 30809 +usr/lib/x86_64-linux-gnu/dri/i965_dri.so 30808 +usr/lib/x86_64-linux-gnu/libdrm_intel.so.1.0.0 30807 +usr/lib/x86_64-linux-gnu/libdrm_nouveau.so.2.0.0 30806 +usr/lib/x86_64-linux-gnu/libdrm_radeon.so.1.0.1 30805 +usr/lib/x86_64-linux-gnu/libpciaccess.so.0.11.1 30804 +usr/lib/systemd/user/at-spi-dbus-bus.service 30802 +usr/lib/at-spi2-core/at-spi-bus-launcher 30800 +usr/share/glib-2.0/schemas/gschemas.compiled 30799 +usr/lib/x86_64-linux-gnu/gio/modules/libdconfsettings.so 30798 +usr/share/dconf/profile/gdm 30797 +usr/share/defaults/at-spi2/accessibility.conf 30795 +usr/share/dbus-1/accessibility-services/org.a11y.atspi.Registry.service 30794 +usr/lib/gnome-session/gnome-session-check-accelerated-gl-helper 30791 +usr/lib/at-spi2-core/at-spi2-registryd 30790 +usr/share/gnome-session/hardware-compatibility 30789 +usr/share/gnome-session/sessions/gdm-tails.session 30785 +usr/share/gdm/greeter/applications/gdm-shell-tails.desktop 30784 +usr/share/applications/tails-greeter.desktop 30783 +etc/xdg/autostart/gnome-settings-daemon.desktop 30782 +usr/share/gdm/greeter/autostart/orca-autostart.desktop 30781 +etc/xdg/autostart/spice-vdagent.desktop 30780 +usr/bin/gnome-shell 30779 +usr/lib/gnome-shell/libgnome-shell.so 30776 +usr/lib/gnome-shell/libgnome-shell-js.so 30775 +usr/lib/libgjs.so.0.0.0 30774 +usr/lib/x86_64-linux-gnu/mutter/libmutter-cogl-pango.so 30773 +usr/lib/x86_64-linux-gnu/libgirepository-1.0.so.1.0.0 30772 +usr/lib/x86_64-linux-gnu/libtelepathy-glib.so.0.84.1 30771 +usr/lib/x86_64-linux-gnu/libmutter.so.0.0.0 30770 +usr/lib/x86_64-linux-gnu/mutter/libmutter-clutter-1.0.so 30769 +usr/lib/gnome-shell/libgnome-shell-menu.so 30768 +usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.1004.0 30767 +usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.1004.0 30766 +usr/lib/x86_64-linux-gnu/libstartup-notification-1.so.0.0.0 30765 +usr/lib/x86_64-linux-gnu/libcanberra-gtk3.so.0.1.9 30764 +usr/lib/x86_64-linux-gnu/libcanberra.so.0.2.5 30763 +usr/lib/x86_64-linux-gnu/libpolkit-agent-1.so.0.0.0 30762 +usr/lib/x86_64-linux-gnu/libgcr-base-3.so.1.0.0 30761 +usr/lib/x86_64-linux-gnu/libnm-glib.so.4.9.0 30760 +usr/lib/x86_64-linux-gnu/libnm-util.so.2.7.0 30759 +usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.3.3 30758 +usr/lib/x86_64-linux-gnu/libsecret-1.so.0.0.0 30757 +usr/lib/x86_64-linux-gnu/libcroco-0.6.so.3.0.1 30756 +usr/lib/x86_64-linux-gnu/mutter/libmutter-cogl.so 30755 +usr/lib/x86_64-linux-gnu/libpulse-mainloop-glib.so.0.0.5 30754 +usr/lib/x86_64-linux-gnu/libmozjs-24.so.0.0.0 30753 +usr/lib/x86_64-linux-gnu/libupower-glib.so.3.0.1 30752 +usr/lib/x86_64-linux-gnu/libgnome-desktop-3.so.12.2.0 30751 +usr/lib/x86_64-linux-gnu/libxkbfile.so.1.0.2 30750 +usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0.0.0 30749 +usr/lib/x86_64-linux-gnu/libxcb-randr.so.0.1.0 30748 +usr/lib/x86_64-linux-gnu/libxcb-res.so.0.0.0 30747 +usr/lib/x86_64-linux-gnu/libinput.so.10.11.5 30746 +usr/lib/x86_64-linux-gnu/libgbm.so.1.0.0 30745 +usr/lib/x86_64-linux-gnu/libjson-glib-1.0.so.0.200.6 30744 +usr/lib/x86_64-linux-gnu/libwayland-server.so.0.1.0 30743 +usr/lib/x86_64-linux-gnu/mutter/libmutter-cogl-path.so 30742 +usr/lib/x86_64-linux-gnu/libxcb-util.so.0.0.0 30741 +usr/lib/x86_64-linux-gnu/libvorbisfile.so.3.3.7 30740 +usr/lib/x86_64-linux-gnu/libtdb.so.1.3.11 30739 +usr/lib/x86_64-linux-gnu/libltdl.so.7.3.1 30738 +usr/lib/x86_64-linux-gnu/libgck-1.so.0.0.0 30737 +usr/lib/x86_64-linux-gnu/libp11-kit.so.0.2.0 30736 +usr/lib/x86_64-linux-gnu/libgnutls.so.30.13.1 30735 +usr/lib/x86_64-linux-gnu/libxml2.so.2.9.4 30734 +usr/lib/x86_64-linux-gnu/libEGL.so.1.1.0 30733 +usr/lib/x86_64-linux-gnu/libplds4.so 30732 +usr/lib/x86_64-linux-gnu/libplc4.so 30731 +usr/lib/x86_64-linux-gnu/libnspr4.so 30730 +usr/lib/x86_64-linux-gnu/libxcb-xkb.so.1.0.0 30729 +usr/lib/x86_64-linux-gnu/libmtdev.so.1.0.0 30728 +usr/lib/x86_64-linux-gnu/libevdev.so.2.1.18 30727 +usr/lib/x86_64-linux-gnu/libtasn1.so.6.5.3 30726 +usr/lib/x86_64-linux-gnu/libnettle.so.6.3 30725 +usr/lib/x86_64-linux-gnu/libhogweed.so.4.3 30724 +usr/lib/x86_64-linux-gnu/libgmp.so.10.3.2 30723 +usr/lib/x86_64-linux-gnu/libicui18n.so.57.1 30722 +usr/lib/x86_64-linux-gnu/libicuuc.so.57.1 30721 +usr/lib/x86_64-linux-gnu/libicudata.so.57.1 30720 +usr/bin/xz 30719 +var/lib/gdm3/#207932 30718 +lib/systemd/system/upower.service 30717 +usr/lib/upower/upowerd 30715 +lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0 30714 +usr/lib/x86_64-linux-gnu/libimobiledevice.so.6.0.0 30713 +usr/lib/x86_64-linux-gnu/libplist.so.3.0.0 30712 +usr/lib/x86_64-linux-gnu/libusbmuxd.so.4.0.0 30711 +etc/UPower/UPower.conf 30710 +usr/share/libwacom/serial-wacf004.tablet 30687 +usr/share/libwacom/one-by-wacom-s-p.tablet 30686 +usr/share/libwacom/one-by-wacom-m-p.tablet 30685 +usr/share/libwacom/n-trig-pen.tablet 30684 +usr/share/libwacom/isdv4-ef.tablet 30683 +usr/share/libwacom/isdv4-ed.tablet 30682 +usr/share/libwacom/isdv4-ec.tablet 30681 +usr/share/libwacom/isdv4-e6.tablet 30680 +usr/share/libwacom/isdv4-e5.tablet 30679 +usr/share/libwacom/isdv4-e3.tablet 30678 +usr/share/libwacom/isdv4-93.tablet 30677 +usr/share/libwacom/isdv4-90.tablet 30676 +usr/share/libwacom/isdv4-504a.tablet 30675 +usr/share/libwacom/isdv4-5002.tablet 30674 +usr/share/libwacom/isdv4-5000.tablet 30673 +usr/share/libwacom/isdv4-4800.tablet 30672 +usr/share/libwacom/isdv4-4004.tablet 30671 +usr/share/libwacom/isdv4-12c.tablet 30670 +usr/share/libwacom/isdv4-116.tablet 30669 +usr/share/libwacom/isdv4-114.tablet 30668 +usr/share/libwacom/isdv4-10f.tablet 30667 +usr/share/libwacom/isdv4-10d.tablet 30666 +usr/share/libwacom/isdv4-101.tablet 30665 +usr/share/libwacom/isdv4-100.tablet 30664 +usr/share/libwacom/intuos-s-pt.tablet 30663 +usr/share/libwacom/intuos-s-p.tablet 30662 +usr/share/libwacom/intuos-s-pt2.tablet 30661 +usr/share/libwacom/intuos-s-p2.tablet 30660 +usr/share/libwacom/intuos-pro-s.tablet 30659 +usr/share/libwacom/intuos-pro-m.tablet 30658 +usr/share/libwacom/intuos-pro-l.tablet 30657 +usr/share/libwacom/intuos-m-pt.tablet 30656 +usr/share/libwacom/intuos-m-p.tablet 30655 +usr/share/libwacom/intuos-m-pt2.tablet 30654 +usr/share/libwacom/intuos-m-p2.tablet 30653 +usr/share/libwacom/intuos-9x12.tablet 30652 +usr/share/libwacom/intuos-6x8.tablet 30651 +usr/share/libwacom/intuos5-touch-s.tablet 30650 +usr/share/libwacom/intuos5-touch-m.tablet 30649 +usr/share/libwacom/intuos5-touch-l.tablet 30648 +usr/share/libwacom/intuos5-s.tablet 30647 +usr/share/libwacom/intuos5-m.tablet 30646 +usr/share/libwacom/intuos-4x5.tablet 30645 +usr/share/libwacom/intuos4-8x13.tablet 30644 +usr/share/libwacom/intuos4-6x9-wl.tablet 30643 +usr/share/libwacom/intuos4-6x9.tablet 30642 +usr/share/libwacom/intuos4-4x6.tablet 30641 +usr/share/libwacom/intuos4-12x19.tablet 30640 +usr/share/libwacom/intuos3-9x12.tablet 30639 +usr/share/libwacom/intuos3-6x8.tablet 30638 +usr/share/libwacom/intuos3-6x11.tablet 30637 +usr/share/libwacom/intuos3-4x6.tablet 30636 +usr/share/libwacom/intuos3-4x5.tablet 30635 +usr/share/libwacom/intuos3-12x19.tablet 30634 +usr/share/libwacom/intuos3-12x12.tablet 30633 +usr/share/libwacom/intuos2-9x12.tablet 30632 +usr/share/libwacom/intuos2-6x8.tablet 30631 +usr/share/libwacom/intuos2-4x5.tablet 30630 +usr/share/libwacom/intuos2-12x18.tablet 30629 +usr/share/libwacom/intuos2-12x12.tablet 30628 +usr/share/libwacom/intuos-12x18.tablet 30627 +usr/share/libwacom/intuos-12x12.tablet 30626 +usr/share/libwacom/huion-h610-pro.tablet 30625 +usr/share/libwacom/graphire-wireless-8x6.tablet 30624 +usr/share/libwacom/graphire4-4x5.tablet 30623 +usr/share/libwacom/graphire3-6x8.tablet 30622 +usr/share/libwacom/graphire3-4x5.tablet 30621 +usr/share/libwacom/generic.tablet 30620 +usr/share/libwacom/ek-remote.tablet 30619 +usr/share/libwacom/dtu-2231.tablet 30618 +usr/share/libwacom/dtu-1931.tablet 30617 +usr/share/libwacom/dtu-1631.tablet 30616 +usr/share/libwacom/dtu-1141.tablet 30615 +usr/share/libwacom/dtu-1031x.tablet 30614 +usr/share/libwacom/dtu-1031.tablet 30613 +usr/share/libwacom/dtk-2241.tablet 30612 +usr/share/libwacom/dtk-1651.tablet 30611 +usr/share/libwacom/dti-520.tablet 30610 +usr/share/libwacom/dth-2242.tablet 30609 +usr/share/libwacom/dtf-720.tablet 30608 +usr/share/libwacom/cintiq-companion.tablet 30607 +usr/share/libwacom/cintiq-companion-hybrid.tablet 30606 +usr/share/libwacom/cintiq-companion-2.tablet 30605 +usr/share/libwacom/cintiq-27hdt.tablet 30604 +usr/share/libwacom/cintiq-27hd.tablet 30603 +usr/share/libwacom/cintiq-24hd-touch.tablet 30602 +usr/share/libwacom/cintiq-24hd.tablet 30601 +usr/share/libwacom/cintiq-22hdt.tablet 30600 +usr/share/libwacom/cintiq-22hd.tablet 30599 +usr/share/libwacom/cintiq-21ux.tablet 30598 +usr/share/libwacom/cintiq-21ux2.tablet 30597 +usr/share/libwacom/cintiq-20wsx.tablet 30596 +usr/share/libwacom/cintiq-13hdt.tablet 30595 +usr/share/libwacom/cintiq-13hd.tablet 30594 +usr/share/libwacom/cintiq-12wx.tablet 30593 +usr/share/libwacom/bamboo-one.tablet 30592 +usr/share/libwacom/bamboo-4fg-s-t.tablet 30591 +usr/share/libwacom/bamboo-4fg-s-pt.tablet 30590 +usr/share/libwacom/bamboo-4fg-se-s-pt.tablet 30589 +usr/share/libwacom/bamboo-4fg-se-m-pt.tablet 30588 +usr/share/libwacom/bamboo-4fg-fun-s.tablet 30587 +usr/share/libwacom/bamboo-4fg-fun-m.tablet 30586 +usr/share/libwacom/bamboo-2fg-s-t.tablet 30585 +usr/share/libwacom/bamboo-2fg-s-pt.tablet 30584 +usr/share/libwacom/bamboo-2fg-s-p.tablet 30583 +usr/share/libwacom/bamboo-2fg-m-p.tablet 30582 +usr/share/libwacom/bamboo-2fg-fun-s-pt.tablet 30581 +usr/share/libwacom/bamboo-2fg-fun-m-pt.tablet 30580 +usr/share/libwacom/bamboo-16fg-s-t.tablet 30579 +usr/share/libwacom/bamboo-16fg-s-pt.tablet 30578 +usr/share/libwacom/bamboo-16fg-s-p.tablet 30577 +usr/share/libwacom/bamboo-16fg-m-pt.tablet 30576 +usr/share/libwacom/bamboo-0fg-s-p.tablet 30575 +usr/share/libwacom/libwacom.stylus 30574 +usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders.cache 30573 +usr/lib/x86_64-linux-gnu/libcanberra-0.30/libcanberra-pulse.so 30572 +etc/pulse/client.conf 30571 +usr/bin/pulseaudio 30569 +usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecore-10.0.so 30568 +usr/lib/x86_64-linux-gnu/liborc-0.4.so.0.25.0 30567 +usr/lib/x86_64-linux-gnu/libspeexdsp.so.1.5.0 30566 +usr/lib/x86_64-linux-gnu/libsoxr.so.0.1.1 30565 +usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0 30564 +etc/pulse/daemon.conf 30563 +etc/pulse/default.pa 30562 +usr/lib/pulse-10.0/modules/module-device-restore.so 30561 +usr/lib/pulse-10.0/modules/libprotocol-native.so 30560 +usr/lib/pulse-10.0/modules/module-stream-restore.so 30559 +usr/lib/pulse-10.0/modules/module-card-restore.so 30558 +usr/lib/pulse-10.0/modules/module-augment-properties.so 30557 +usr/lib/pulse-10.0/modules/module-switch-on-port-available.so 30556 +usr/lib/pulse-10.0/modules/module-udev-detect.so 30555 +usr/lib/pulse-10.0/modules/module-alsa-card.so 30546 +usr/lib/pulse-10.0/modules/libalsa-util.so 30545 +usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf 30544 +usr/share/alsa/cards/aliases.conf 30543 +usr/share/alsa/pcm/default.conf 30542 +usr/share/alsa/pcm/dmix.conf 30541 +usr/share/alsa/pcm/dsnoop.conf 30540 +usr/share/alsa/cards/HDA-Intel.conf 30539 +usr/share/alsa/pcm/front.conf 30538 +usr/share/alsa/pcm/surround21.conf 30537 +usr/share/alsa/pcm/surround40.conf 30536 +usr/share/alsa/pcm/surround41.conf 30535 +usr/share/alsa/pcm/surround50.conf 30534 +usr/share/alsa/pcm/surround51.conf 30533 +usr/share/alsa/pcm/surround71.conf 30532 +usr/share/alsa/pcm/iec958.conf 30531 +usr/share/alsa/pcm/hdmi.conf 30530 +usr/share/alsa/pcm/modem.conf 30529 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-front-mic.conf 30528 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-mic.conf.common 30527 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-rear-mic.conf 30526 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-internal-mic.conf 30525 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-dock-mic.conf 30524 +usr/share/pulseaudio/alsa-mixer/paths/analog-input.conf 30523 +usr/share/pulseaudio/alsa-mixer/paths/analog-input.conf.common 30522 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-mic.conf 30521 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-linein.conf 30520 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-aux.conf 30519 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-video.conf 30518 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-tvtuner.conf 30517 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-fm.conf 30516 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-mic-line.conf 30515 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-headphone-mic.conf 30514 +usr/share/pulseaudio/alsa-mixer/paths/analog-input-headset-mic.conf 30513 +usr/share/pulseaudio/alsa-mixer/paths/analog-output.conf 30512 +usr/share/pulseaudio/alsa-mixer/paths/analog-output.conf.common 30511 +usr/share/pulseaudio/alsa-mixer/paths/analog-output-lineout.conf 30510 +usr/share/pulseaudio/alsa-mixer/paths/analog-output-speaker.conf 30509 +usr/share/pulseaudio/alsa-mixer/paths/analog-output-headphones.conf 30508 +usr/share/pulseaudio/alsa-mixer/paths/analog-output-headphones-2.conf 30507 +usr/share/pulseaudio/alsa-mixer/paths/hdmi-output-0.conf 30506 +usr/lib/pulse-10.0/modules/module-native-protocol-unix.so 30505 +usr/lib/pulse-10.0/modules/module-default-device-restore.so 30504 +usr/lib/pulse-10.0/modules/module-rescue-streams.so 30503 +usr/lib/pulse-10.0/modules/module-always-sink.so 30502 +usr/lib/pulse-10.0/modules/module-intended-roles.so 30501 +usr/lib/pulse-10.0/modules/module-suspend-on-idle.so 30500 +usr/lib/pulse-10.0/modules/module-console-kit.so 30499 +usr/lib/pulse-10.0/modules/module-systemd-login.so 30498 +usr/lib/pulse-10.0/modules/module-position-event-sounds.so 30497 +usr/lib/pulse-10.0/modules/module-role-cork.so 30496 +usr/lib/pulse-10.0/modules/module-filter-heuristics.so 30495 +usr/lib/pulse-10.0/modules/module-filter-apply.so 30494 +usr/share/icons/Adwaita/cursors/left_ptr 30493 +usr/lib/x86_64-linux-gnu/girepository-1.0/GLib-2.0.typelib 30492 +usr/lib/x86_64-linux-gnu/mutter/Clutter-1.0.typelib 30491 +usr/lib/x86_64-linux-gnu/girepository-1.0/cairo-1.0.typelib 30490 +usr/lib/x86_64-linux-gnu/girepository-1.0/Json-1.0.typelib 30489 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gio-2.0.typelib 30488 +usr/lib/x86_64-linux-gnu/girepository-1.0/GObject-2.0.typelib 30487 +usr/lib/x86_64-linux-gnu/girepository-1.0/GL-1.0.typelib 30486 +usr/lib/x86_64-linux-gnu/mutter/CoglPango-1.0.typelib 30485 +usr/lib/x86_64-linux-gnu/girepository-1.0/PangoCairo-1.0.typelib 30484 +usr/lib/x86_64-linux-gnu/girepository-1.0/PangoFT2-1.0.typelib 30483 +usr/lib/x86_64-linux-gnu/girepository-1.0/freetype2-2.0.typelib 30482 +usr/lib/x86_64-linux-gnu/girepository-1.0/fontconfig-2.0.typelib 30481 +usr/lib/x86_64-linux-gnu/girepository-1.0/Pango-1.0.typelib 30480 +usr/lib/x86_64-linux-gnu/mutter/Cogl-1.0.typelib 30479 +usr/lib/x86_64-linux-gnu/girepository-1.0/Atk-1.0.typelib 30478 +usr/lib/gjs/girepository-1.0/GjsPrivate-1.0.typelib 30477 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gtk-3.0.typelib 30476 +usr/lib/x86_64-linux-gnu/girepository-1.0/xlib-2.0.typelib 30475 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gdk-3.0.typelib 30474 +usr/lib/x86_64-linux-gnu/girepository-1.0/GdkPixbuf-2.0.typelib 30473 +usr/lib/x86_64-linux-gnu/girepository-1.0/GModule-2.0.typelib 30472 +usr/lib/gnome-shell/Shell-0.1.typelib 30471 +usr/lib/girepository-1.0/TelepathyGLib-0.12.typelib 30470 +usr/lib/gnome-shell/St-1.0.typelib 30469 +usr/lib/x86_64-linux-gnu/girepository-1.0/Soup-2.4.typelib 30468 +usr/lib/gnome-shell/ShellMenu-0.1.typelib 30467 +usr/lib/x86_64-linux-gnu/girepository-1.0/NetworkManager-1.0.typelib 30466 +usr/lib/x86_64-linux-gnu/girepository-1.0/DBusGLib-1.0.typelib 30465 +usr/lib/x86_64-linux-gnu/girepository-1.0/NMClient-1.0.typelib 30464 +usr/lib/x86_64-linux-gnu/mutter/Meta-3.0.typelib 30463 +usr/lib/x86_64-linux-gnu/girepository-1.0/xfixes-4.0.typelib 30462 +usr/lib/x86_64-linux-gnu/girepository-1.0/GDesktopEnums-3.0.typelib 30461 +usr/lib/x86_64-linux-gnu/mutter/ClutterX11-1.0.typelib 30460 +usr/lib/x86_64-linux-gnu/girepository-1.0/GnomeDesktop-3.0.typelib 30459 +usr/lib/girepository-1.0/AccountsService-1.0.typelib 30458 +usr/lib/x86_64-linux-gnu/girepository-1.0/Polkit-1.0.typelib 30457 +usr/lib/gnome-shell/ShellJS-0.1.typelib 30456 +usr/lib/girepository-1.0/Caribou-1.0.typelib 30455 +usr/lib/x86_64-linux-gnu/girepository-1.0/IBus-1.0.typelib 30454 +usr/lib/x86_64-linux-gnu/libcaribou.so.0.0.0 30453 +usr/lib/x86_64-linux-gnu/libxklavier.so.16.4.0 30452 +usr/lib/x86_64-linux-gnu/libgee-0.8.so.2.5.1 30451 +usr/lib/x86_64-linux-gnu/girepository-1.0/GWeather-3.0.typelib 30450 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gdm-1.0.typelib 30449 +usr/lib/x86_64-linux-gnu/girepository-1.0/Atspi-2.0.typelib 30448 +usr/share/gnome-shell/modes/classic.json 30447 +usr/share/gnome-shell/modes/gdm-tails.json 30446 +etc/xdg/gnome-mimeapps.list 30445 +usr/local/share/mime/mime.cache 30444 +usr/share/mime/mime.cache 30443 +usr/share/gdm/greeter/applications/mimeapps.list 30442 +usr/share/applications/gnome-mimeapps.list 30441 +usr/share/applications/mimeinfo.cache 30440 +usr/share/gdm/greeter/applications/mime-dummy-handler.desktop 30439 +usr/share/applications/gnome-bluetooth-panel.desktop 30438 +usr/lib/libreoffice/share/xdg/xsltfilter.desktop 30437 +usr/share/applications/python3.5.desktop 30436 +usr/lib/libreoffice/share/xdg/math.desktop 30435 +usr/share/applications/synaptic.desktop 30434 +usr/share/applications/tails-persistence-delete.desktop 30433 +usr/share/applications/poedit.desktop 30432 +usr/share/applications/evince-previewer.desktop 30431 +usr/share/applications/org.gnome.Totem.desktop 30430 +usr/share/applications/unlock-veracrypt-volumes.desktop 30429 +usr/share/applications/gnome-sound-panel.desktop 30428 +usr/share/applications/simple-scan.desktop 30427 +usr/share/applications/nm-connection-editor.desktop 30426 +usr/share/applications/org.gnome.Nautilus.desktop 30425 +usr/share/applications/gnome-disk-image-mounter.desktop 30424 +usr/share/applications/poedit-uri.desktop 30423 +usr/share/applications/ibus-setup-chewing.desktop 30422 +usr/share/applications/ibus-setup-anthy.desktop 30421 +usr/share/applications/gcr-prompter.desktop 30420 +usr/share/applications/gnome-search-tool.desktop 30419 +usr/share/applications/gcr-viewer.desktop 30418 +usr/share/applications/gnome-wacom-panel.desktop 30417 +usr/share/applications/scribus.desktop 30416 +usr/share/applications/org.gnome.PowerStats.desktop 30415 +usr/share/applications/python2.7.desktop 30414 +usr/share/applications/tails-about.desktop 30413 +usr/lib/libreoffice/share/xdg/startcenter.desktop 30412 +usr/share/applications/tails-documentation.desktop 30411 +usr/share/applications/gnome-control-center.desktop 30410 +usr/share/applications/tails-installer.desktop 30409 +usr/share/applications/gnome-search-panel.desktop 30408 +usr/share/applications/org.gnome.FileRoller.desktop 30407 +usr/share/applications/vim.desktop 30406 +usr/share/applications/unsafe-browser.desktop 30405 +usr/share/applications/yelp.desktop 30404 +usr/share/applications/tor-browser.desktop 30403 +usr/share/applications/brasero.desktop 30402 +usr/share/applications/org.gnome.Terminal.desktop 30401 +usr/share/applications/org.gnome.Shell.PortalHelper.desktop 30400 +usr/share/applications/org.gnome.SoundRecorder.desktop 30399 +usr/share/applications/gnome-power-panel.desktop 30398 +usr/share/applications/audacity.desktop 30397 +usr/share/applications/org.gnome.gedit.desktop 30396 +usr/share/applications/ibus-setup-libpinyin.desktop 30395 +usr/share/applications/tails-persistence-setup.desktop 30394 +usr/share/applications/gnome-info-panel.desktop 30393 +usr/share/applications/nm-applet.desktop 30392 +usr/share/applications/gnome-region-panel.desktop 30391 +usr/share/applications/gnome-calculator.desktop 30390 +usr/share/applications/evince.desktop 30389 +usr/share/applications/gnome-keyboard-panel.desktop 30388 +usr/share/applications/gnome-notifications-panel.desktop 30387 +usr/share/applications/gkbd-keyboard-display.desktop 30386 +usr/share/applications/seahorse.desktop 30385 +usr/lib/libreoffice/share/xdg/calc.desktop 30384 +usr/share/applications/brasero-nautilus.desktop 30383 +usr/share/applications/gnome-shell-extension-prefs.desktop 30382 +usr/share/applications/bookletimposer.desktop 30381 +usr/lib/libreoffice/share/xdg/impress.desktop 30380 +usr/share/applications/ibus-setup-hangul.desktop 30379 +usr/share/applications/gnome-datetime-panel.desktop 30378 +usr/share/applications/ibus-setup.desktop 30377 +usr/share/applications/gnome-universal-access-panel.desktop 30376 +usr/share/applications/eog.desktop 30375 +usr/share/applications/electrum.desktop 30374 +usr/share/applications/nautilus-classic.desktop 30373 +usr/share/applications/sound-juicer.desktop 30372 +usr/share/applications/gnome-color-panel.desktop 30371 +usr/share/applications/dasher.desktop 30370 +usr/share/applications/gnome-mouse-panel.desktop 30369 +usr/share/applications/gnome-system-monitor.desktop 30368 +usr/lib/libreoffice/share/xdg/writer.desktop 30367 +usr/share/applications/seahorse-pgp-encrypted.desktop 30366 +usr/share/applications/gnome-disk-image-writer.desktop 30365 +usr/share/applications/gnome-printers-panel.desktop 30364 +usr/share/applications/org.gnome.Shell.desktop 30363 +usr/share/applications/keepassx.desktop 30362 +usr/share/applications/ibus-setup-libbopomofo.desktop 30361 +usr/share/applications/pidgin.desktop 30360 +usr/share/applications/onioncircuits.desktop 30359 +usr/share/applications/gimp.desktop 30358 +usr/share/applications/whisperback.desktop 30357 +usr/share/applications/gnome-display-panel.desktop 30356 +usr/share/applications/org.gnome.Screenshot.desktop 30355 +usr/share/applications/gtkhash.desktop 30354 +usr/share/applications/gnome-sharing-panel.desktop 30353 +usr/share/applications/display-im6.q16.desktop 30352 +usr/lib/libreoffice/share/xdg/draw.desktop 30351 +usr/share/applications/org.boum.tails.additional-software-config.desktop 30350 +usr/share/applications/evolution-calendar.desktop 30349 +usr/share/applications/gnome-network-panel.desktop 30348 +usr/share/applications/gnome-privacy-panel.desktop 30347 +usr/share/applications/gnome-background-panel.desktop 30346 +usr/share/applications/seahorse-pgp-keys.desktop 30345 +usr/share/applications/mat.desktop 30344 +usr/share/applications/nautilus-autorun-software.desktop 30343 +usr/share/applications/gnome-user-accounts-panel.desktop 30342 +usr/share/applications/inkscape.desktop 30341 +usr/share/applications/gnome-system-monitor-kde.desktop 30340 +usr/share/applications/org.gnome.DiskUtility.desktop 30339 +usr/share/applications/seahorse-pgp-signature.desktop 30338 +usr/share/applications/mutter.desktop 30337 +usr/share/applications/thunderbird.desktop 30336 +usr/share/applications/onionshare.desktop 30335 +usr/share/applications/root-terminal.desktop 30334 +usr/share/gnome-shell/gnome-shell-theme.gresource 30333 +usr/share/gnome-shell/theme/gnome-classic.css 30332 +usr/share/locale/en/LC_MESSAGES/gnome-desktop-3.0.mo 30331 +usr/share/tails/desktop_wallpaper.png 30330 +usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-png.so 30329 +usr/share/desktop-base/softwaves-theme/lockscreen/gnome-background.xml 30328 +usr/share/X11/xkb/rules/evdev.xml 30327 +usr/share/xml/iso-codes/iso_639-2.xml 30326 +usr/share/xml/iso-codes/iso_639-3.xml 30325 +usr/share/xml/iso-codes/iso_3166-1.xml 30324 +usr/lib/x86_64-linux-gnu/libibus-1.0.so.5.0.514 30323 +usr/bin/ibus-daemon 30322 +usr/share/X11/xkb/rules/evdev.lst 30321 +usr/share/X11/xkb/rules/evdev 30320 +usr/bin/xkbcomp 30319 +usr/share/X11/xkb/keycodes/evdev 30318 +usr/share/X11/xkb/keycodes/aliases 30317 +usr/share/X11/xkb/geometry/pc 30316 +usr/share/X11/xkb/types/complete 30315 +usr/share/X11/xkb/types/basic 30314 +usr/share/X11/xkb/types/mousekeys 30313 +usr/share/X11/xkb/types/pc 30312 +usr/share/X11/xkb/types/iso9995 30311 +usr/share/X11/xkb/types/level5 30310 +usr/share/X11/xkb/types/extra 30309 +usr/share/X11/xkb/types/numpad 30308 +usr/share/X11/xkb/compat/complete 30307 +usr/share/X11/xkb/compat/basic 30306 +usr/share/X11/xkb/compat/ledcaps 30305 +usr/share/X11/xkb/compat/lednum 30304 +usr/share/X11/xkb/compat/iso9995 30303 +usr/share/X11/xkb/compat/mousekeys 30302 +usr/share/X11/xkb/compat/accessx 30301 +usr/share/X11/xkb/compat/misc 30300 +usr/share/X11/xkb/compat/ledscroll 30299 +usr/share/X11/xkb/compat/xfree86 30298 +usr/share/X11/xkb/compat/level5 30297 +usr/share/X11/xkb/compat/caps 30296 +usr/share/X11/xkb/symbols/pc 30295 +usr/share/X11/xkb/symbols/srvr_ctrl 30294 +usr/share/X11/xkb/symbols/keypad 30293 +usr/share/ibus/keymaps/us 30292 +usr/share/ibus/keymaps/common 30291 +usr/share/ibus/keymaps/modifiers 30290 +usr/share/X11/xkb/symbols/altwin 30289 +usr/share/X11/xkb/symbols/us 30288 +usr/share/ibus/component/anthy.xml 30287 +usr/share/X11/xkb/symbols/inet 30286 +usr/lib/x86_64-linux-gnu/girepository-1.0/NMGtk-1.0.typelib 30285 +usr/lib/ibus/ibus-engine-anthy 30284 +usr/lib/x86_64-linux-gnu/girepository-1.0/GnomeBluetooth-1.0.typelib 30283 +usr/lib/x86_64-linux-gnu/libgnome-bluetooth.so.13.0.1 30282 +usr/lib/x86_64-linux-gnu/libnotify.so.4.0.0 30281 +usr/lib/x86_64-linux-gnu/girepository-1.0/UPowerGlib-1.0.typelib 30280 +usr/share/ibus-anthy/engine/main.py 30279 +usr/lib/python3.5/getopt.py 30278 +usr/lib/gnome-shell/Gvc-1.0.typelib 30277 +usr/lib/python3.5/xml/__init__.py 30276 +usr/lib/python3.5/xml/dom/__init__.py 30275 +usr/lib/python3.5/xml/dom/domreg.py 30274 +usr/lib/x86_64-linux-gnu/libaccountsservice.so.0.0.0 30273 +usr/lib/python3.5/xml/dom/minidom.py 30272 +usr/lib/x86_64-linux-gnu/libgdm.so.1.0.0 30271 +usr/share/gdm/BuiltInSessions/default.desktop 30270 +usr/share/xsessions/gnome-classic.desktop 30269 +usr/share/xsessions/gnome.desktop 30268 +usr/lib/python3.5/xml/dom/minicompat.py 30267 +usr/lib/python3.5/xml/dom/xmlbuilder.py 30266 +usr/lib/python3.5/xml/dom/NodeFilter.py 30265 +usr/lib/python3/dist-packages/gi/__init__.py 30264 +usr/lib/python3.5/pkgutil.py 30263 +usr/lib/python3.5/importlib/__init__.py 30262 +usr/lib/python3.5/importlib/util.py 30261 +usr/lib/python3.5/importlib/abc.py 30260 +usr/lib/python3.5/importlib/machinery.py 30259 +usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1.8.0 30258 +usr/lib/python3/dist-packages/gi/_gi.cpython-35m-x86_64-linux-gnu.so 30257 +usr/lib/gnome-settings-daemon/gnome-settings-daemon-localeexec 30256 +usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2.2 30253 +usr/lib/python3/dist-packages/gi/_error.py 30252 +usr/bin/spice-vdagent 30251 +usr/lib/python3/dist-packages/gi/repository/__init__.py 30248 +usr/lib/python3/dist-packages/gi/importer.py 30247 +usr/lib/python3/dist-packages/gi/module.py 30246 +usr/lib/python3/dist-packages/gi/types.py 30245 +usr/lib/python3/dist-packages/gi/_constants.py 30244 +usr/bin/gsettings 30243 +usr/lib/python3/dist-packages/gi/docstring.py 30242 +usr/lib/x86_64-linux-gnu/libkrb5.so.3.3 30241 +usr/lib/python3/dist-packages/gi/_propertyhelper.py 30240 +usr/lib/x86_64-linux-gnu/libk5crypto.so.3.1 30239 +lib/x86_64-linux-gnu/libcom_err.so.2.1 30238 +usr/lib/x86_64-linux-gnu/libkrb5support.so.0.1 30237 +lib/x86_64-linux-gnu/libkeyutils.so.1.5 30236 +usr/lib/python3/dist-packages/gi/_signalhelper.py 30235 +usr/lib/python3/dist-packages/gi/overrides/__init__.py 30234 +usr/lib/gnome-settings-daemon/gnome-settings-daemon 30233 +usr/lib/gnome-settings-daemon-3.0/libgsd.so 30232 +usr/lib/x86_64-linux-gnu/gio/modules/libgiognutls.so 30231 +etc/ssl/certs/ca-certificates.crt 30230 +usr/lib/python3/dist-packages/gi/overrides/GLib.py 30229 +usr/lib/python3/dist-packages/gi/_option.py 30228 +usr/lib/gnome-settings-daemon-3.0/a11y-keyboard.gnome-settings-plugin 30225 +usr/lib/gnome-settings-daemon-3.0/a11y-settings.gnome-settings-plugin 30224 +usr/lib/gnome-settings-daemon-3.0/clipboard.gnome-settings-plugin 30223 +usr/lib/gnome-settings-daemon-3.0/color.gnome-settings-plugin 30222 +usr/lib/gnome-settings-daemon-3.0/datetime.gnome-settings-plugin 30221 +usr/lib/gnome-settings-daemon-3.0/housekeeping.gnome-settings-plugin 30220 +usr/lib/gnome-settings-daemon-3.0/keyboard.gnome-settings-plugin 30219 +usr/lib/gnome-settings-daemon-3.0/media-keys.gnome-settings-plugin 30218 +usr/lib/gnome-settings-daemon-3.0/mouse.gnome-settings-plugin 30217 +usr/lib/gnome-settings-daemon-3.0/orientation.gnome-settings-plugin 30216 +usr/lib/gnome-settings-daemon-3.0/power.gnome-settings-plugin 30215 +usr/lib/gnome-settings-daemon-3.0/print-notifications.gnome-settings-plugin 30214 +usr/lib/gnome-settings-daemon-3.0/rfkill.gnome-settings-plugin 30213 +usr/lib/gnome-settings-daemon-3.0/screensaver-proxy.gnome-settings-plugin 30212 +usr/lib/gnome-settings-daemon-3.0/sharing.gnome-settings-plugin 30211 +usr/lib/gnome-settings-daemon-3.0/smartcard.gnome-settings-plugin 30210 +usr/lib/gnome-settings-daemon-3.0/sound.gnome-settings-plugin 30209 +usr/lib/gnome-settings-daemon-3.0/wacom.gnome-settings-plugin 30208 +usr/lib/gnome-settings-daemon-3.0/xrandr.gnome-settings-plugin 30207 +usr/lib/gnome-settings-daemon-3.0/xsettings.gnome-settings-plugin 30206 +usr/lib/gnome-settings-daemon-3.0/libpower.so 30205 +usr/lib/python3/dist-packages/gi/overrides/GObject.py 30204 +usr/lib/gnome-settings-daemon-3.0/libxsettings.so 30203 +usr/lib/gnome-settings-daemon-3.0/gtk-modules/at-spi2-atk.desktop 30202 +usr/lib/gnome-settings-daemon-3.0/gtk-modules/caribou-gtk-module.desktop 30201 +usr/lib/gnome-settings-daemon-3.0/gtk-modules/caribou-gtk3-module.desktop 30200 +etc/fonts/fonts.conf 30199 +usr/share/fontconfig/conf.avail/10-scale-bitmap-fonts.conf 30198 +usr/share/fontconfig/conf.avail/11-lcdfilter-default.conf 30197 +etc/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf 30196 +etc/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf 30195 +etc/fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf 30194 +etc/fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf 30193 +etc/fonts/conf.avail/20-unhint-small-dejavu-sans.conf 30192 +etc/fonts/conf.avail/20-unhint-small-dejavu-serif.conf 30191 +usr/share/fontconfig/conf.avail/20-unhint-small-vera.conf 30190 +usr/share/fontconfig/conf.avail/30-metric-aliases.conf 30189 +usr/share/fontconfig/conf.avail/30-urw-aliases.conf 30188 +etc/fonts/conf.avail/31-cantarell.conf 30187 +usr/share/fontconfig/conf.avail/40-nonlatin.conf 30186 +usr/share/fontconfig/conf.avail/45-latin.conf 30185 +usr/share/fontconfig/conf.avail/49-sansserif.conf 30184 +usr/share/fontconfig/conf.avail/50-user.conf 30183 +usr/share/fontconfig/conf.avail/51-local.conf 30182 +etc/fonts/conf.avail/57-dejavu-sans-mono.conf 30181 +etc/fonts/conf.avail/57-dejavu-sans.conf 30180 +etc/fonts/conf.avail/57-dejavu-serif.conf 30179 +usr/lib/python3/dist-packages/gi/overrides/Gio.py 30178 +etc/fonts/conf.avail/58-dejavu-lgc-sans-mono.conf 30177 +etc/fonts/conf.avail/58-dejavu-lgc-sans.conf 30176 +etc/fonts/conf.avail/58-dejavu-lgc-serif.conf 30175 +usr/share/fontconfig/conf.avail/60-latin.conf 30174 +etc/fonts/conf.avail/65-culmus.conf 30173 +usr/share/fontconfig/conf.avail/65-fonts-persian.conf 30172 +usr/share/fontconfig/conf.avail/65-nonlatin.conf 30171 +usr/share/fontconfig/conf.avail/69-unifont.conf 30170 +usr/share/fontconfig/conf.avail/70-fonts-noto-cjk.conf 30169 +usr/share/fontconfig/conf.avail/70-no-bitmaps.conf 30168 +usr/share/fontconfig/conf.avail/80-delicious.conf 30167 +etc/fonts/conf.avail/90-fonts-linux-libertine.conf 30166 +usr/share/fontconfig/conf.avail/90-synthetic.conf 30165 +etc/fonts/conf.d/99pdftoopvp.conf 30164 +var/cache/fontconfig/3830d5c3ddfd5cd38a049b759396e72e-le64.cache-4 30163 +var/cache/fontconfig/4c599c202bc5c08e2d34565a40eac3b2-le64.cache-4 30162 +var/cache/fontconfig/c855463f699352c367813e37f3f70ea7-le64.cache-4 30161 +var/cache/fontconfig/57e423e26b20ab21d0f2f29c145174c3-le64.cache-4 30160 +var/cache/fontconfig/573ec803664ed168555e0e8b6d0f0c7f-le64.cache-4 30159 +var/cache/fontconfig/7ef2298fde41cc6eeb7af42e48b7d293-le64.cache-4 30158 +var/cache/fontconfig/e13b20fdb08344e0e664864cc2ede53d-le64.cache-4 30157 +var/cache/fontconfig/707971e003b4ae6c8121c3a920e507f5-le64.cache-4 30156 +var/cache/fontconfig/fe547fea3a41b43a38975d292a2b19c7-le64.cache-4 30155 +var/cache/fontconfig/f1f2465696798768e9653f19e17ccdc8-le64.cache-4 30154 +var/cache/fontconfig/95530828ff6c81d309f8258d8d02a23e-le64.cache-4 30153 +var/cache/fontconfig/d3e5c4ee2ceb1fc347f91d4cefc53bc0-le64.cache-4 30152 +var/cache/fontconfig/e52a45a1c8c8fe895fc0fc8c4e6999b8-le64.cache-4 30151 +var/cache/fontconfig/188ac73a183f12857f63bb60a4a6d603-le64.cache-4 30150 +var/cache/fontconfig/62f91419b9ebdb6975e7e41ab6412357-le64.cache-4 30149 +var/cache/fontconfig/53d14c92082a93e67d5078324eb314ca-le64.cache-4 30148 +usr/lib/python3/dist-packages/gi/overrides/IBus.py 30147 +usr/share/ibus-anthy/engine/_config.py 30146 +var/cache/fontconfig/9b89f8e3dae116d678bbf48e5f21f69b-le64.cache-4 30145 +var/cache/fontconfig/a0513722a37733a9dfd54dccd328039d-le64.cache-4 30144 +var/cache/fontconfig/d589a48862398ed80a3d6066f4f56f4c-le64.cache-4 30143 +var/cache/fontconfig/3047814df9a2f067bd2d96a2b9c36e5a-le64.cache-4 30142 +var/cache/fontconfig/0bd3dc0958fa2205aaaa8ebb13e2872b-le64.cache-4 30141 +var/cache/fontconfig/4794a0821666d79190d59a36cb4f44b5-le64.cache-4 30140 +var/cache/fontconfig/6d41288fd70b0be22e8c3a91e032eec0-le64.cache-4 30139 +usr/lib/x86_64-linux-gnu/gio/modules/libgiolibproxy.so 30138 +var/cache/fontconfig/0fafd173547752dce4dee1a69e0b3c95-le64.cache-4 30137 +var/cache/fontconfig/6333f38776742d18e214673cd2c24e34-le64.cache-4 30136 +usr/lib/gnome-settings-daemon-3.0/libxrandr.so 30135 +usr/lib/x86_64-linux-gnu/libproxy.so.1.0.0 30134 +usr/lib/gnome-settings-daemon-3.0/libsound.so 30133 +usr/lib/x86_64-linux-gnu/gio/modules/libgiognomeproxy.so 30132 +usr/share/ibus-anthy/engine/factory.py 30131 +usr/share/ibus-anthy/engine/engine.py 30130 +usr/lib/x86_64-linux-gnu/gio/modules/libgioremote-volume-monitor.so 30129 +usr/lib/gnome-settings-daemon-3.0/libkeyboard.so 30128 +usr/lib/gnome-settings-daemon-3.0/liba11y-settings.so 30127 +usr/lib/gnome-settings-daemon-3.0/liba11y-keyboard.so 30126 +usr/lib/gnome-settings-daemon-3.0/libsmartcard.so 30125 +usr/share/X11/locale/locale.alias 30124 +usr/share/X11/locale/locale.dir 30123 +usr/lib/x86_64-linux-gnu/libnss3.so 30122 +usr/share/X11/locale/en_US.UTF-8/XLC_LOCALE 30121 +usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so 30120 +usr/lib/x86_64-linux-gnu/libnssutil3.so 30119 +usr/lib/gnome-settings-daemon-3.0/libcolor.so 30118 +usr/lib/x86_64-linux-gnu/libcolord.so.2.0.5 30117 +usr/lib/x86_64-linux-gnu/libcolordprivate.so.2.0.5 30116 +usr/lib/x86_64-linux-gnu/liblcms2.so.2.0.8 30115 +usr/lib/girepository-1.0/Anthy-9000.typelib 30114 +usr/share/ibus-anthy/engine/tables.py 30113 +usr/share/ibus-anthy/engine/jastring.py 30112 +usr/lib/gnome-settings-daemon-3.0/liborientation.so 30111 +usr/lib/gnome-settings-daemon-3.0/libmedia-keys.so 30110 +usr/share/ibus-anthy/engine/romaji.py 30109 +usr/share/ibus-anthy/engine/segment.py 30108 +usr/share/ibus-anthy/engine/kana.py 30107 +var/lib/polkit-1/localauthority/10-vendor.d/systemd-networkd.pkla 30106 +var/lib/polkit-1/localauthority/10-vendor.d/org.freedesktop.NetworkManager.pkla 30105 +var/lib/polkit-1/localauthority/10-vendor.d/gnome-control-center.pkla 30104 +etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.pkla 30103 +etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.cups.pkla 30102 +etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.accounts.pkla 30101 +usr/lib/gnome-settings-daemon-3.0/libclipboard.so 30100 +usr/bin/tails-greeter 30097 +usr/share/ibus-anthy/engine/thumb.py 30096 +lib/systemd/system/colord.service 30095 +usr/share/ibus-anthy/setup/anthyprefs.py 30093 +usr/lib/colord/colord 30092 +usr/share/tails-greeter/set-cursor.py 30091 +usr/lib/x86_64-linux-gnu/libgusb.so.2.0.10 30090 +usr/share/ibus-anthy/setup/prefs.py 30089 +usr/share/fonts/truetype/dejavu/DejaVuSans.ttf 30088 +usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so 30087 +usr/share/ibus-anthy/engine/default.xml 30086 +usr/lib/x86_64-linux-gnu/nss/libnssdbm3.so 30085 +usr/lib/x86_64-linux-gnu/nss/libfreeblpriv3.so 30083 +usr/lib/x86_64-linux-gnu/colord-plugins/libcd_plugin_camera.so 30079 +usr/lib/x86_64-linux-gnu/colord-plugins/libcd_plugin_sane.so 30078 +usr/lib/x86_64-linux-gnu/colord-plugins/libcd_plugin_scanner.so 30077 +usr/share/ibus/component/chewing.xml 30076 +usr/share/ibus/component/dconf.xml 30075 +usr/share/ibus/component/gtkpanel.xml 30074 +usr/share/ibus/component/hangul.xml 30073 +usr/share/ibus/component/libpinyin.xml 30072 +usr/share/ibus/component/simple.xml 30071 +usr/share/ibus/component/unikey.xml 30070 +lib/systemd/system/systemd-hostnamed.service 30069 +usr/lib/ibus/ibus-engine-unikey 30068 +usr/lib/ibus/ibus-dconf 30067 +usr/share/color/icc/colord/BestRGB.icc 30066 +usr/share/color/icc/colord/BetaRGB.icc 30064 +usr/share/color/icc/colord/BruceRGB.icc 30063 +usr/lib/ibus/ibus-x11 30062 +usr/share/color/icc/colord/Crayons.icc 30061 +usr/share/icons/Adwaita/index.theme 30060 +usr/share/color/icc/colord/DonRGB4.icc 30059 +usr/share/color/icc/colord/ECI-RGBv1.icc 30058 +usr/share/color/icc/colord/ECI-RGBv2.icc 30057 +usr/share/color/icc/colord/EktaSpacePS5.icc 30056 +usr/share/color/icc/colord/FOGRA27L_coated.icc 30055 +usr/share/color/icc/colord/FOGRA28L_webcoated.icc 30054 +usr/share/color/icc/colord/FOGRA29L_uncoated.icc 30053 +usr/share/color/icc/colord/FOGRA30L_uncoated_yellowish.icc 30052 +usr/share/color/icc/colord/FOGRA39L_coated.icc 30051 +usr/share/color/icc/colord/FOGRA40L_SC_paper.icc 30050 +usr/share/color/icc/colord/FOGRA45L_lwc.icc 30049 +usr/share/color/icc/colord/FOGRA47L_uncoated.icc 30048 +usr/share/color/icc/colord/GRACoL_TR006_coated.icc 30047 +usr/share/color/icc/colord/Gamma5000K.icc 30046 +usr/share/color/icc/colord/Gamma5500K.icc 30045 +usr/share/color/icc/colord/Gamma6500K.icc 30044 +usr/share/color/icc/colord/IFRA26S_2004_newsprint.icc 30043 +usr/share/color/icc/colord/SNAP_TR002_newsprint.icc 30042 +lib/systemd/systemd-hostnamed 30041 +usr/share/themes/Default/gtk-3.0/gtk-keys.css 30040 +usr/lib/python3/dist-packages/gi/overrides/Pango.py 30039 +usr/share/color/icc/colord/SWOP_TR003_coated_3.icc 30038 +etc/os-release 30037 +usr/share/color/icc/colord/SWOP_TR005_coated_5.icc 30036 +usr/share/icons/gnome/index.theme 30035 +usr/lib/python3/dist-packages/gi/overrides/Gdk.py 30034 +usr/share/color/icc/colord/WideGamutRGB.icc 30033 +usr/lib/x86_64-linux-gnu/girepository-1.0/GdkX11-3.0.typelib 30032 +usr/share/color/icc/ghostscript/default_cmyk.icc 30031 +usr/share/color/icc/ghostscript/default_gray.icc 30030 +usr/share/color/icc/ghostscript/default_rgb.icc 30029 +usr/lib/python3/dist-packages/gi/overrides/Gtk.py 30028 +usr/share/color/icc/ghostscript/gray_to_k.icc 30027 +usr/share/color/icc/ghostscript/lab.icc 30026 +usr/share/color/icc/ghostscript/ps_cmyk.icc 30025 +usr/share/color/icc/ghostscript/ps_gray.icc 30024 +usr/share/color/icc/ghostscript/ps_rgb.icc 30023 +usr/share/color/icc/ghostscript/sgray.icc 30022 +usr/share/color/icc/ghostscript/srgb.icc 30021 +usr/share/icons/hicolor/index.theme 30020 +usr/lib/colord/colord-sane 30017 +usr/lib/x86_64-linux-gnu/libsane.so.1.0.25 30016 +lib/systemd/system/systemd-localed.service 30015 +etc/sane.d/dll.d/hplip 30014 +etc/sane.d/dll.conf 30013 +usr/lib/x86_64-linux-gnu/sane/libsane-xerox_mfp.so.1.0.25 30012 +etc/sane.d/xerox_mfp.conf 30010 +usr/lib/x86_64-linux-gnu/sane/libsane-umax1220u.so.1.0.25 30009 +etc/sane.d/umax1220u.conf 30008 +usr/lib/x86_64-linux-gnu/sane/libsane-umax.so.1.0.25 30007 +usr/share/icons/Adwaita/16x16/apps/preferences-desktop-accessibility-symbolic.symbolic.png 30006 +usr/share/icons/Adwaita/48x48/actions/pan-down-symbolic.symbolic.png 30005 +usr/share/icons/Adwaita/16x16/actions/find-location-symbolic.symbolic.png 30004 +etc/sane.d/umax.conf 30003 +usr/share/icons/Adwaita/cursors/watch 30002 +usr/lib/x86_64-linux-gnu/sane/libsane-u12.so.1.0.25 30001 +etc/sane.d/u12.conf 30000 +usr/lib/x86_64-linux-gnu/sane/libsane-teco3.so.1.0.25 29999 +usr/share/fonts/opentype/cantarell/Cantarell-Regular.otf 29998 +etc/sane.d/teco3.conf 29997 +usr/lib/x86_64-linux-gnu/sane/libsane-teco2.so.1.0.25 29996 +etc/sane.d/teco2.conf 29995 +usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf 29994 +usr/lib/x86_64-linux-gnu/sane/libsane-teco1.so.1.0.25 29993 +etc/sane.d/teco1.conf 29992 +usr/lib/x86_64-linux-gnu/sane/libsane-tamarack.so.1.0.25 29991 +etc/sane.d/tamarack.conf 29990 +usr/lib/x86_64-linux-gnu/sane/libsane-sp15c.so.1.0.25 29989 +etc/sane.d/sp15c.conf 29988 +usr/lib/x86_64-linux-gnu/sane/libsane-snapscan.so.1.0.25 29987 +lib/systemd/systemd-localed 29986 +etc/sane.d/snapscan.conf 29985 +usr/lib/x86_64-linux-gnu/sane/libsane-sm3840.so.1.0.25 29984 +usr/lib/x86_64-linux-gnu/sane/libsane-sm3600.so.1.0.25 29983 +usr/lib/x86_64-linux-gnu/sane/libsane-sharp.so.1.0.25 29982 +etc/sane.d/sharp.conf 29981 +usr/lib/x86_64-linux-gnu/sane/libsane-sceptre.so.1.0.25 29980 +etc/sane.d/sceptre.conf 29979 +usr/lib/x86_64-linux-gnu/sane/libsane-s9036.so.1.0.25 29978 +etc/sane.d/s9036.conf 29977 +usr/lib/x86_64-linux-gnu/sane/libsane-rts8891.so.1.0.25 29976 +usr/share/icons/Adwaita/16x16/status/battery-full-charging-symbolic.symbolic.png 29975 +etc/sane.d/rts8891.conf 29974 +usr/lib/x86_64-linux-gnu/sane/libsane-ricoh.so.1.0.25 29973 +usr/share/tails-greeter/tails-greeter.py 29972 +usr/share/icons/Adwaita/48x48/status/battery-full-charging-symbolic.symbolic.png 29968 +etc/sane.d/ricoh.conf 29967 +usr/lib/x86_64-linux-gnu/sane/libsane-qcam.so.1.0.25 29966 +etc/sane.d/qcam.conf 29965 +usr/lib/x86_64-linux-gnu/sane/libsane-plustek.so.1.0.25 29964 +usr/lib/gnome-settings-daemon/gsd-backlight-helper 29963 +etc/sane.d/plustek.conf 29962 +usr/lib/x86_64-linux-gnu/sane/libsane-pixma.so.1.0.25 29961 +etc/sane.d/pixma.conf 29960 +usr/lib/python3.5/logging/config.py 29954 +usr/lib/ibus/ibus-engine-simple 29953 +usr/lib/python3.5/logging/handlers.py 29952 +usr/lib/python3.5/pickle.py 29951 +usr/share/desktop-base/softwaves-theme/lockscreen/contents/images/1920x1080.svg 29950 +usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so 29949 +usr/lib/x86_64-linux-gnu/librsvg-2.so.2.40.16 29948 +usr/lib/x86_64-linux-gnu/libnm-gtk.so.0.0.0 29947 +usr/lib/python3.5/_compat_pickle.py 29946 +usr/lib/python3.5/queue.py 29945 +usr/lib/python3.5/socketserver.py 29944 +usr/lib/python3.5/configparser.py 29943 +usr/share/tails-greeter/tails-logging.conf 29942 +usr/share/icons/Adwaita/48x48/devices/audio-speakers-symbolic.symbolic.png 29941 +usr/share/icons/Adwaita/16x16/status/audio-volume-medium-symbolic.symbolic.png 29940 +usr/local/lib/udev-watchdog-wrapper 29937 +usr/lib/x86_64-linux-gnu/sane/libsane-pie.so.1.0.25 29936 +etc/sane.d/pie.conf 29935 +usr/lib/x86_64-linux-gnu/sane/libsane-niash.so.1.0.25 29934 +usr/lib/x86_64-linux-gnu/sane/libsane-nec.so.1.0.25 29933 +etc/sane.d/nec.conf 29932 +usr/lib/x86_64-linux-gnu/sane/libsane-mustek_usb2.so.1.0.25 29931 +usr/lib/x86_64-linux-gnu/sane/libsane-mustek_usb.so.1.0.25 29930 +usr/lib/python3/dist-packages/tailsgreeter/__init__.py 29929 +usr/lib/python3/dist-packages/tailsgreeter/errors.py 29928 +usr/lib/python3/dist-packages/tailsgreeter/config.py 29927 +usr/lib/python3/dist-packages/tailsgreeter/gdmclient.py 29926 +usr/lib/python3/dist-packages/tailsgreeter/persistence.py 29925 +usr/lib/python3/dist-packages/tailsgreeter/utils.py 29924 +etc/sane.d/mustek_usb.conf 29923 +usr/lib/x86_64-linux-gnu/sane/libsane-mustek.so.1.0.25 29922 +usr/lib/x86_64-linux-gnu/libieee1284.so.3.2.2 29921 +etc/sane.d/mustek.conf 29920 +usr/lib/x86_64-linux-gnu/sane/libsane-microtek2.so.1.0.25 29919 +usr/lib/python3/dist-packages/tailsgreeter/physicalsecurity.py 29918 +usr/lib/python3.5/pipes.py 29917 +usr/local/sbin/udev-watchdog 29916 +etc/sane.d/microtek2.conf 29907 +usr/lib/x86_64-linux-gnu/sane/libsane-microtek.so.1.0.25 29906 +etc/sane.d/microtek.conf 29905 +usr/lib/x86_64-linux-gnu/sane/libsane-matsushita.so.1.0.25 29904 +usr/lib/python3.5/lib-dynload/_bz2.cpython-35m-x86_64-linux-gnu.so 29903 +etc/sane.d/matsushita.conf 29902 +usr/lib/x86_64-linux-gnu/sane/libsane-magicolor.so.1.0.25 29901 +usr/lib/python3.5/lib-dynload/_lzma.cpython-35m-x86_64-linux-gnu.so 29898 +etc/sane.d/magicolor.conf 29897 +usr/lib/x86_64-linux-gnu/sane/libsane-ma1509.so.1.0.25 29896 +etc/sane.d/ma1509.conf 29895 +usr/lib/x86_64-linux-gnu/sane/libsane-lexmark.so.1.0.25 29894 +usr/lib/python3.5/shlex.py 29893 +usr/lib/python3/dist-packages/tailsgreeter/rootaccess.py 29892 +usr/lib/python3/dist-packages/tailsgreeter/language.py 29891 +etc/sane.d/lexmark.conf 29890 +usr/lib/x86_64-linux-gnu/sane/libsane-leo.so.1.0.25 29889 +etc/sane.d/leo.conf 29888 +usr/lib/x86_64-linux-gnu/sane/libsane-kvs20xx.so.1.0.25 29887 +usr/lib/x86_64-linux-gnu/sane/libsane-kvs1025.so.1.0.25 29886 +usr/lib/python3/dist-packages/pycountry/__init__.py 29885 +usr/lib/python3/dist-packages/pycountry/db.py 29884 +usr/lib/x86_64-linux-gnu/sane/libsane-kodakaio.so.1.0.25 29883 +usr/lib/x86_64-linux-gnu/libavahi-common.so.3.5.3 29882 +usr/lib/x86_64-linux-gnu/libavahi-client.so.3.2.9 29881 +etc/sane.d/kodakaio.conf 29880 +usr/lib/python3/dist-packages/pkg_resources/__init__.py 29879 +usr/lib/x86_64-linux-gnu/sane/libsane-kodak.so.1.0.25 29878 +etc/sane.d/kodak.conf 29877 +usr/lib/x86_64-linux-gnu/sane/libsane-ibm.so.1.0.25 29876 +etc/sane.d/ibm.conf 29875 +usr/lib/x86_64-linux-gnu/sane/libsane-hs2p.so.1.0.25 29874 +etc/sane.d/hs2p.conf 29873 +usr/lib/x86_64-linux-gnu/sane/libsane-hpljm1005.so.1.0.25 29872 +usr/lib/x86_64-linux-gnu/sane/libsane-hp5590.so.1.0.25 29871 +usr/lib/x86_64-linux-gnu/sane/libsane-hp5400.so.1.0.25 29870 +etc/sane.d/hp5400.conf 29869 +usr/lib/x86_64-linux-gnu/sane/libsane-hp4200.so.1.0.25 29868 +usr/lib/python3.5/zipfile.py 29867 +etc/sane.d/hp4200.conf 29866 +usr/lib/x86_64-linux-gnu/sane/libsane-hp3500.so.1.0.25 29865 +usr/lib/x86_64-linux-gnu/sane/libsane-hpsj5s.so.1.0.25 29864 +etc/sane.d/hpsj5s.conf 29863 +usr/lib/x86_64-linux-gnu/sane/libsane-hp3900.so.1.0.25 29862 +usr/lib/python3.5/platform.py 29861 +usr/lib/x86_64-linux-gnu/libtiff.so.5.2.6 29860 +usr/lib/x86_64-linux-gnu/libjbig.so.0 29859 +usr/lib/x86_64-linux-gnu/libjpeg.so.62.2.0 29858 +etc/sane.d/hp3900.conf 29857 +usr/lib/x86_64-linux-gnu/sane/libsane-hp.so.1.0.25 29856 +usr/lib/python3.5/plistlib.py 29855 +etc/sane.d/hp.conf 29854 +usr/lib/python3.5/xml/parsers/__init__.py 29851 +usr/lib/python3.5/xml/parsers/expat.py 29850 +usr/lib/x86_64-linux-gnu/sane/libsane-gt68xx.so.1.0.25 29849 +usr/lib/python3.5/email/__init__.py 29848 +usr/lib/python3.5/email/parser.py 29847 +usr/lib/python3.5/email/feedparser.py 29846 +etc/sane.d/gt68xx.conf 29845 +usr/lib/x86_64-linux-gnu/sane/libsane-genesys.so.1.0.25 29844 +usr/lib/python3.5/email/errors.py 29843 +usr/lib/python3.5/email/message.py 29842 +etc/sane.d/genesys.conf 29841 +usr/lib/x86_64-linux-gnu/sane/libsane-fujitsu.so.1.0.25 29840 +usr/lib/python3.5/uu.py 29839 +usr/lib/python3.5/quopri.py 29838 +usr/lib/python3.5/email/utils.py 29837 +etc/sane.d/fujitsu.conf 29836 +usr/lib/x86_64-linux-gnu/sane/libsane-epsonds.so.1.0.25 29835 +usr/lib/python3.5/urllib/__init__.py 29834 +usr/lib/python3.5/urllib/parse.py 29833 +etc/sane.d/epsonds.conf 29832 +usr/lib/x86_64-linux-gnu/sane/libsane-epson2.so.1.0.25 29831 +etc/sane.d/epson2.conf 29830 +usr/lib/python3.5/email/_parseaddr.py 29829 +usr/lib/python3.5/calendar.py 29828 +usr/lib/python3.5/email/charset.py 29827 +usr/lib/python3.5/email/base64mime.py 29826 +usr/lib/python3.5/base64.py 29825 +usr/lib/python3.5/email/quoprimime.py 29824 +usr/lib/python3.5/email/encoders.py 29823 +usr/lib/python3.5/email/_policybase.py 29822 +usr/lib/python3.5/email/header.py 29821 +usr/lib/python3.5/email/_encoded_words.py 29820 +usr/lib/python3.5/email/iterators.py 29819 +usr/lib/python3/dist-packages/pkg_resources/extern/__init__.py 29818 +usr/lib/python3/dist-packages/pkg_resources/_vendor/__init__.py 29817 +usr/lib/python3/dist-packages/pkg_resources/_vendor/six.py 29816 +usr/lib/python3/dist-packages/pkg_resources/_vendor/appdirs.py 29815 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/__init__.py 29814 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/__about__.py 29813 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/version.py 29812 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/_structures.py 29811 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/specifiers.py 29810 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/_compat.py 29809 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/requirements.py 29808 +usr/lib/python3/dist-packages/pkg_resources/_vendor/pyparsing.py 29807 +usr/lib/python3.5/pprint.py 29806 +usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/markers.py 29805 +usr/lib/python3/dist-packages/whisperback-1.7.23.egg-info 29804 +usr/lib/python3/dist-packages/Werkzeug-0.11.15.egg-info/PKG-INFO 29803 +usr/lib/python3/dist-packages/urllib3-1.19.1.egg-info/PKG-INFO 29802 +usr/lib/python3/dist-packages/tails_greeter-1.0.10.egg-info 29801 +usr/lib/python3/dist-packages/systemd_python-233.egg-info 29800 +usr/lib/python3/dist-packages/stem-1.5.3.egg-info 29799 +usr/lib/python3/dist-packages/six-1.10.0.egg-info/PKG-INFO 29798 +usr/lib/python3/dist-packages/sh-1.11.egg-info 29797 +usr/lib/python3/dist-packages/setuptools-33.1.1.egg-info/PKG-INFO 29796 +usr/lib/python3/dist-packages/requests-2.12.4.egg-info/PKG-INFO 29795 +usr/lib/python3/dist-packages/reportlab-3.3.0.egg-info 29794 +usr/lib/python3/dist-packages/regex-2017.01.17.egg-info 29793 +usr/lib/python3/dist-packages/qrcode-5.3.egg-info/PKG-INFO 29792 +usr/lib/python3/dist-packages/PyYAML-3.12.egg-info 29791 +usr/lib/python3/dist-packages/pyxdg-0.25.egg-info 29790 +usr/lib/python3/dist-packages/pytz-2016.7.egg-info/PKG-INFO 29789 +usr/lib/python3/dist-packages/python_pam-1.8.2.egg-info/PKG-INFO 29788 +usr/lib/python3/dist-packages/python_gnupg-0.3.9.egg-info 29787 +usr/lib/python3/dist-packages/python_apt-1.4.0.b3.egg-info 29786 +usr/lib/python3/dist-packages/PySocks-1.6.5.egg-info 29785 +usr/lib/python3/dist-packages/pyserial-3.2.1.egg-info 29784 +usr/lib/python3/dist-packages/pyinotify-0.9.6.egg-info 29783 +usr/lib/python3/dist-packages/pygobject-3.22.0.egg-info 29782 +usr/lib/python3/dist-packages/pydbus-0.6.0.egg-info/PKG-INFO 29781 +usr/lib/python3/dist-packages/pycups-1.9.73.egg-info 29780 +usr/lib/python3/dist-packages/pycountry-1.8.egg-info/PKG-INFO 29779 +usr/lib/python3/dist-packages/pyaes-1.6.1.egg-info 29778 +usr/lib/python3/dist-packages/ptyprocess-0.5.1.egg-info 29777 +usr/lib/python3/dist-packages/psutil-5.0.1.egg-info 29776 +usr/lib/python3/dist-packages/protobuf-3.0.0.egg-info/PKG-INFO 29775 +usr/lib/python3/dist-packages/Pillow-4.0.0.egg-info/PKG-INFO 29774 +usr/lib/python3/dist-packages/pexpect-4.2.1.egg-info 29773 +usr/lib/python3/dist-packages/onionshare-0.9.2.egg-info/PKG-INFO 29772 +usr/lib/python3/dist-packages/onioncircuits-0.6.egg-info 29771 +usr/lib/python3/dist-packages/MarkupSafe-0.23.egg-info/PKG-INFO 29770 +usr/lib/python3/dist-packages/lxml-3.7.1.egg-info/PKG-INFO 29769 +usr/lib/python3/dist-packages/louis-3.0.0.egg-info 29768 +usr/lib/python3/dist-packages/jsonrpclib_pelix-0.3.1.egg-info/PKG-INFO 29767 +usr/lib/python3/dist-packages/Jinja2-2.8.egg-info/PKG-INFO 29766 +usr/lib/python3/dist-packages/itsdangerous-0.24.egg-info/PKG-INFO 29765 +usr/lib/python3/dist-packages/Flask-0.12.1.egg-info/PKG-INFO 29764 +usr/lib/python3/dist-packages/Electrum-3.2.3.egg-info/PKG-INFO 29763 +usr/lib/python3/dist-packages/ecdsa-0.13.egg-info 29762 +usr/lib/python3/dist-packages/dnspython-1.15.0.egg-info/PKG-INFO 29761 +usr/lib/python3/dist-packages/cupshelpers-1.0.egg-info 29760 +usr/lib/python3/dist-packages/colorama-0.3.7.egg-info/PKG-INFO 29759 +usr/lib/python3/dist-packages/click-6.6.egg-info/PKG-INFO 29758 +usr/lib/python3/dist-packages/chardet-2.3.0.egg-info/PKG-INFO 29757 +usr/lib/python3/dist-packages/Brlapi-0.6.5.egg-info 29756 +usr/lib/python3/dist-packages/atomicwrites-1.1.5.egg-info/PKG-INFO 29755 +usr/lib/python3/dist-packages/protobuf-3.0.0.egg-info/namespace_packages.txt 29754 +usr/lib/python3.5/xml/dom/expatbuilder.py 29753 +usr/share/xml/iso-codes/iso_15924.xml 29752 +usr/share/xml/iso-codes/iso_4217.xml 29751 +usr/share/xml/iso-codes/iso_3166-2.xml 29750 +usr/lib/python3/dist-packages/pytz/__init__.py 29749 +usr/lib/python3/dist-packages/pytz/exceptions.py 29748 +usr/lib/python3/dist-packages/pytz/lazy.py 29747 +usr/lib/python3/dist-packages/pytz/tzinfo.py 29746 +usr/lib/python3.5/bisect.py 29745 +usr/lib/python3/dist-packages/pytz/tzfile.py 29744 +usr/lib/python3/dist-packages/tailsgreeter/gui.py 29743 +usr/lib/python3.5/webbrowser.py 29742 +usr/lib/x86_64-linux-gnu/girepository-1.0/WebKit2-4.0.typelib 29741 +usr/lib/x86_64-linux-gnu/girepository-1.0/JavaScriptCore-4.0.typelib 29740 +usr/share/locale/en/LC_MESSAGES/tails-greeter.mo 29739 +usr/share/tails-greeter/default_langcodes 29738 +usr/share/tails-greeter/language_codes 29737 +lib/systemd/systemd-update-utmp 29733 +usr/share/tails-greeter/greeter.css 29731 +usr/share/tails-greeter/greeter.ui 29730 +usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules.cache 29729 +usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules/im-ibus.so 29728 +usr/lib/locale/am_ET/LC_MESSAGES/SYS_LC_MESSAGES 29727 +usr/share/locale/am/LC_MESSAGES/iso_639-2.mo 29726 +usr/lib/locale/ar_AE/LC_MESSAGES/SYS_LC_MESSAGES 29725 +usr/share/locale/ar/LC_MESSAGES/iso_639-2.mo 29724 +usr/lib/locale/ast_ES/LC_MESSAGES/SYS_LC_MESSAGES 29723 +usr/share/locale/ast/LC_MESSAGES/iso_639-2.mo 29722 +usr/lib/locale/be_BY/LC_MESSAGES/SYS_LC_MESSAGES 29721 +usr/share/locale/be/LC_MESSAGES/iso_639-2.mo 29720 +usr/lib/locale/bg_BG/LC_MESSAGES/SYS_LC_MESSAGES 29719 +usr/share/locale/bg/LC_MESSAGES/iso_639-2.mo 29718 +usr/lib/locale/bn_BD/LC_MESSAGES/SYS_LC_MESSAGES 29717 +usr/share/locale/bn/LC_MESSAGES/iso_639-2.mo 29716 +usr/lib/locale/bo_CN/LC_MESSAGES/SYS_LC_MESSAGES 29715 +usr/lib/locale/br_FR/LC_MESSAGES/SYS_LC_MESSAGES 29714 +usr/share/locale/br/LC_MESSAGES/iso_639-2.mo 29713 +usr/lib/locale/bs_BA/LC_MESSAGES/SYS_LC_MESSAGES 29712 +usr/share/locale/bs/LC_MESSAGES/iso_639-2.mo 29711 +usr/lib/locale/ca_ES/LC_MESSAGES/SYS_LC_MESSAGES 29710 +usr/share/locale/ca/LC_MESSAGES/iso_639-2.mo 29709 +usr/lib/x86_64-linux-gnu/sane/libsane-epjitsu.so.1.0.25 29708 +etc/sane.d/epjitsu.conf 29707 +usr/lib/x86_64-linux-gnu/sane/libsane-dmc.so.1.0.25 29706 +etc/sane.d/dmc.conf 29705 +usr/lib/x86_64-linux-gnu/sane/libsane-dell1600n_net.so.1.0.25 29704 +etc/sane.d/dell1600n_net.conf 29703 +usr/lib/locale/cs_CZ/LC_MESSAGES/SYS_LC_MESSAGES 29702 +usr/share/locale/cs/LC_MESSAGES/iso_639-2.mo 29701 +usr/lib/locale/cy_GB/LC_MESSAGES/SYS_LC_MESSAGES 29700 +usr/share/locale/cy/LC_MESSAGES/iso_639-2.mo 29699 +usr/lib/locale/da_DK/LC_MESSAGES/SYS_LC_MESSAGES 29698 +usr/share/locale/da/LC_MESSAGES/iso_639-2.mo 29697 +usr/lib/locale/de_AT/LC_MESSAGES/SYS_LC_MESSAGES 29696 +usr/share/locale/de/LC_MESSAGES/iso_639-2.mo 29695 +usr/lib/locale/dz_BT/LC_MESSAGES/SYS_LC_MESSAGES 29694 +usr/lib/locale/el_CY/LC_MESSAGES/SYS_LC_MESSAGES 29693 +usr/share/locale/el/LC_MESSAGES/iso_639-2.mo 29692 +usr/lib/locale/en_AU/LC_MESSAGES/SYS_LC_MESSAGES 29691 +usr/share/locale/es/LC_MESSAGES/iso_639-2.mo 29690 +usr/lib/locale/et_EE/LC_MESSAGES/SYS_LC_MESSAGES 29689 +usr/share/locale/et/LC_MESSAGES/iso_639-2.mo 29688 +usr/lib/locale/eu_ES/LC_MESSAGES/SYS_LC_MESSAGES 29687 +usr/share/locale/eu/LC_MESSAGES/iso_639-2.mo 29686 +usr/lib/x86_64-linux-gnu/sane/libsane-coolscan3.so.1.0.25 29685 +usr/lib/locale/fa_IR/LC_MESSAGES/SYS_LC_MESSAGES 29684 +usr/share/locale/fa/LC_MESSAGES/iso_639-2.mo 29683 +usr/lib/locale/fi_FI/LC_MESSAGES/SYS_LC_MESSAGES 29682 +usr/share/locale/fi/LC_MESSAGES/iso_639-2.mo 29681 +usr/lib/locale/fr_CA/LC_MESSAGES/SYS_LC_MESSAGES 29680 +usr/share/locale/fr/LC_MESSAGES/iso_639-2.mo 29679 +usr/lib/locale/ga_IE/LC_MESSAGES/SYS_LC_MESSAGES 29678 +usr/share/locale/ga/LC_MESSAGES/iso_639-2.mo 29677 +usr/lib/locale/gl_ES/LC_MESSAGES/SYS_LC_MESSAGES 29676 +usr/share/locale/gl/LC_MESSAGES/iso_639-2.mo 29675 +usr/lib/locale/gu_IN/LC_MESSAGES/SYS_LC_MESSAGES 29674 +usr/share/locale/gu/LC_MESSAGES/iso_639-2.mo 29673 +usr/lib/locale/he_IL/LC_MESSAGES/SYS_LC_MESSAGES 29672 +usr/share/locale/he/LC_MESSAGES/iso_639-2.mo 29671 +usr/lib/locale/bho_IN/LC_MESSAGES/SYS_LC_MESSAGES 29670 +usr/share/locale/hi/LC_MESSAGES/iso_639-2.mo 29669 +usr/share/locale/hr/LC_MESSAGES/iso_639-2.mo 29668 +usr/lib/locale/hu_HU/LC_MESSAGES/SYS_LC_MESSAGES 29667 +usr/share/locale/hu/LC_MESSAGES/iso_639-2.mo 29666 +usr/lib/locale/id_ID/LC_MESSAGES/SYS_LC_MESSAGES 29665 +usr/share/locale/id/LC_MESSAGES/iso_639-2.mo 29664 +usr/lib/locale/is_IS/LC_MESSAGES/SYS_LC_MESSAGES 29663 +usr/share/locale/is/LC_MESSAGES/iso_639-2.mo 29662 +usr/lib/locale/it_IT/LC_MESSAGES/SYS_LC_MESSAGES 29661 +usr/share/locale/it/LC_MESSAGES/iso_639-2.mo 29660 +etc/sane.d/coolscan3.conf 29659 +usr/lib/x86_64-linux-gnu/sane/libsane-coolscan.so.1.0.25 29658 +usr/lib/locale/ka_GE/LC_MESSAGES/SYS_LC_MESSAGES 29657 +usr/lib/locale/kk_KZ/LC_MESSAGES/SYS_LC_MESSAGES 29656 +usr/lib/locale/km_KH/LC_MESSAGES/SYS_LC_MESSAGES 29655 +usr/lib/locale/kn_IN/LC_MESSAGES/SYS_LC_MESSAGES 29654 +etc/sane.d/coolscan.conf 29653 +usr/lib/x86_64-linux-gnu/sane/libsane-cardscan.so.1.0.25 29652 +usr/share/locale/kn/LC_MESSAGES/iso_639-2.mo 29651 +usr/lib/locale/ku_TR/LC_MESSAGES/SYS_LC_MESSAGES 29650 +usr/lib/locale/lo_LA/LC_MESSAGES/SYS_LC_MESSAGES 29649 +usr/lib/locale/lt_LT/LC_MESSAGES/SYS_LC_MESSAGES 29648 +usr/share/locale/lt/LC_MESSAGES/iso_639-2.mo 29647 +usr/lib/locale/lv_LV/LC_MESSAGES/SYS_LC_MESSAGES 29646 +usr/share/locale/lv/LC_MESSAGES/iso_639-2.mo 29645 +usr/lib/locale/mk_MK/LC_MESSAGES/SYS_LC_MESSAGES 29644 +usr/share/locale/mk/LC_MESSAGES/iso_639-2.mo 29643 +usr/lib/locale/ml_IN/LC_MESSAGES/SYS_LC_MESSAGES 29642 +usr/share/locale/ml/LC_MESSAGES/iso_639-2.mo 29641 +etc/sane.d/cardscan.conf 29640 +usr/lib/x86_64-linux-gnu/sane/libsane-canon_dr.so.1.0.25 29639 +usr/lib/locale/mr_IN/LC_MESSAGES/SYS_LC_MESSAGES 29638 +usr/share/locale/mr/LC_MESSAGES/iso_639-2.mo 29637 +usr/lib/locale/my_MM/LC_MESSAGES/SYS_LC_MESSAGES 29636 +usr/lib/locale/nb_NO/LC_MESSAGES/SYS_LC_MESSAGES 29635 +usr/share/locale/nb/LC_MESSAGES/iso_639-2.mo 29634 +usr/lib/locale/ne_NP/LC_MESSAGES/SYS_LC_MESSAGES 29633 +usr/lib/locale/af_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29632 +usr/share/locale/nl/LC_MESSAGES/iso_639-2.mo 29631 +usr/share/locale/nn/LC_MESSAGES/iso_639-2.mo 29630 +usr/lib/locale/pa_IN/LC_MESSAGES/SYS_LC_MESSAGES 29629 +usr/share/locale/pa/LC_MESSAGES/iso_639-2.mo 29628 +usr/lib/locale/pl_PL/LC_MESSAGES/SYS_LC_MESSAGES 29627 +usr/share/locale/pl/LC_MESSAGES/iso_639-2.mo 29626 +usr/lib/locale/pt_BR/LC_MESSAGES/SYS_LC_MESSAGES 29625 +usr/share/locale/pt/LC_MESSAGES/iso_639-2.mo 29624 +usr/lib/locale/ro_RO/LC_MESSAGES/SYS_LC_MESSAGES 29623 +usr/share/locale/ro/LC_MESSAGES/iso_639-2.mo 29622 +usr/lib/locale/ru_RU/LC_MESSAGES/SYS_LC_MESSAGES 29621 +usr/share/locale/ru/LC_MESSAGES/iso_639-2.mo 29620 +usr/lib/locale/se_NO/LC_MESSAGES/SYS_LC_MESSAGES 29619 +usr/lib/locale/si_LK/LC_MESSAGES/SYS_LC_MESSAGES 29618 +usr/lib/locale/sk_SK/LC_MESSAGES/SYS_LC_MESSAGES 29617 +usr/share/locale/sk/LC_MESSAGES/iso_639-2.mo 29616 +usr/lib/locale/sl_SI/LC_MESSAGES/SYS_LC_MESSAGES 29615 +usr/share/locale/sl/LC_MESSAGES/iso_639-2.mo 29614 +usr/lib/locale/sq_AL/LC_MESSAGES/SYS_LC_MESSAGES 29613 +usr/lib/locale/mk_MK.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29612 +usr/share/locale/sr/LC_MESSAGES/iso_639-2.mo 29611 +usr/lib/locale/sv_FI/LC_MESSAGES/SYS_LC_MESSAGES 29610 +usr/share/locale/sv/LC_MESSAGES/iso_639-2.mo 29609 +usr/lib/locale/ta_IN/LC_MESSAGES/SYS_LC_MESSAGES 29608 +usr/share/locale/ta/LC_MESSAGES/iso_639-2.mo 29607 +usr/lib/locale/te_IN/LC_MESSAGES/SYS_LC_MESSAGES 29606 +usr/share/locale/te/LC_MESSAGES/iso_639-2.mo 29605 +usr/lib/locale/th_TH/LC_MESSAGES/SYS_LC_MESSAGES 29604 +usr/share/locale/th/LC_MESSAGES/iso_639-2.mo 29603 +usr/lib/locale/tl_PH/LC_MESSAGES/SYS_LC_MESSAGES 29602 +usr/lib/locale/tr_CY/LC_MESSAGES/SYS_LC_MESSAGES 29601 +usr/share/locale/tr/LC_MESSAGES/iso_639-2.mo 29600 +usr/lib/locale/ug_CN/LC_MESSAGES/SYS_LC_MESSAGES 29599 +usr/lib/locale/uk_UA/LC_MESSAGES/SYS_LC_MESSAGES 29598 +usr/share/locale/uk/LC_MESSAGES/iso_639-2.mo 29597 +etc/sane.d/canon_dr.conf 29596 +usr/lib/x86_64-linux-gnu/sane/libsane-canon630u.so.1.0.25 29595 +usr/lib/locale/vi_VN/LC_MESSAGES/SYS_LC_MESSAGES 29594 +usr/share/locale/vi/LC_MESSAGES/iso_639-2.mo 29593 +usr/lib/locale/zh_CN/LC_MESSAGES/SYS_LC_MESSAGES 29592 +usr/share/locale/zh_CN/LC_MESSAGES/iso_639-2.mo 29591 +usr/lib/locale/aa_DJ/LC_MESSAGES/SYS_LC_MESSAGES 29590 +usr/share/locale/af/LC_MESSAGES/iso_639-2.mo 29589 +usr/lib/locale/ak_GH/LC_MESSAGES/SYS_LC_MESSAGES 29588 +usr/lib/locale/an_ES/LC_MESSAGES/SYS_LC_MESSAGES 29587 +usr/lib/locale/anp_IN/LC_MESSAGES/SYS_LC_MESSAGES 29586 +usr/lib/locale/ayc_PE/LC_MESSAGES/SYS_LC_MESSAGES 29585 +usr/lib/locale/az_AZ/LC_MESSAGES/SYS_LC_MESSAGES 29584 +usr/share/locale/az/LC_MESSAGES/iso_639-2.mo 29583 +usr/lib/locale/as_IN/LC_MESSAGES/SYS_LC_MESSAGES 29582 +usr/share/locale/as/LC_MESSAGES/iso_639-2.mo 29581 +usr/lib/locale/bem_ZM/LC_MESSAGES/SYS_LC_MESSAGES 29580 +usr/lib/locale/brx_IN/LC_MESSAGES/SYS_LC_MESSAGES 29579 +usr/lib/locale/bhb_IN.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29578 +usr/share/locale/byn/LC_MESSAGES/iso_639-2.mo 29577 +usr/lib/locale/ce_RU/LC_MESSAGES/SYS_LC_MESSAGES 29576 +usr/lib/locale/chr_US/LC_MESSAGES/SYS_LC_MESSAGES 29575 +usr/lib/locale/cmn_TW/LC_MESSAGES/SYS_LC_MESSAGES 29574 +usr/lib/locale/crh_UA/LC_MESSAGES/SYS_LC_MESSAGES 29573 +usr/share/locale/crh/LC_MESSAGES/iso_639-2.mo 29572 +etc/sane.d/canon630u.conf 29571 +usr/lib/x86_64-linux-gnu/sane/libsane-canon.so.1.0.25 29570 +usr/lib/locale/csb_PL/LC_MESSAGES/SYS_LC_MESSAGES 29569 +usr/lib/locale/doi_IN/LC_MESSAGES/SYS_LC_MESSAGES 29568 +usr/lib/locale/ff_SN/LC_MESSAGES/SYS_LC_MESSAGES 29567 +usr/lib/locale/fil_PH/LC_MESSAGES/SYS_LC_MESSAGES 29566 +usr/lib/locale/fo_FO/LC_MESSAGES/SYS_LC_MESSAGES 29565 +usr/lib/locale/fur_IT/LC_MESSAGES/SYS_LC_MESSAGES 29564 +usr/lib/locale/af_ZA.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29563 +usr/lib/locale/gd_GB/LC_MESSAGES/SYS_LC_MESSAGES 29562 +usr/share/locale/gez/LC_MESSAGES/iso_639-2.mo 29561 +usr/lib/locale/gv_GB/LC_MESSAGES/SYS_LC_MESSAGES 29560 +usr/lib/locale/ha_NG/LC_MESSAGES/SYS_LC_MESSAGES 29559 +usr/lib/locale/hak_TW/LC_MESSAGES/SYS_LC_MESSAGES 29558 +usr/lib/locale/hne_IN/LC_MESSAGES/SYS_LC_MESSAGES 29557 +usr/lib/locale/hsb_DE/LC_MESSAGES/SYS_LC_MESSAGES 29556 +usr/lib/locale/ht_HT/LC_MESSAGES/SYS_LC_MESSAGES 29555 +usr/lib/locale/hy_AM/LC_MESSAGES/SYS_LC_MESSAGES 29554 +usr/lib/locale/ia_FR/LC_MESSAGES/SYS_LC_MESSAGES 29553 +usr/lib/locale/ig_NG/LC_MESSAGES/SYS_LC_MESSAGES 29552 +usr/lib/locale/ik_CA/LC_MESSAGES/SYS_LC_MESSAGES 29551 +usr/lib/locale/iu_CA/LC_MESSAGES/SYS_LC_MESSAGES 29550 +usr/lib/locale/kl_GL/LC_MESSAGES/SYS_LC_MESSAGES 29549 +usr/lib/locale/kok_IN/LC_MESSAGES/SYS_LC_MESSAGES 29548 +usr/share/locale/kok/LC_MESSAGES/iso_639-2.mo 29547 +usr/lib/locale/ks_IN/LC_MESSAGES/SYS_LC_MESSAGES 29546 +usr/lib/locale/kw_GB/LC_MESSAGES/SYS_LC_MESSAGES 29545 +usr/lib/locale/ky_KG/LC_MESSAGES/SYS_LC_MESSAGES 29544 +usr/lib/locale/lb_LU/LC_MESSAGES/SYS_LC_MESSAGES 29543 +usr/lib/locale/lg_UG/LC_MESSAGES/SYS_LC_MESSAGES 29542 +usr/lib/locale/an_ES.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29541 +usr/lib/locale/ln_CD/LC_MESSAGES/SYS_LC_MESSAGES 29540 +usr/lib/locale/lzh_TW/LC_MESSAGES/SYS_LC_MESSAGES 29539 +usr/lib/locale/mg_MG/LC_MESSAGES/SYS_LC_MESSAGES 29538 +usr/lib/locale/mhr_RU/LC_MESSAGES/SYS_LC_MESSAGES 29537 +usr/lib/locale/mi_NZ/LC_MESSAGES/SYS_LC_MESSAGES 29536 +usr/share/locale/mi/LC_MESSAGES/iso_639-2.mo 29535 +usr/lib/locale/mn_MN/LC_MESSAGES/SYS_LC_MESSAGES 29534 +usr/share/locale/mn/LC_MESSAGES/iso_639-2.mo 29533 +usr/share/locale/ms/LC_MESSAGES/iso_639-2.mo 29532 +usr/lib/locale/mt_MT/LC_MESSAGES/SYS_LC_MESSAGES 29531 +usr/share/locale/mt/LC_MESSAGES/iso_639-2.mo 29530 +usr/lib/locale/nan_TW/LC_MESSAGES/SYS_LC_MESSAGES 29529 +etc/sane.d/canon.conf 29528 +usr/lib/locale/li_NL/LC_MESSAGES/SYS_LC_MESSAGES 29527 +usr/lib/x86_64-linux-gnu/sane/libsane-bh.so.1.0.25 29526 +usr/lib/locale/nhn_MX/LC_MESSAGES/SYS_LC_MESSAGES 29525 +usr/lib/locale/niu_NU/LC_MESSAGES/SYS_LC_MESSAGES 29524 +etc/sane.d/bh.conf 29523 +usr/lib/locale/nso_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29522 +usr/share/locale/nso/LC_MESSAGES/iso_639-2.mo 29521 +usr/lib/locale/oc_FR/LC_MESSAGES/SYS_LC_MESSAGES 29520 +usr/lib/x86_64-linux-gnu/sane/libsane-as6e.so.1.0.25 29519 +usr/share/locale/oc/LC_MESSAGES/iso_639-2.mo 29518 +usr/lib/locale/or_IN/LC_MESSAGES/SYS_LC_MESSAGES 29517 +usr/share/locale/or/LC_MESSAGES/iso_639-2.mo 29516 +usr/lib/x86_64-linux-gnu/sane/libsane-artec_eplus48u.so.1.0.25 29515 +usr/lib/locale/os_RU/LC_MESSAGES/SYS_LC_MESSAGES 29514 +usr/lib/locale/ps_AF/LC_MESSAGES/SYS_LC_MESSAGES 29513 +usr/share/locale/ps/LC_MESSAGES/iso_639-2.mo 29512 +usr/lib/locale/quz_PE/LC_MESSAGES/SYS_LC_MESSAGES 29511 +usr/lib/locale/rw_RW/LC_MESSAGES/SYS_LC_MESSAGES 29510 +usr/share/locale/rw/LC_MESSAGES/iso_639-2.mo 29509 +usr/lib/locale/sa_IN/LC_MESSAGES/SYS_LC_MESSAGES 29508 +usr/lib/locale/sat_IN/LC_MESSAGES/SYS_LC_MESSAGES 29507 +usr/lib/locale/sc_IT/LC_MESSAGES/SYS_LC_MESSAGES 29506 +usr/lib/locale/ar_AE.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29505 +usr/lib/locale/sgs_LT/LC_MESSAGES/SYS_LC_MESSAGES 29504 +usr/lib/locale/en_CA.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29503 +usr/lib/locale/so_KE/LC_MESSAGES/SYS_LC_MESSAGES 29502 +usr/lib/locale/ss_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29501 +usr/lib/locale/sw_KE/LC_MESSAGES/SYS_LC_MESSAGES 29500 +usr/lib/locale/tg_TJ/LC_MESSAGES/SYS_LC_MESSAGES 29499 +usr/share/locale/ti/LC_MESSAGES/iso_639-2.mo 29498 +usr/share/locale/tig/LC_MESSAGES/iso_639-2.mo 29497 +usr/lib/locale/tk_TM/LC_MESSAGES/SYS_LC_MESSAGES 29496 +usr/lib/locale/tn_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29495 +usr/lib/locale/tt_RU/LC_MESSAGES/SYS_LC_MESSAGES 29494 +usr/share/locale/tt/LC_MESSAGES/iso_639-2.mo 29493 +usr/lib/locale/unm_US/LC_MESSAGES/SYS_LC_MESSAGES 29492 +usr/lib/locale/ur_IN/LC_MESSAGES/SYS_LC_MESSAGES 29491 +usr/lib/locale/uz_UZ/LC_MESSAGES/SYS_LC_MESSAGES 29490 +usr/lib/locale/ve_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29489 +usr/share/locale/ve/LC_MESSAGES/iso_639-2.mo 29488 +usr/lib/locale/wa_BE/LC_MESSAGES/SYS_LC_MESSAGES 29487 +usr/share/locale/wa/LC_MESSAGES/iso_639-2.mo 29486 +usr/lib/locale/wae_CH/LC_MESSAGES/SYS_LC_MESSAGES 29485 +etc/sane.d/artec_eplus48u.conf 29484 +usr/lib/locale/wo_SN/LC_MESSAGES/SYS_LC_MESSAGES 29483 +usr/lib/x86_64-linux-gnu/sane/libsane-artec.so.1.0.25 29482 +usr/lib/locale/xh_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29481 +usr/share/locale/xh/LC_MESSAGES/iso_639-2.mo 29480 +usr/lib/locale/yi_US/LC_MESSAGES/SYS_LC_MESSAGES 29479 +etc/sane.d/artec.conf 29478 +usr/lib/locale/yo_NG/LC_MESSAGES/SYS_LC_MESSAGES 29477 +usr/lib/locale/yue_HK/LC_MESSAGES/SYS_LC_MESSAGES 29476 +usr/lib/x86_64-linux-gnu/sane/libsane-avision.so.1.0.25 29475 +usr/lib/locale/zu_ZA/LC_MESSAGES/SYS_LC_MESSAGES 29474 +usr/share/locale/zu/LC_MESSAGES/iso_639-2.mo 29473 +usr/lib/locale/aa_DJ.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29472 +usr/share/locale/af/LC_MESSAGES/iso_3166-1.mo 29471 +usr/share/locale/sq/LC_MESSAGES/iso_3166-1.mo 29470 +usr/lib/locale/sq_AL.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29469 +usr/share/locale/hy/LC_MESSAGES/iso_3166-1.mo 29468 +usr/share/locale/ast/LC_MESSAGES/iso_3166-1.mo 29467 +usr/share/locale/az/LC_MESSAGES/iso_3166-1.mo 29466 +usr/share/locale/id/LC_MESSAGES/iso_3166-1.mo 29465 +usr/share/locale/ms/LC_MESSAGES/iso_3166-1.mo 29464 +usr/share/locale/byn/LC_MESSAGES/iso_3166-1.mo 29463 +usr/share/locale/bs/LC_MESSAGES/iso_3166-1.mo 29462 +usr/share/locale/br/LC_MESSAGES/iso_3166-1.mo 29461 +usr/share/locale/ca/LC_MESSAGES/iso_3166-1.mo 29460 +usr/lib/locale/ca_AD/LC_MESSAGES/SYS_LC_MESSAGES 29459 +etc/sane.d/avision.conf 29458 +usr/share/locale/km/LC_MESSAGES/iso_3166-1.mo 29457 +usr/share/locale/cy/LC_MESSAGES/iso_3166-1.mo 29456 +usr/share/locale/da/LC_MESSAGES/iso_3166-1.mo 29455 +usr/share/locale/de/LC_MESSAGES/iso_3166-1.mo 29454 +usr/share/locale/dz/LC_MESSAGES/iso_3166-1.mo 29453 +usr/share/locale/et/LC_MESSAGES/iso_3166-1.mo 29452 +usr/lib/locale/en_CA/LC_MESSAGES/SYS_LC_MESSAGES 29451 +usr/share/locale/es/LC_MESSAGES/iso_3166-1.mo 29450 +usr/lib/locale/ca_AD.utf8/LC_MESSAGES/SYS_LC_MESSAGES 29449 +usr/share/locale/eu/LC_MESSAGES/iso_3166-1.mo 29448 +usr/share/locale/fo/LC_MESSAGES/iso_3166-1.mo 29447 +usr/share/locale/fr/LC_MESSAGES/iso_3166-1.mo 29446 +usr/lib/locale/fr_BE/LC_MESSAGES/SYS_LC_MESSAGES 29445 +usr/lib/locale/fr_CH/LC_MESSAGES/SYS_LC_MESSAGES 29444 +usr/share/locale/ga/LC_MESSAGES/iso_3166-1.mo 29443 +usr/share/locale/gl/LC_MESSAGES/iso_3166-1.mo 29442 +usr/share/locale/ka/LC_MESSAGES/iso_3166-1.mo 29441 +usr/share/locale/hr/LC_MESSAGES/iso_3166-1.mo 29440 +usr/share/locale/rw/LC_MESSAGES/iso_3166-1.mo 29439 +usr/share/locale/ia/LC_MESSAGES/iso_3166-1.mo 29438 +usr/share/locale/zu/LC_MESSAGES/iso_3166-1.mo 29437 +usr/share/locale/xh/LC_MESSAGES/iso_3166-1.mo 29436 +usr/share/locale/it/LC_MESSAGES/iso_3166-1.mo 29435 +usr/lib/locale/it_CH/LC_MESSAGES/SYS_LC_MESSAGES 29434 +usr/share/locale/kk/LC_MESSAGES/iso_3166-1.mo 29433 +usr/share/locale/ku/LC_MESSAGES/iso_3166-1.mo 29432 +usr/share/locale/lv/LC_MESSAGES/iso_3166-1.mo 29431 +usr/share/locale/lt/LC_MESSAGES/iso_3166-1.mo 29430 +usr/share/locale/hu/LC_MESSAGES/iso_3166-1.mo 29429 +usr/share/locale/mt/LC_MESSAGES/iso_3166-1.mo 29428 +usr/share/locale/nl/LC_MESSAGES/iso_3166-1.mo 29427 +usr/lib/x86_64-linux-gnu/sane/libsane-apple.so.1.0.25 29426 +usr/share/locale/ne/LC_MESSAGES/iso_3166-1.mo 29425 +usr/share/locale/nn/LC_MESSAGES/iso_3166-1.mo 29424 +usr/share/locale/nb/LC_MESSAGES/iso_3166-1.mo 29423 +usr/share/locale/oc/LC_MESSAGES/iso_3166-1.mo 29422 +usr/share/locale/nso/LC_MESSAGES/iso_3166-1.mo 29421 +usr/share/locale/pl/LC_MESSAGES/iso_3166-1.mo 29420 +usr/share/locale/pt_BR/LC_MESSAGES/iso_639-2.mo 29419 +usr/share/locale/pt_BR/LC_MESSAGES/iso_3166-1.mo 29418 +usr/share/locale/pt/LC_MESSAGES/iso_3166-1.mo 29417 +etc/sane.d/apple.conf 29416 +usr/lib/x86_64-linux-gnu/sane/libsane-agfafocus.so.1.0.25 29415 +usr/share/locale/ps/LC_MESSAGES/iso_3166-1.mo 29414 +usr/share/locale/mi/LC_MESSAGES/iso_3166-1.mo 29413 +usr/share/locale/ro/LC_MESSAGES/iso_3166-1.mo 29412 +etc/sane.d/agfafocus.conf 29411 +usr/lib/x86_64-linux-gnu/sane/libsane-abaton.so.1.0.25 29410 +etc/sane.d/abaton.conf 29409 +usr/lib/x86_64-linux-gnu/sane/libsane-net.so.1.0.25 29408 +usr/share/locale/si/LC_MESSAGES/iso_3166-1.mo 29407 +usr/share/locale/sk/LC_MESSAGES/iso_3166-1.mo 29406 +usr/share/locale/sl/LC_MESSAGES/iso_3166-1.mo 29405 +usr/lib/locale/so_DJ/LC_MESSAGES/SYS_LC_MESSAGES 29404 +usr/share/locale/so/LC_MESSAGES/iso_3166-1.mo 29403 +etc/sane.d/net.conf 29402 +usr/lib/x86_64-linux-gnu/sane/libsane-hpaio.so.1.0.0 29401 +usr/share/locale/fi/LC_MESSAGES/iso_3166-1.mo 29400 +usr/share/locale/sv/LC_MESSAGES/iso_3166-1.mo 29399 +usr/share/locale/sw/LC_MESSAGES/iso_3166-1.mo 29398 +usr/share/locale/tl/LC_MESSAGES/iso_3166-1.mo 29397 +usr/share/locale/crh/LC_MESSAGES/iso_3166-1.mo 29396 +usr/share/locale/vi/LC_MESSAGES/iso_3166-1.mo 29395 +usr/share/locale/tk/LC_MESSAGES/iso_3166-1.mo 29394 +usr/share/locale/tr/LC_MESSAGES/iso_3166-1.mo 29393 +usr/share/locale/ug/LC_MESSAGES/iso_3166-1.mo 29392 +usr/lib/locale/ur_PK/LC_MESSAGES/SYS_LC_MESSAGES 29391 +usr/share/locale/ve/LC_MESSAGES/iso_3166-1.mo 29390 +usr/lib/x86_64-linux-gnu/libhpip.so.0.0.1 29389 +usr/share/locale/wa/LC_MESSAGES/iso_3166-1.mo 29388 +usr/lib/x86_64-linux-gnu/libhpmud.so.0.0.6 29387 +usr/lib/x86_64-linux-gnu/libcups.so.2 29386 +usr/share/locale/wal/LC_MESSAGES/iso_3166-1.mo 29385 +usr/share/locale/wo/LC_MESSAGES/iso_3166-1.mo 29384 +usr/share/locale/is/LC_MESSAGES/iso_3166-1.mo 29383 +usr/share/locale/cs/LC_MESSAGES/iso_3166-1.mo 29382 +usr/share/locale/el/LC_MESSAGES/iso_3166-1.mo 29381 +usr/share/locale/be/LC_MESSAGES/iso_3166-1.mo 29380 +usr/lib/x86_64-linux-gnu/libhpdiscovery.so.0.0.1 29379 +usr/lib/x86_64-linux-gnu/libnetsnmp.so.30.0.3 29378 +usr/share/locale/bg/LC_MESSAGES/iso_3166-1.mo 29377 +usr/share/locale/mk/LC_MESSAGES/iso_3166-1.mo 29376 +usr/share/locale/mn/LC_MESSAGES/iso_3166-1.mo 29375 +usr/share/locale/ru/LC_MESSAGES/iso_3166-1.mo 29374 +usr/lib/locale/ru_UA/LC_MESSAGES/SYS_LC_MESSAGES 29373 +usr/share/locale/sr/LC_MESSAGES/iso_3166-1.mo 29372 +usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2 29371 +usr/share/locale/tt/LC_MESSAGES/iso_3166-1.mo 29370 +usr/share/locale/uk/LC_MESSAGES/iso_3166-1.mo 29369 +usr/share/locale/he/LC_MESSAGES/iso_3166-1.mo 29368 +usr/share/locale/ar/LC_MESSAGES/iso_3166-1.mo 29367 +usr/share/locale/fa/LC_MESSAGES/iso_3166-1.mo 29366 +usr/share/locale/mr/LC_MESSAGES/iso_3166-1.mo 29365 +usr/share/locale/hi/LC_MESSAGES/iso_3166-1.mo 29364 +usr/share/locale/as/LC_MESSAGES/iso_3166-1.mo 29363 +usr/share/locale/bn/LC_MESSAGES/iso_3166-1.mo 29362 +usr/share/locale/bn_IN/LC_MESSAGES/iso_3166-1.mo 29361 +usr/share/locale/pa/LC_MESSAGES/iso_3166-1.mo 29360 +usr/lib/locale/pa_PK/LC_MESSAGES/SYS_LC_MESSAGES 29359 +usr/share/locale/gu/LC_MESSAGES/iso_3166-1.mo 29358 +usr/share/locale/or/LC_MESSAGES/iso_3166-1.mo 29357 +usr/share/locale/ta/LC_MESSAGES/iso_3166-1.mo 29356 +usr/share/locale/te/LC_MESSAGES/iso_3166-1.mo 29355 +usr/share/locale/kn/LC_MESSAGES/iso_3166-1.mo 29354 +usr/share/locale/ml/LC_MESSAGES/iso_3166-1.mo 29353 +usr/share/locale/th/LC_MESSAGES/iso_3166-1.mo 29352 +usr/share/locale/tig/LC_MESSAGES/iso_3166-1.mo 29351 +usr/share/locale/ti/LC_MESSAGES/iso_3166-1.mo 29350 +usr/share/locale/am/LC_MESSAGES/iso_3166-1.mo 29349 +usr/share/locale/gez/LC_MESSAGES/iso_3166-1.mo 29348 +usr/share/locale/zh_CN/LC_MESSAGES/iso_3166-1.mo 29347 +usr/lib/locale/zh_HK/LC_MESSAGES/SYS_LC_MESSAGES 29346 +usr/share/locale/zh_HK/LC_MESSAGES/iso_639-2.mo 29345 +usr/share/locale/zh_HK/LC_MESSAGES/iso_3166-1.mo 29344 +usr/lib/locale/zh_SG/LC_MESSAGES/SYS_LC_MESSAGES 29343 +usr/lib/locale/zh_TW/LC_MESSAGES/SYS_LC_MESSAGES 29342 +usr/share/locale/zh_TW/LC_MESSAGES/iso_639-2.mo 29341 +usr/share/locale/zh_TW/LC_MESSAGES/iso_3166-1.mo 29340 +usr/share/zoneinfo/Africa/Abidjan 29339 +usr/share/zoneinfo/Africa/Accra 29338 +usr/share/zoneinfo/Africa/Addis_Ababa 29337 +usr/share/zoneinfo/Africa/Algiers 29336 +usr/share/zoneinfo/Africa/Bangui 29335 +usr/share/zoneinfo/Africa/Bissau 29334 +usr/share/zoneinfo/Africa/Blantyre 29333 +usr/share/zoneinfo/Egypt 29332 +usr/share/zoneinfo/Africa/Casablanca 29331 +usr/share/zoneinfo/Africa/Ceuta 29330 +usr/share/zoneinfo/Africa/El_Aaiun 29329 +usr/share/zoneinfo/Africa/Johannesburg 29328 +usr/share/zoneinfo/Africa/Juba 29327 +usr/share/zoneinfo/Africa/Khartoum 29326 +usr/share/zoneinfo/Africa/Monrovia 29325 +usr/share/zoneinfo/Africa/Ndjamena 29324 +usr/share/zoneinfo/Africa/Sao_Tome 29323 +usr/share/zoneinfo/Libya 29322 +usr/share/zoneinfo/Africa/Tunis 29321 +usr/share/zoneinfo/Africa/Windhoek 29320 +usr/share/zoneinfo/America/Adak 29319 +usr/share/zoneinfo/America/Anchorage 29318 +usr/share/zoneinfo/America/Anguilla 29317 +usr/share/zoneinfo/America/Araguaina 29316 +usr/share/zoneinfo/America/Buenos_Aires 29315 +usr/share/zoneinfo/America/Catamarca 29314 +usr/share/zoneinfo/America/Cordoba 29313 +usr/share/zoneinfo/America/Jujuy 29312 +usr/share/zoneinfo/America/Argentina/La_Rioja 29311 +usr/share/zoneinfo/America/Mendoza 29310 +usr/share/zoneinfo/America/Argentina/Rio_Gallegos 29309 +usr/share/zoneinfo/America/Argentina/Salta 29308 +usr/share/zoneinfo/America/Argentina/San_Juan 29307 +usr/share/zoneinfo/America/Argentina/San_Luis 29306 +usr/share/zoneinfo/America/Argentina/Tucuman 29305 +usr/share/zoneinfo/America/Argentina/Ushuaia 29304 +usr/share/zoneinfo/America/Aruba 29303 +usr/share/zoneinfo/America/Asuncion 29302 +usr/share/zoneinfo/America/Atikokan 29301 +usr/share/zoneinfo/America/Bahia 29300 +usr/share/zoneinfo/America/Bahia_Banderas 29299 +usr/share/zoneinfo/America/Barbados 29298 +usr/share/zoneinfo/America/Belem 29297 +usr/share/zoneinfo/America/Belize 29296 +usr/share/zoneinfo/America/Blanc-Sablon 29295 +usr/share/zoneinfo/America/Boa_Vista 29294 +usr/share/zoneinfo/America/Bogota 29293 +usr/share/zoneinfo/America/Boise 29292 +usr/share/zoneinfo/America/Cambridge_Bay 29291 +usr/share/zoneinfo/America/Campo_Grande 29290 +usr/share/zoneinfo/America/Cancun 29289 +usr/share/zoneinfo/America/Caracas 29288 +usr/share/zoneinfo/America/Cayenne 29287 +usr/share/zoneinfo/America/Cayman 29286 +usr/share/zoneinfo/America/Chicago 29285 +usr/share/zoneinfo/America/Chihuahua 29284 +usr/share/zoneinfo/America/Costa_Rica 29283 +usr/share/zoneinfo/America/Creston 29282 +usr/share/zoneinfo/America/Cuiaba 29281 +usr/share/zoneinfo/America/Danmarkshavn 29280 +usr/share/zoneinfo/America/Dawson 29279 +usr/share/zoneinfo/America/Dawson_Creek 29278 +usr/share/zoneinfo/Navajo 29277 +usr/share/zoneinfo/America/Detroit 29276 +usr/share/zoneinfo/America/Edmonton 29275 +usr/share/zoneinfo/America/Eirunepe 29274 +usr/share/zoneinfo/America/El_Salvador 29273 +usr/share/zoneinfo/America/Ensenada 29272 +usr/share/zoneinfo/America/Fort_Nelson 29271 +usr/share/zoneinfo/America/Fort_Wayne 29270 +usr/share/zoneinfo/America/Fortaleza 29269 +usr/share/zoneinfo/America/Glace_Bay 29268 +usr/share/zoneinfo/America/Godthab 29267 +usr/share/zoneinfo/America/Goose_Bay 29266 +usr/share/zoneinfo/America/Grand_Turk 29265 +usr/share/zoneinfo/America/Guatemala 29264 +usr/share/zoneinfo/America/Guayaquil 29263 +usr/share/zoneinfo/America/Guyana 29262 +usr/share/zoneinfo/America/Halifax 29261 +usr/share/zoneinfo/Cuba 29260 +usr/share/zoneinfo/America/Hermosillo 29259 +usr/share/zoneinfo/America/Knox_IN 29258 +usr/share/zoneinfo/America/Indiana/Marengo 29257 +usr/share/zoneinfo/America/Indiana/Petersburg 29256 +usr/share/zoneinfo/America/Indiana/Tell_City 29255 +usr/share/zoneinfo/America/Indiana/Vevay 29254 +usr/share/zoneinfo/America/Indiana/Vincennes 29253 +usr/share/zoneinfo/America/Indiana/Winamac 29252 +usr/share/zoneinfo/America/Inuvik 29251 +usr/share/zoneinfo/America/Iqaluit 29250 +usr/share/zoneinfo/Jamaica 29249 +usr/share/zoneinfo/America/Juneau 29248 +usr/share/zoneinfo/America/Louisville 29247 +usr/share/zoneinfo/America/Kentucky/Monticello 29246 +usr/share/zoneinfo/America/La_Paz 29245 +usr/share/zoneinfo/America/Lima 29244 +usr/share/zoneinfo/America/Los_Angeles 29243 +usr/share/zoneinfo/America/Maceio 29242 +usr/share/zoneinfo/America/Managua 29241 +usr/share/zoneinfo/America/Manaus 29240 +usr/share/zoneinfo/America/Martinique 29239 +usr/share/zoneinfo/America/Matamoros 29238 +usr/share/zoneinfo/America/Mazatlan 29237 +usr/share/zoneinfo/America/Menominee 29236 +usr/share/zoneinfo/America/Merida 29235 +usr/share/zoneinfo/America/Metlakatla 29234 +usr/share/zoneinfo/America/Mexico_City 29233 +usr/share/zoneinfo/America/Miquelon 29232 +usr/share/zoneinfo/America/Moncton 29231 +usr/share/zoneinfo/America/Monterrey 29230 +usr/share/zoneinfo/America/Montevideo 29229 +usr/share/zoneinfo/America/Montreal 29228 +usr/share/zoneinfo/America/Nassau 29227 +usr/share/zoneinfo/posixrules 29226 +usr/share/zoneinfo/America/Nipigon 29225 +usr/share/zoneinfo/America/Nome 29224 +usr/share/zoneinfo/America/Noronha 29223 +usr/share/zoneinfo/America/North_Dakota/Beulah 29222 +usr/share/zoneinfo/America/North_Dakota/Center 29221 +usr/share/zoneinfo/America/North_Dakota/New_Salem 29220 +usr/share/zoneinfo/America/Ojinaga 29219 +usr/share/zoneinfo/America/Pangnirtung 29218 +usr/share/zoneinfo/America/Paramaribo 29217 +usr/share/zoneinfo/America/Phoenix 29216 +usr/share/zoneinfo/America/Port-au-Prince 29215 +usr/share/zoneinfo/America/Porto_Acre 29214 +usr/share/zoneinfo/America/Porto_Velho 29213 +usr/share/zoneinfo/America/Puerto_Rico 29212 +usr/share/zoneinfo/America/Rainy_River 29211 +usr/share/zoneinfo/America/Rankin_Inlet 29210 +usr/share/zoneinfo/America/Recife 29209 +usr/share/zoneinfo/America/Regina 29208 +usr/share/zoneinfo/America/Resolute 29207 +usr/share/zoneinfo/America/Santarem 29206 +usr/share/zoneinfo/America/Santiago 29205 +usr/share/zoneinfo/America/Santo_Domingo 29204 +usr/share/zoneinfo/America/Sao_Paulo 29203 +usr/share/zoneinfo/America/Scoresbysund 29202 +usr/share/zoneinfo/America/Sitka 29201 +usr/share/zoneinfo/America/St_Johns 29200 +usr/share/zoneinfo/America/Swift_Current 29199 +usr/share/zoneinfo/America/Tegucigalpa 29198 +usr/share/zoneinfo/America/Thule 29197 +usr/share/zoneinfo/America/Thunder_Bay 29196 +usr/share/zoneinfo/America/Vancouver 29195 +usr/share/zoneinfo/America/Whitehorse 29194 +usr/share/zoneinfo/America/Winnipeg 29193 +usr/share/zoneinfo/America/Yakutat 29192 +usr/share/zoneinfo/America/Yellowknife 29191 +usr/share/zoneinfo/Antarctica/Casey 29190 +usr/share/zoneinfo/Antarctica/Davis 29189 +usr/share/zoneinfo/Antarctica/DumontDUrville 29188 +usr/share/zoneinfo/Antarctica/Macquarie 29187 +usr/share/zoneinfo/Antarctica/Mawson 29186 +usr/share/zoneinfo/NZ 29185 +usr/share/zoneinfo/Antarctica/Palmer 29184 +usr/share/zoneinfo/Antarctica/Rothera 29183 +usr/share/zoneinfo/Antarctica/Syowa 29182 +usr/share/zoneinfo/Antarctica/Troll 29181 +usr/share/zoneinfo/Antarctica/Vostok 29180 +usr/share/zoneinfo/Arctic/Longyearbyen 29179 +usr/share/zoneinfo/Asia/Aden 29178 +usr/share/zoneinfo/Asia/Almaty 29177 +usr/share/zoneinfo/Asia/Amman 29176 +usr/share/zoneinfo/Asia/Anadyr 29175 +usr/share/zoneinfo/Asia/Aqtau 29174 +usr/share/zoneinfo/Asia/Aqtobe 29173 +usr/share/zoneinfo/Asia/Ashgabat 29172 +usr/share/zoneinfo/Asia/Baghdad 29171 +usr/share/zoneinfo/Asia/Bahrain 29170 +usr/share/zoneinfo/Asia/Baku 29169 +usr/share/zoneinfo/Asia/Bangkok 29168 +usr/share/zoneinfo/Asia/Barnaul 29167 +usr/share/zoneinfo/Asia/Beirut 29166 +usr/share/zoneinfo/Asia/Bishkek 29165 +usr/share/zoneinfo/Asia/Brunei 29164 +usr/share/zoneinfo/Asia/Calcutta 29163 +usr/share/zoneinfo/Asia/Chita 29162 +usr/share/zoneinfo/Asia/Choibalsan 29161 +usr/share/zoneinfo/PRC 29160 +usr/share/zoneinfo/Asia/Colombo 29159 +usr/share/zoneinfo/Asia/Dacca 29158 +usr/share/zoneinfo/Asia/Damascus 29157 +usr/share/zoneinfo/Asia/Dili 29156 +usr/share/zoneinfo/Asia/Dubai 29155 +usr/share/zoneinfo/Asia/Dushanbe 29154 +usr/share/zoneinfo/Asia/Gaza 29153 +usr/share/zoneinfo/Asia/Hebron 29152 +usr/share/zoneinfo/Asia/Ho_Chi_Minh 29151 +usr/share/zoneinfo/Hongkong 29150 +usr/share/zoneinfo/Asia/Hovd 29149 +usr/share/zoneinfo/Asia/Irkutsk 29148 +usr/share/zoneinfo/Turkey 29147 +usr/share/zoneinfo/Asia/Jakarta 29146 +usr/share/zoneinfo/Asia/Jayapura 29145 +usr/share/zoneinfo/Israel 29144 +usr/share/zoneinfo/Asia/Kabul 29143 +usr/share/zoneinfo/Asia/Kamchatka 29142 +usr/share/zoneinfo/Asia/Karachi 29141 +usr/share/zoneinfo/Asia/Kashgar 29140 +usr/share/zoneinfo/Asia/Kathmandu 29139 +usr/share/zoneinfo/Asia/Khandyga 29138 +usr/share/zoneinfo/Asia/Krasnoyarsk 29137 +usr/share/zoneinfo/Asia/Kuala_Lumpur 29136 +usr/share/zoneinfo/Asia/Kuching 29135 +usr/share/zoneinfo/Asia/Macao 29134 +usr/share/zoneinfo/Asia/Magadan 29133 +usr/share/zoneinfo/Asia/Makassar 29132 +usr/share/zoneinfo/Asia/Manila 29131 +usr/share/zoneinfo/Asia/Nicosia 29130 +usr/share/zoneinfo/Asia/Novokuznetsk 29129 +usr/share/zoneinfo/Asia/Novosibirsk 29128 +usr/share/zoneinfo/Asia/Omsk 29127 +usr/share/zoneinfo/Asia/Oral 29126 +usr/share/zoneinfo/Asia/Pontianak 29125 +usr/share/zoneinfo/Asia/Pyongyang 29124 +usr/share/zoneinfo/Asia/Qyzylorda 29123 +usr/share/zoneinfo/Asia/Rangoon 29122 +usr/share/zoneinfo/Asia/Sakhalin 29121 +usr/share/zoneinfo/Asia/Samarkand 29120 +usr/share/zoneinfo/ROK 29119 +usr/share/zoneinfo/Singapore 29118 +usr/share/zoneinfo/Asia/Srednekolymsk 29117 +usr/share/zoneinfo/ROC 29116 +usr/share/zoneinfo/Asia/Tashkent 29115 +usr/share/zoneinfo/Asia/Tbilisi 29114 +usr/share/zoneinfo/Iran 29113 +usr/share/zoneinfo/Asia/Thimbu 29112 +usr/share/zoneinfo/Japan 29111 +usr/share/zoneinfo/Asia/Tomsk 29110 +usr/share/zoneinfo/Asia/Ulaanbaatar 29109 +usr/share/zoneinfo/Asia/Ust-Nera 29108 +usr/share/zoneinfo/Asia/Vladivostok 29107 +usr/share/zoneinfo/Asia/Yakutsk 29106 +usr/share/zoneinfo/Asia/Yekaterinburg 29105 +usr/share/zoneinfo/Asia/Yerevan 29104 +usr/share/zoneinfo/Atlantic/Azores 29103 +usr/share/zoneinfo/Atlantic/Bermuda 29102 +usr/share/zoneinfo/Atlantic/Canary 29101 +usr/share/zoneinfo/Atlantic/Cape_Verde 29100 +usr/share/zoneinfo/Atlantic/Faeroe 29099 +usr/share/zoneinfo/Atlantic/Madeira 29098 +usr/share/zoneinfo/Iceland 29097 +usr/share/zoneinfo/Atlantic/South_Georgia 29096 +usr/share/zoneinfo/Atlantic/Stanley 29095 +usr/share/zoneinfo/Australia/ACT 29094 +usr/share/zoneinfo/Australia/Adelaide 29093 +usr/share/zoneinfo/Australia/Brisbane 29092 +usr/share/zoneinfo/Australia/Broken_Hill 29091 +usr/share/zoneinfo/Australia/Currie 29090 +usr/share/zoneinfo/Australia/Darwin 29089 +usr/share/zoneinfo/Australia/Eucla 29088 +usr/share/zoneinfo/Australia/Hobart 29087 +usr/share/zoneinfo/Australia/LHI 29086 +usr/share/zoneinfo/Australia/Lindeman 29085 +usr/share/zoneinfo/Australia/Melbourne 29084 +usr/share/zoneinfo/Australia/Perth 29083 +usr/share/zoneinfo/CET 29082 +usr/share/zoneinfo/CST6CDT 29081 +usr/share/zoneinfo/Chile/EasterIsland 29080 +usr/share/zoneinfo/EET 29079 +usr/share/zoneinfo/EST 29078 +usr/share/zoneinfo/EST5EDT 29077 +usr/share/zoneinfo/Eire 29076 +usr/share/zoneinfo/GMT 29075 +usr/share/zoneinfo/Etc/GMT+1 29074 +usr/share/zoneinfo/Etc/GMT+10 29073 +usr/share/zoneinfo/Etc/GMT+11 29072 +usr/share/zoneinfo/Etc/GMT+12 29071 +usr/share/zoneinfo/Etc/GMT+2 29070 +usr/share/zoneinfo/Etc/GMT+3 29069 +usr/share/zoneinfo/Etc/GMT+4 29068 +usr/share/zoneinfo/Etc/GMT+5 29067 +usr/share/zoneinfo/Etc/GMT+6 29066 +usr/share/zoneinfo/Etc/GMT+7 29065 +usr/share/zoneinfo/Etc/GMT+8 29064 +usr/share/zoneinfo/Etc/GMT+9 29063 +usr/share/zoneinfo/Etc/GMT-1 29062 +usr/share/zoneinfo/Etc/GMT-10 29061 +usr/share/zoneinfo/Etc/GMT-11 29060 +usr/share/zoneinfo/Etc/GMT-12 29059 +usr/share/zoneinfo/Etc/GMT-13 29058 +usr/share/zoneinfo/Etc/GMT-14 29057 +usr/share/zoneinfo/Etc/GMT-2 29056 +usr/share/zoneinfo/Etc/GMT-3 29055 +usr/share/zoneinfo/Etc/GMT-4 29054 +usr/share/zoneinfo/Etc/GMT-5 29053 +usr/share/zoneinfo/Etc/GMT-6 29052 +usr/share/zoneinfo/Etc/GMT-7 29051 +usr/share/zoneinfo/Etc/GMT-8 29050 +usr/share/zoneinfo/Etc/GMT-9 29049 +usr/share/zoneinfo/Europe/Amsterdam 29048 +usr/share/zoneinfo/Europe/Andorra 29047 +usr/share/zoneinfo/Europe/Astrakhan 29046 +usr/share/zoneinfo/Europe/Athens 29045 +usr/share/zoneinfo/GB 29044 +usr/share/zoneinfo/Europe/Belgrade 29043 +usr/share/zoneinfo/Europe/Berlin 29042 +usr/share/zoneinfo/Europe/Bratislava 29041 +usr/share/zoneinfo/Europe/Brussels 29040 +usr/share/zoneinfo/Europe/Bucharest 29039 +usr/share/zoneinfo/Europe/Budapest 29038 +usr/share/zoneinfo/Europe/Busingen 29037 +usr/share/zoneinfo/Europe/Chisinau 29036 +usr/share/zoneinfo/Europe/Copenhagen 29035 +usr/share/zoneinfo/Europe/Gibraltar 29034 +usr/share/zoneinfo/Europe/Helsinki 29033 +usr/share/zoneinfo/Europe/Kaliningrad 29032 +usr/share/zoneinfo/Europe/Kiev 29031 +usr/share/zoneinfo/Europe/Kirov 29030 +usr/share/zoneinfo/Portugal 29029 +usr/share/zoneinfo/Europe/Luxembourg 29028 +usr/share/zoneinfo/Europe/Madrid 29027 +usr/share/zoneinfo/Europe/Malta 29026 +usr/share/zoneinfo/Europe/Minsk 29025 +usr/share/zoneinfo/Europe/Monaco 29024 +usr/share/zoneinfo/W-SU 29023 +usr/share/zoneinfo/Europe/Paris 29022 +usr/share/zoneinfo/Europe/Riga 29021 +usr/share/zoneinfo/Europe/Rome 29020 +usr/share/zoneinfo/Europe/Samara 29019 +usr/share/zoneinfo/Europe/Simferopol 29018 +usr/share/zoneinfo/Europe/Sofia 29017 +usr/share/zoneinfo/Europe/Stockholm 29016 +usr/share/zoneinfo/Europe/Tallinn 29015 +usr/share/zoneinfo/Europe/Tirane 29014 +usr/share/zoneinfo/Europe/Ulyanovsk 29013 +usr/share/zoneinfo/Europe/Uzhgorod 29012 +usr/share/zoneinfo/Europe/Vienna 29011 +usr/share/zoneinfo/Europe/Vilnius 29010 +usr/share/zoneinfo/Europe/Volgograd 29009 +usr/share/zoneinfo/Poland 29008 +usr/share/zoneinfo/Europe/Zaporozhye 29007 +usr/share/zoneinfo/HST 29006 +usr/share/zoneinfo/Indian/Chagos 29005 +usr/share/zoneinfo/Indian/Christmas 29004 +usr/share/zoneinfo/Indian/Cocos 29003 +usr/share/zoneinfo/Indian/Kerguelen 29002 +usr/share/zoneinfo/Indian/Mahe 29001 +usr/share/zoneinfo/Indian/Maldives 29000 +usr/share/zoneinfo/Indian/Mauritius 28999 +usr/share/zoneinfo/Indian/Reunion 28998 +usr/share/zoneinfo/Kwajalein 28997 +usr/share/zoneinfo/MET 28996 +usr/share/zoneinfo/MST 28995 +usr/share/zoneinfo/MST7MDT 28994 +usr/share/zoneinfo/NZ-CHAT 28993 +usr/share/zoneinfo/PST8PDT 28992 +usr/share/zoneinfo/Pacific/Apia 28991 +usr/share/zoneinfo/Pacific/Bougainville 28990 +usr/share/zoneinfo/Pacific/Chuuk 28989 +usr/share/zoneinfo/Pacific/Efate 28988 +usr/share/zoneinfo/Pacific/Enderbury 28987 +usr/share/zoneinfo/Pacific/Fakaofo 28986 +usr/share/zoneinfo/Pacific/Fiji 28985 +usr/share/zoneinfo/Pacific/Funafuti 28984 +usr/share/zoneinfo/Pacific/Galapagos 28983 +usr/share/zoneinfo/Pacific/Gambier 28982 +usr/share/zoneinfo/Pacific/Guadalcanal 28981 +usr/share/zoneinfo/Pacific/Guam 28980 +usr/share/zoneinfo/Pacific/Honolulu 28979 +usr/share/zoneinfo/Pacific/Kiritimati 28978 +usr/share/zoneinfo/Pacific/Kosrae 28977 +usr/share/zoneinfo/Pacific/Majuro 28976 +usr/share/zoneinfo/Pacific/Marquesas 28975 +usr/share/zoneinfo/Pacific/Midway 28974 +usr/share/zoneinfo/Pacific/Nauru 28973 +usr/share/zoneinfo/Pacific/Niue 28972 +usr/share/zoneinfo/Pacific/Norfolk 28971 +usr/share/zoneinfo/Pacific/Noumea 28970 +usr/share/zoneinfo/Pacific/Palau 28969 +usr/share/zoneinfo/Pacific/Pitcairn 28968 +usr/share/zoneinfo/Pacific/Pohnpei 28967 +usr/share/zoneinfo/Pacific/Port_Moresby 28966 +usr/share/zoneinfo/Pacific/Rarotonga 28965 +usr/share/zoneinfo/Pacific/Tahiti 28964 +usr/share/zoneinfo/Pacific/Tarawa 28963 +usr/share/zoneinfo/Pacific/Tongatapu 28962 +usr/share/zoneinfo/Pacific/Wake 28961 +usr/share/zoneinfo/Pacific/Wallis 28960 +usr/share/zoneinfo/WET 28959 +usr/local/sbin/live-persist 28958 +lib/live/boot/9990-cmdline-old 28957 +lib/live/boot/9990-misc-helpers.sh 28956 +sbin/cryptsetup 28953 +lib/x86_64-linux-gnu/libpopt.so.0.0.0 28952 +usr/share/fonts/opentype/cantarell/Cantarell-Bold.otf 28949 +usr/lib/dconf/dconf-service 28948 +usr/share/icons/hicolor/scalable/actions/tails-help.svg 28947 +usr/share/icons/hicolor/scalable/actions/tails-language.svg 28946 +usr/share/icons/hicolor/scalable/actions/tails-keyboard-layout.svg 28945 +usr/share/icons/hicolor/scalable/actions/tails-formats.svg 28944 +usr/share/icons/Adwaita/16x16/actions/list-add-symbolic.symbolic.png 28943 +usr/share/icons/Adwaita/cursors/top_left_corner 28942 +usr/share/icons/Adwaita/cursors/top_side 28941 +usr/share/icons/Adwaita/cursors/top_right_corner 28940 +usr/share/icons/Adwaita/cursors/left_side 28939 +usr/share/icons/Adwaita/cursors/right_side 28938 +usr/share/icons/Adwaita/cursors/bottom_left_corner 28937 +usr/share/icons/Adwaita/cursors/bottom_side 28936 +usr/share/icons/Adwaita/cursors/bottom_right_corner 28935 +usr/share/icons/hicolor/32x32/apps/gdm-setup.png 28934 +usr/lib/gdm3/gdm-session-worker 28932 +etc/pam.d/gdm-password 28929 +lib/x86_64-linux-gnu/security/pam_nologin.so 28928 +lib/x86_64-linux-gnu/security/pam_succeed_if.so 28927 +lib/x86_64-linux-gnu/security/pam_selinux.so 28926 +lib/x86_64-linux-gnu/security/pam_loginuid.so 28925 +lib/x86_64-linux-gnu/security/pam_keyinit.so 28924 +lib/x86_64-linux-gnu/security/pam_limits.so 28923 +lib/x86_64-linux-gnu/security/pam_env.so 28922 +etc/securetty 28921 +etc/security/limits.conf 28919 +etc/security/pam_env.conf 28918 +etc/environment 28917 +lib/systemd/system/user@.service 28915 +lib/systemd/system/user-.slice.d/10-defaults.conf 28914 +lib/systemd/system/user-runtime-dir@.service 28913 +lib/systemd/systemd-user-runtime-dir 28906 +etc/pam.d/systemd-user 28904 +lib/systemd/systemd 28903 +etc/systemd/user.conf 28902 +usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator 28900 +usr/lib/systemd/user/default.target 28898 +usr/lib/systemd/user/shutdown.target 28897 +usr/lib/systemd/user/basic.target 28896 +usr/lib/systemd/user/tails-create-tor-browser-directories.service 28895 +usr/lib/systemd/user/tails-add-GNOME-bookmarks.service 28894 +usr/lib/systemd/user/paths.target 28893 +usr/lib/systemd/user/timers.target 28892 +usr/lib/systemd/user/sockets.target 28891 +usr/lib/systemd/user/gpg-agent.socket 28890 +usr/lib/systemd/user/gpg-agent.service 28889 +usr/lib/systemd/user/gpg-agent-ssh.socket 28888 +usr/lib/systemd/user/gpg-agent-extra.socket 28887 +usr/lib/systemd/user/gpg-agent-browser.socket 28886 +usr/lib/systemd/user/dirmngr.socket 28885 +usr/lib/systemd/user/dirmngr.service 28884 +usr/lib/systemd/user/dbus.socket 28883 +usr/lib/systemd/user/dbus.service 28882 +usr/bin/dirmngr 28880 +usr/local/lib/add-GNOME-bookmarks 28877 +usr/bin/id 28871 +usr/local/lib/tails-shell-library/tails-greeter.sh 28870 +usr/local/lib/create-tor-browser-directories 28869 +usr/bin/gio 28867 +etc/gdm3/PostLogin/Default 28865 +etc/live/config.d/username.conf 28864 +usr/share/dbus-1/session.conf 28863 +etc/dbus-1/session.d/im.pidgin.purple.PurpleService.conf 28862 +usr/share/dbus-1/services/ca.desrt.dconf.service 28861 +usr/share/dbus-1/services/org.a11y.Bus.service 28860 +usr/share/dbus-1/services/org.fedoraproject.Config.Printing.service 28859 +usr/share/dbus-1/services/org.freedesktop.ColorHelper.service 28858 +usr/share/dbus-1/services/org.freedesktop.FileManager1.service 28857 +usr/share/dbus-1/services/org.freedesktop.IBus.service 28856 +usr/share/dbus-1/services/org.freedesktop.secrets.service 28855 +usr/share/dbus-1/services/org.gnome.Calculator.SearchProvider.service 28854 +usr/share/dbus-1/services/org.gnome.Caribou.Daemon.service 28853 +usr/share/dbus-1/services/org.gnome.ControlCenter.SearchProvider.service 28852 +usr/share/dbus-1/services/org.gnome.ControlCenter.service 28851 +usr/share/dbus-1/services/org.gnome.DiskUtility.service 28850 +usr/share/dbus-1/services/org.gnome.FileRoller.ArchiveManager1.service 28849 +usr/share/dbus-1/services/org.gnome.FileRoller.service 28848 +usr/share/dbus-1/services/org.gnome.Nautilus.service 28847 +usr/share/dbus-1/services/org.gnome.Screenshot.service 28846 +usr/share/dbus-1/services/org.gnome.Shell.CalendarServer.service 28845 +usr/share/dbus-1/services/org.gnome.Shell.HotplugSniffer.service 28844 +usr/share/dbus-1/services/org.gnome.Shell.PortalHelper.service 28843 +usr/share/dbus-1/services/org.gnome.Terminal.service 28842 +usr/share/dbus-1/services/org.gnome.Totem.service 28841 +usr/share/dbus-1/services/org.gnome.evince.Daemon.service 28840 +usr/share/dbus-1/services/org.gnome.evolution.dataserver.AddressBook.service 28839 +usr/share/dbus-1/services/org.gnome.evolution.dataserver.Calendar.service 28838 +usr/share/dbus-1/services/org.gnome.evolution.dataserver.Sources.service 28837 +usr/share/dbus-1/services/org.gnome.evolution.dataserver.UserPrompter.service 28836 +usr/share/dbus-1/services/org.gnome.gedit.service 28835 +usr/share/dbus-1/services/org.gnome.keyring.PrivatePrompter.service 28834 +usr/share/dbus-1/services/org.gnome.keyring.SystemPrompter.service 28833 +usr/share/dbus-1/services/org.gnome.keyring.service 28832 +usr/share/dbus-1/services/org.gnome.seahorse.Application.service 28831 +usr/share/dbus-1/services/org.gnome.seahorse.service 28830 +usr/share/dbus-1/services/org.gtk.GLib.PACRunner.service 28829 +usr/share/dbus-1/services/org.gtk.vfs.AfcVolumeMonitor.service 28828 +usr/share/dbus-1/services/org.gtk.vfs.Daemon.service 28827 +usr/share/dbus-1/services/org.gtk.vfs.GPhoto2VolumeMonitor.service 28826 +usr/share/dbus-1/services/org.gtk.vfs.GoaVolumeMonitor.service 28825 +usr/share/dbus-1/services/org.gtk.vfs.MTPVolumeMonitor.service 28824 +usr/share/dbus-1/services/org.gtk.vfs.Metadata.service 28823 +usr/share/dbus-1/services/org.gtk.vfs.UDisks2VolumeMonitor.service 28822 +usr/local/lib/tails-unblock-network 28821 +usr/bin/localectl 28820 +usr/lib/systemd/user/gvfs-daemon.service 28819 +lib/systemd/system/tails-unblock-network.service 28818 +usr/lib/gvfs/gvfsd 28816 +usr/lib/x86_64-linux-gnu/gvfs/libgvfsdaemon.so 28815 +usr/share/systemd/language-fallback-map 28813 +usr/share/gvfs/mounts/admin.mount 28810 +usr/share/gvfs/mounts/afc.mount 28809 +usr/share/gvfs/mounts/afp-browse.mount 28808 +usr/share/gvfs/mounts/afp.mount 28807 +usr/share/gvfs/mounts/archive.mount 28806 +usr/share/gvfs/mounts/burn.mount 28805 +usr/share/gvfs/mounts/cdda.mount 28804 +usr/share/gvfs/mounts/computer.mount 28803 +usr/share/gvfs/mounts/dav+sd.mount 28802 +usr/share/gvfs/mounts/dav.mount 28801 +usr/share/gvfs/mounts/dns-sd.mount 28800 +usr/share/gvfs/mounts/ftp.mount 28799 +usr/share/gvfs/mounts/ftps.mount 28798 +usr/share/gvfs/mounts/google.mount 28797 +usr/share/gvfs/mounts/gphoto2.mount 28796 +usr/share/gvfs/mounts/http.mount 28795 +usr/share/gvfs/mounts/localtest.mount 28794 +usr/share/gvfs/mounts/mtp.mount 28793 +usr/share/gvfs/mounts/network.mount 28792 +usr/share/gvfs/mounts/nfs.mount 28791 +usr/share/gvfs/mounts/recent.mount 28790 +usr/share/gvfs/mounts/sftp.mount 28789 +usr/share/gvfs/mounts/smb-browse.mount 28788 +usr/share/gvfs/mounts/smb.mount 28787 +usr/share/gvfs/mounts/trash.mount 28786 +bin/sync 28785 +usr/lib/systemd/user/gvfs-metadata.service 28783 +usr/sbin/deluser 28782 +usr/lib/gvfs/gvfsd-metadata 28779 +usr/share/perl/5.24.1/File/Find.pm 28777 +usr/share/perl/5.24.1/File/Basename.pm 28776 +usr/lib/x86_64-linux-gnu/perl/5.24.1/File/Spec.pm 28775 +usr/lib/x86_64-linux-gnu/perl/5.24.1/File/Spec/Unix.pm 28774 +usr/share/perl/5.24.1/File/Temp.pm 28773 +usr/share/perl/5.24.1/File/Path.pm 28772 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Errno.pm 28771 +usr/share/perl/5.24.1/parent.pm 28770 +usr/share/perl/5.24.1/Carp/Heavy.pm 28769 +etc/deluser.conf 28768 +usr/bin/passwd 28767 +etc/gdm3/PreSession/Default 28763 +usr/lib/gdm3/gdm-x-session.tails 28762 +usr/lib/gdm3/gdm-x-session.real 28759 +usr/bin/Xorg 28758 +usr/lib/xorg/Xorg.wrap 28757 +etc/X11/Xwrapper.config 28756 +usr/lib/xorg/Xorg 28754 +usr/lib/x86_64-linux-gnu/libXfont2.so.2.0.0 28753 +usr/lib/x86_64-linux-gnu/libfontenc.so.1.0.0 28752 +usr/lib/xorg/protocol.txt 28751 +usr/share/X11/xorg.conf.d/10-amdgpu.conf 28750 +usr/share/X11/xorg.conf.d/10-quirks.conf 28749 +usr/share/X11/xorg.conf.d/40-libinput.conf 28748 +usr/share/X11/xorg.conf.d/90-tails.conf 28747 +usr/lib/xorg/modules/extensions/libglx.so 28737 +usr/lib/xorg/modules/drivers/ati_drv.so 28736 +usr/lib/xorg/modules/drivers/radeon_drv.so 28735 +usr/lib/xorg/modules/drivers/modesetting_drv.so 28734 +usr/lib/xorg/modules/drivers/fbdev_drv.so 28733 +usr/lib/xorg/modules/drivers/vesa_drv.so 28732 +usr/lib/xorg/modules/libfbdevhw.so 28731 +usr/lib/xorg/modules/libglamoregl.so 28730 +usr/share/glvnd/egl_vendor.d/50_mesa.json 28729 +usr/lib/x86_64-linux-gnu/libEGL_mesa.so.0.0.0 28728 +usr/lib/xorg/modules/libfb.so 28727 +usr/lib/xorg/modules/libexa.so 28726 +usr/share/fonts/X11/Type1/fonts.dir 28725 +usr/lib/xorg/modules/input/libinput_drv.so 28724 +etc/gdm3/Xsession 28714 +etc/profile 28713 +etc/profile.d/bash_completion.sh 28712 +etc/profile.d/vte-2.91.sh 28711 +etc/X11/Xsession.d/20dbus_xdg-runtime 28710 +usr/bin/dbus-update-activation-environment 28709 +etc/X11/Xsession.d/20x11-common_process-args 28708 +etc/X11/Xsession.options 28707 +etc/X11/Xsession.d/30x11-common_xresources 28706 +usr/bin/xrdb 28705 +usr/lib/x86_64-linux-gnu/libXmuu.so.1.0.0 28704 +lib/modules/4.19.0-5-amd64/kernel/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko 28569 +lib/modules/4.19.0-5-amd64/kernel/drivers/net/ethernet/atheros/atl1c/atl1c.ko 28555 +lib/firmware/iwlwifi-1000-5.ucode 28538 +lib/modules/4.19.0-5-amd64/kernel/net/mac80211/mac80211.ko 28532 +usr/share/alsa/init/00main 28531 +usr/share/alsa/init/hda 28530 +usr/share/alsa/init/default 28529 +lib/systemd/system/systemd-udev-settle.service 28525 +etc/X11/Xresources/x11-common 28489 +usr/local/lib/tails-spoof-mac 28475 +usr/local/lib/tails-shell-library/hardware.sh 28438 +usr/local/lib/tails-shell-library/log.sh 28437 +usr/bin/gettext.sh 28435 +usr/bin/x86_64-linux-gnu-cpp-6 28373 +usr/bin/macchanger 28308 +usr/share/macchanger/OUI.list 28307 +usr/lib/gcc/x86_64-linux-gnu/6/cc1 28276 +lib/modules/4.19.0-5-amd64/kernel/drivers/net/wireless/intel/iwlwifi/dvm/iwldvm.ko 28275 +usr/lib/x86_64-linux-gnu/libisl.so.15.3.0 28274 +usr/share/macchanger/wireless.list 28273 +usr/lib/x86_64-linux-gnu/libmpc.so.3.0.0 28272 +usr/lib/x86_64-linux-gnu/libmpfr.so.4.1.5 28271 +lib/crda/setregdomain 28270 +lib/modules/4.19.0-5-amd64/kernel/crypto/arc4.ko 28269 +lib/systemd/systemd-rfkill 28267 +etc/default/crda 28266 +lib/systemd/systemd-sysctl 28261 +etc/sysctl.d/disable_ipv6.conf 28260 +etc/sysctl.d/fs_protected.conf 28259 +etc/sysctl.d/kexec.conf 28258 +etc/sysctl.d/kptr_restrict.conf 28257 +etc/sysctl.d/mmap_aslr.conf 28256 +etc/sysctl.d/pmtud.conf 28255 +etc/sysctl.d/ptrace_scope.conf 28254 +etc/sysctl.d/tcp_timestamps.conf 28253 +etc/sysctl.d/unprivileged_bpf.conf 28252 +etc/X11/Xsession.d/60xdg-user-dirs-update 28249 +usr/bin/xdg-user-dirs-update 28248 +etc/default/nss 28247 +etc/xdg/user-dirs.conf 28246 +etc/xdg/user-dirs.defaults 28245 +etc/X11/Xsession.d/75dbus_dbus-launch 28244 +etc/X11/Xsession.d/90atk-adaptor 28243 +etc/X11/Xsession.d/90gpg-agent 28241 +usr/bin/gpgconf 28240 +etc/X11/Xsession.d/90qt5-opengl 28239 +usr/bin/glxinfo 28238 +usr/lib/x86_64-linux-gnu/libGLEW.so.2.0.0 28237 +usr/lib/x86_64-linux-gnu/libGLU.so.1.3.1 28236 +etc/X11/Xsession.d/90qt-a11y 28235 +etc/X11/Xsession.d/90x11-common_ssh-agent 28234 +etc/X11/Xsession.d/92tails-set-SSH_AUTH_SOCK 28233 +etc/X11/Xsession.d/95dbus_update-activation-env 28232 +etc/X11/Xsession.d/98vboxadd-xclient 28231 +etc/X11/Xsession.d/99x11-common_start 28230 +usr/bin/gnome-session 28229 +etc/dconf/profile/user 28228 +etc/dconf/db/local 28227 +usr/lib/gnome-session/gnome-session-binary 28226 +usr/share/gnome-session/sessions/gnome.session 28219 +etc/xdg/autostart/at-spi-dbus-bus.desktop 28218 +etc/xdg/autostart/caribou-autostart.desktop 28217 +etc/xdg/autostart/gnome-keyring-pkcs11.desktop 28216 +etc/xdg/autostart/gnome-keyring-secrets.desktop 28215 +etc/xdg/autostart/gnome-keyring-ssh.desktop 28214 +etc/xdg/autostart/nautilus-autostart.desktop 28213 +etc/xdg/autostart/nm-applet.desktop 28212 +etc/xdg/autostart/openpgp-applet.desktop 28211 +etc/xdg/autostart/orca-autostart.desktop 28210 +etc/xdg/autostart/pulseaudio.desktop 28209 +etc/xdg/autostart/systemd-desktop-target.desktop 28208 +etc/xdg/autostart/systemd-gnome-early-initialization-target.desktop 28207 +etc/xdg/autostart/user-dirs-update-gtk.desktop 28206 +usr/lib/systemd/user/gnome-early-initialization.target 28203 +usr/lib/systemd/user/tails-configure-keyboard.service 28202 +usr/local/lib/tails-configure-keyboard 28200 +usr/bin/gnome-keyring-daemon 28195 +usr/share/gnome/applications/vim.desktop 28185 +usr/share/gnome/applications/display-im6.q16.desktop 28184 +usr/share/tails/screensaver_background.png 28183 +bin/false 28180 +usr/share/wayland-sessions/gnome-wayland.desktop 28179 +usr/lib/x86_64-linux-gnu/girepository-1.0/PolkitAgent-1.0.typelib 28178 +usr/lib/girepository-1.0/TelepathyLogger-0.2.typelib 28177 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gcr-3.typelib 28176 +usr/lib/x86_64-linux-gnu/girepository-1.0/Gck-1.typelib 28175 +usr/share/gvfs/remote-volume-monitors/afc.monitor 28174 +usr/share/gvfs/remote-volume-monitors/goa.monitor 28173 +usr/share/gvfs/remote-volume-monitors/gphoto2.monitor 28172 +usr/share/gvfs/remote-volume-monitors/mtp.monitor 28171 +usr/share/gvfs/remote-volume-monitors/udisks2.monitor 28170 +usr/lib/systemd/user/gvfs-udisks2-volume-monitor.service 28169 +usr/lib/gvfs/gvfs-udisks2-volume-monitor 28167 +usr/lib/x86_64-linux-gnu/libudisks2.so.0.0.0 28166 +usr/lib/x86_64-linux-gnu/libbluray.so.1.10.0 28165 +lib/systemd/system/udisks2.service 28164 +usr/lib/udisks2/udisksd 28162 +lib/x86_64-linux-gnu/libatasmart.so.4.0.5 28161 +etc/crypttab 28160 +usr/lib/systemd/user/gvfs-mtp-volume-monitor.service 28159 +usr/lib/gvfs/gvfs-mtp-volume-monitor 28157 +usr/lib/systemd/user/gvfs-gphoto2-volume-monitor.service 28156 +etc/dconf/profile/ibus 28155 +etc/dconf/db/ibus 28154 +usr/lib/gvfs/gvfs-gphoto2-volume-monitor 28152 +usr/lib/x86_64-linux-gnu/libgphoto2.so.6.0.0 28151 +usr/lib/x86_64-linux-gnu/libgphoto2_port.so.12.0.0 28150 +usr/lib/x86_64-linux-gnu/libexif.so.12.3.3 28149 +usr/lib/systemd/user/gvfs-goa-volume-monitor.service 28148 +usr/lib/gvfs/gvfs-goa-volume-monitor 28146 +usr/lib/x86_64-linux-gnu/libgoa-1.0.so.0.0.0 28145 +usr/lib/systemd/user/gvfs-afc-volume-monitor.service 28144 +usr/lib/gvfs/gvfs-afc-volume-monitor 28142 +usr/share/gnome-shell/search-providers/gnome-calculator-search-provider.ini 28141 +usr/share/gnome-shell/search-providers/gnome-control-center-search-provider.ini 28140 +usr/share/gnome-shell/search-providers/gnome-terminal-search-provider.ini 28139 +usr/share/gnome-shell/search-providers/nautilus-search-provider.ini 28138 +usr/share/gnome-shell/search-providers/seahorse-search-provider.ini 28137 +usr/share/gnome-shell/extensions/torstatus@tails.boum.org/metadata.json 28136 +usr/share/perl5/Gtk3.pm 28135 +usr/share/gnome-shell/extensions/torstatus@tails.boum.org/extension.js 28134 +usr/lib/gnome-settings-daemon/gsd-printer 28133 +usr/share/gnome-shell/extensions/user-theme@gnome-shell-extensions.gcampax.github.com/metadata.json 28132 +usr/local/lib/tails-virt-notify-user 28129 +usr/share/gnome-shell/extensions/window-list@gnome-shell-extensions.gcampax.github.com/metadata.json 28127 +usr/share/gnome-shell/extensions/window-list@gnome-shell-extensions.gcampax.github.com/extension.js 28126 +lib/systemd/system/tails-additional-software-install.service 28125 +usr/share/perl5/Desktop/Notify.pm 28124 +usr/lib/gvfs/gvfsd-trash 28123 +usr/share/gnome-shell/extensions/window-list@gnome-shell-extensions.gcampax.github.com/convenience.js 28122 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus.pm 28121 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Net/DBus/DBus.so 28120 +usr/share/gnome-shell/extensions/window-list@gnome-shell-extensions.gcampax.github.com/stylesheet.css 28119 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Bus.pm 28118 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Connection.pm 28117 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Message/MethodCall.pm 28116 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Message.pm 28115 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Iterator.pm 28114 +usr/share/gnome-shell/extensions/windowsNavigator@gnome-shell-extensions.gcampax.github.com/metadata.json 28113 +usr/share/gnome-shell/extensions/workspace-indicator@gnome-shell-extensions.gcampax.github.com/metadata.json 28112 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Message/Signal.pm 28111 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Message/MethodReturn.pm 28110 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Message/Error.pm 28109 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/PendingCall.pm 28108 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Service.pm 28107 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/RemoteService.pm 28106 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/RemoteObject.pm 28105 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Introspector.pm 28104 +usr/share/perl5/XML/Twig.pm 28103 +usr/share/perl/5.24.1/UNIVERSAL.pm 28102 +usr/share/perl/5.24.1/utf8.pm 28101 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/Parser.pm 28100 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/Parser/Expat.pm 28099 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/XML/Parser/Expat/Expat.so 28098 +usr/lib/x86_64-linux-gnu/perl/5.24.1/File/Glob.pm 28097 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/File/Glob/Glob.so 28096 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libevince-properties-page.so 28095 +usr/lib/x86_64-linux-gnu/libevdocument3.so.4.0.0 28094 +usr/lib/x86_64-linux-gnu/evince/4/backends/comicsdocument.evince-backend 28093 +usr/lib/x86_64-linux-gnu/evince/4/backends/djvudocument.evince-backend 28092 +usr/lib/x86_64-linux-gnu/evince/4/backends/dvidocument.evince-backend 28091 +usr/lib/x86_64-linux-gnu/evince/4/backends/pdfdocument.evince-backend 28090 +usr/lib/x86_64-linux-gnu/evince/4/backends/psdocument.evince-backend 28089 +usr/lib/x86_64-linux-gnu/evince/4/backends/tiffdocument.evince-backend 28088 +usr/lib/x86_64-linux-gnu/evince/4/backends/xpsdocument.evince-backend 28087 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libgtkhash-properties.so 28086 +usr/lib/x86_64-linux-gnu/libmhash.so.2.0.1 28085 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libnautilus-brasero-extension.so 28084 +usr/lib/x86_64-linux-gnu/libbrasero-utils3.so.1.2.6 28083 +usr/lib/x86_64-linux-gnu/libbrasero-media3.so.1.2.6 28082 +usr/lib/x86_64-linux-gnu/libbrasero-burn3.so.1.2.6 28081 +usr/lib/x86_64-linux-gnu/libgstpbutils-1.0.so.0.1004.0 28080 +usr/lib/x86_64-linux-gnu/libtotem-plparser.so.18.1.0 28079 +usr/lib/x86_64-linux-gnu/libgstvideo-1.0.so.0.1004.0 28078 +usr/lib/x86_64-linux-gnu/libgstaudio-1.0.so.0.1004.0 28076 +usr/lib/x86_64-linux-gnu/libgsttag-1.0.so.0.1004.0 28075 +usr/lib/x86_64-linux-gnu/libgmime-2.6.so.0.622.0 28074 +usr/lib/x86_64-linux-gnu/libgpgme.so.11.17.0 28073 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libnautilus-seahorse.so 28071 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libnautilus-sendto.so 28070 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libnautilus-wipe.so 28069 +usr/lib/x86_64-linux-gnu/libgsecuredelete.so.0.1.0 28068 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libterminal-nautilus.so 28067 +usr/lib/x86_64-linux-gnu/nautilus/extensions-3.0/libtotem-properties-page.so 28066 +usr/lib/nautilus/extensions-3.0/libnautilus-python.so 28065 +usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 28064 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/ASyncReply.pm 28063 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Annotation.pm 28062 +usr/share/perl5/Gtk3/SimpleList.pm 28061 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Test/MockConnection.pm 28060 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Error.pm 28059 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Test/MockMessage.pm 28058 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Test/MockIterator.pm 28057 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Data/Dumper.pm 28056 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Data/Dumper/Dumper.so 28055 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Value.pm 28054 +usr/share/perl5/Crypt/OpenPGP_Applet/GnuPG/Interface.pm 28053 +usr/share/perl5/Desktop/Notify/Notification.pm 28052 +usr/share/perl5/Class/Accessor.pm 28051 +usr/share/perl5/Moo.pm 28050 +usr/lib/x86_64-linux-gnu/perl5/5.24/Sub/Name.pm 28049 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Sub/Name/Name.so 28048 +usr/share/perl5/Moo/_strictures.pm 28047 +usr/share/perl5/Moo/_mro.pm 28046 +usr/lib/x86_64-linux-gnu/perl/5.24.1/mro.pm 28045 +usr/share/perl/5.24.1/English.pm 28044 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Tie/Hash/NamedCapture.pm 28043 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Tie/Hash/NamedCapture/NamedCapture.so 28042 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/mro/mro.so 28041 +usr/share/perl5/Moo/_Utils.pm 28040 +usr/lib/x86_64-linux-gnu/perl5/5.24/Sub/Util.pm 28039 +usr/share/perl5/Module/Runtime.pm 28038 +usr/share/perl5/Devel/GlobalDestruction.pm 28037 +usr/share/perl5/IPC/System/Simple.pm 28036 +usr/lib/python2.7/site.py 28035 +usr/lib/python2.7/os.py 28034 +usr/share/perl5/Sub/Exporter/Progressive.pm 28033 +usr/share/perl5/Moo/HandleMoose/_TypeMap.pm 28032 +usr/share/perl5/Moo/sification.pm 28031 +usr/share/perl5/Moo/Object.pm 28030 +usr/share/perl5/namespace/autoclean.pm 28029 +usr/lib/python2.7/posixpath.py 28028 +usr/lib/python2.7/stat.py 28027 +usr/lib/python2.7/genericpath.py 28026 +usr/lib/python2.7/warnings.py 28025 +usr/share/perl5/B/Hooks/EndOfScope.pm 28024 +usr/share/perl5/Module/Implementation.pm 28023 +usr/share/perl5/Try/Tiny.pm 28022 +usr/share/perl5/B/Hooks/EndOfScope/XS.pm 28021 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Config_heavy.pl 28020 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Config_git.pl 28019 +usr/lib/x86_64-linux-gnu/perl5/5.24/Variable/Magic.pm 28018 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Variable/Magic/Magic.so 28017 +usr/share/perl5/namespace/clean.pm 28016 +usr/lib/python2.7/linecache.py 28015 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Reactor.pm 28014 +usr/share/perl5/Package/Stash.pm 28013 +usr/lib/python2.7/types.py 28012 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Binding/Watch.pm 28011 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/Callback.pm 28010 +usr/lib/python2.7/UserDict.py 28009 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Time/HiRes.pm 28008 +usr/lib/x86_64-linux-gnu/perl5/5.24/Package/Stash/XS.pm 28007 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Package/Stash/XS/XS.so 28006 +usr/share/perl5/namespace/clean/_Util.pm 28005 +usr/lib/python2.7/_abcoll.py 28004 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Time/HiRes/HiRes.so 28003 +usr/lib/python2.7/abc.py 28002 +usr/lib/python2.7/_weakrefset.py 28001 +usr/lib/x86_64-linux-gnu/perl5/5.24/Sub/Identify.pm 28000 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Sub/Identify/Identify.so 27999 +usr/share/perl5/GnuPG/Interface.pm 27998 +usr/lib/python2.7/copy_reg.py 27997 +usr/bin/systemd-detect-virt 27996 +usr/share/perl5/MooX/late.pm 27995 +usr/share/perl5/Method/Generate/Constructor.pm 27994 +usr/share/perl5/Sub/Quote.pm 27993 +usr/share/perl5/Sub/Defer.pm 27992 +usr/lib/python2.7/traceback.py 27991 +usr/lib/x86_64-linux-gnu/perl/5.24.1/B.pm 27990 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/B/B.so 27989 +usr/lib/python2.7/sysconfig.py 27988 +usr/lib/python2.7/re.py 27987 +usr/lib/python2.7/sre_compile.py 27986 +usr/share/perl5/Method/Generate/Accessor.pm 27985 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/XSAccessor.pm 27984 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/XSAccessor/Heavy.pm 27983 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Class/XSAccessor/XSAccessor.so 27982 +usr/share/perl5/Image/ExifTool/Exif.pm 27981 +etc/services 27980 +var/lib/NetworkManager/dhclient-eth0.conf 27979 +usr/lib/NetworkManager/nm-dhcp-helper 27977 +usr/lib/python2.7/dist-packages/libmat/exiftool.py 27976 +usr/share/nautilus-python/extensions/onionshare-nautilus.py 27975 +usr/lib/x86_64-linux-gnu/girepository-1.0/Nautilus-3.0.typelib 27974 +usr/bin/nautilus 27971 +usr/lib/x86_64-linux-gnu/libexempi.so.3.4.1 27970 +usr/lib/x86_64-linux-gnu/libtracker-sparql-1.0.so.0.1005.0 27969 +usr/lib/x86_64-linux-gnu/libgailutil-3.so.0.0.0 27968 +usr/lib/x86_64-linux-gnu/libnautilus-extension.so.1.4.0 27967 +usr/lib/x86_64-linux-gnu/libgnome-autoar-0.so.0.0.0 27966 +usr/lib/x86_64-linux-gnu/tracker-1.0/libtracker-data.so.0.0.0 27965 +usr/lib/x86_64-linux-gnu/tracker-1.0/libtracker-common.so.0.0.0 27964 +usr/lib/x86_64-linux-gnu/libarchive.so.13.2.2 27963 +usr/lib/x86_64-linux-gnu/libunistring.so.0.1.2 27962 +usr/lib/x86_64-linux-gnu/libstemmer.so.0d.0.0 27961 +lib/x86_64-linux-gnu/liblzo2.so.2.0.0 27960 +usr/lib/python2.7/sre_parse.py 27958 +usr/lib/python2.7/sre_constants.py 27957 +usr/lib/python2.7/_sysconfigdata.py 27956 +usr/lib/python2.7/plat-x86_64-linux-gnu/_sysconfigdata_nd.py 27955 +usr/lib/python2.7/dist-packages/gtk-2.0-pysupport-compat.pth 27954 +usr/lib/python2.7/dist-packages/pygtk.pth 27953 +etc/python2.7/sitecustomize.py 27952 +usr/lib/python2.7/encodings/__init__.py 27951 +usr/lib/python2.7/codecs.py 27950 +usr/lib/python2.7/encodings/aliases.py 27949 +usr/lib/python2.7/encodings/utf_8.py 27948 +usr/lib/python2.7/dist-packages/gi/__init__.py 27947 +usr/lib/python2.7/__future__.py 27946 +usr/lib/python2.7/pkgutil.py 27945 +usr/lib/python2.7/importlib/__init__.py 27944 +usr/lib/python2.7/dist-packages/gi/_gi.x86_64-linux-gnu.so 27943 +usr/lib/python2.7/dist-packages/gi/_error.py 27942 +usr/lib/python2.7/dist-packages/gi/_gobject/__init__.py 27941 +usr/lib/python2.7/dist-packages/gi/repository/__init__.py 27940 +usr/lib/python2.7/dist-packages/gi/importer.py 27939 +usr/lib/python2.7/contextlib.py 27938 +usr/lib/python2.7/functools.py 27937 +usr/lib/python2.7/dist-packages/gi/module.py 27936 +usr/lib/python2.7/string.py 27935 +usr/lib/python2.7/dist-packages/gi/types.py 27934 +usr/lib/python2.7/dist-packages/gi/_constants.py 27933 +usr/lib/python2.7/dist-packages/gi/docstring.py 27932 +usr/lib/python2.7/dist-packages/gi/_propertyhelper.py 27931 +usr/lib/python2.7/dist-packages/gi/_signalhelper.py 27930 +usr/lib/python2.7/dist-packages/gi/overrides/__init__.py 27929 +usr/lib/python2.7/dist-packages/gi/overrides/GLib.py 27928 +usr/lib/python2.7/socket.py 27927 +usr/lib/python2.7/lib-dynload/_ssl.x86_64-linux-gnu.so 27926 +usr/lib/python2.7/dist-packages/gi/_option.py 27925 +usr/lib/python2.7/optparse.py 27924 +usr/lib/python2.7/textwrap.py 27923 +usr/lib/python2.7/gettext.py 27922 +usr/lib/python2.7/locale.py 27921 +usr/lib/python2.7/copy.py 27920 +usr/lib/python2.7/weakref.py 27919 +usr/lib/python2.7/struct.py 27918 +usr/lib/python2.7/dist-packages/gi/overrides/GObject.py 27917 +usr/lib/python2.7/collections.py 27916 +usr/lib/python2.7/keyword.py 27915 +usr/lib/python2.7/heapq.py 27914 +usr/lib/python2.7/dist-packages/gi/overrides/Pango.py 27913 +usr/lib/python2.7/dist-packages/gi/overrides/Gio.py 27912 +usr/lib/python2.7/dist-packages/gi/overrides/Gdk.py 27911 +usr/lib/python2.7/dist-packages/gi/overrides/Gtk.py 27910 +usr/share/nautilus-python/extensions/nautilus-mat.py 27909 +usr/lib/python2.7/logging/__init__.py 27908 +usr/lib/python2.7/threading.py 27907 +usr/lib/python2.7/atexit.py 27906 +usr/lib/python2.7/urllib.py 27905 +usr/lib/python2.7/base64.py 27904 +usr/lib/python2.7/urlparse.py 27903 +usr/lib/python2.7/ssl.py 27902 +usr/lib/python2.7/dist-packages/libmat/__init__.py 27901 +usr/lib/python2.7/dist-packages/libmat/mat.py 27900 +usr/lib/python2.7/mimetypes.py 27899 +usr/lib/python2.7/platform.py 27898 +usr/lib/python2.7/subprocess.py 27897 +usr/lib/python2.7/pickle.py 27896 +usr/lib/python2.7/xml/__init__.py 27895 +usr/lib/python2.7/xml/sax/__init__.py 27894 +usr/lib/python2.7/xml/sax/xmlreader.py 27893 +usr/lib/python2.7/xml/sax/handler.py 27892 +usr/lib/python2.7/xml/sax/_exceptions.py 27891 +usr/lib/python2.7/dist-packages/libmat/exceptions.py 27890 +usr/lib/python2.7/dist-packages/libmat/strippers.py 27889 +usr/lib/python2.7/dist-packages/libmat/archive.py 27888 +usr/lib/python2.7/shutil.py 27887 +usr/lib/python2.7/fnmatch.py 27886 +usr/lib/python2.7/tarfile.py 27885 +usr/lib/python2.7/tempfile.py 27884 +usr/lib/python2.7/io.py 27883 +usr/lib/python2.7/random.py 27882 +usr/lib/python2.7/hashlib.py 27881 +usr/lib/python2.7/lib-dynload/_hashlib.x86_64-linux-gnu.so 27880 +usr/lib/python2.7/zipfile.py 27879 +usr/lib/python2.7/dist-packages/libmat/parser.py 27878 +usr/lib/python2.7/dist-packages/libmat/mutagenstripper.py 27877 +usr/lib/python2.7/dist-packages/mutagen/__init__.py 27876 +usr/lib/python2.7/dist-packages/mutagen/_util.py 27875 +usr/lib/python2.7/lib-dynload/mmap.x86_64-linux-gnu.so 27874 +usr/lib/python2.7/dist-packages/mutagen/_compat.py 27873 +usr/lib/python2.7/StringIO.py 27872 +usr/lib/python2.7/dist-packages/mutagen/_file.py 27871 +usr/lib/python2.7/dist-packages/mutagen/_tags.py 27870 +usr/lib/python2.7/dist-packages/mutagen/flac.py 27869 +usr/lib/python2.7/dist-packages/mutagen/_vorbis.py 27868 +usr/lib/python2.7/dist-packages/mutagen/id3/__init__.py 27867 +usr/lib/python2.7/dist-packages/mutagen/id3/_file.py 27866 +usr/lib/python2.7/dist-packages/mutagen/id3/_util.py 27865 +usr/lib/python2.7/dist-packages/mutagen/id3/_tags.py 27864 +usr/lib/python2.7/dist-packages/mutagen/id3/_frames.py 27863 +usr/lib/python2.7/dist-packages/mutagen/id3/_specs.py 27862 +usr/lib/python2.7/dist-packages/mutagen/_constants.py 27861 +usr/lib/python2.7/dist-packages/mutagen/id3/_id3v1.py 27860 +usr/lib/python2.7/dist-packages/mutagen/oggvorbis.py 27859 +usr/lib/python2.7/dist-packages/mutagen/ogg.py 27858 +usr/lib/python2.7/dist-packages/mutagen/mp3/__init__.py 27857 +usr/lib/python2.7/dist-packages/mutagen/mp3/_util.py 27856 +usr/lib/python2.7/dist-packages/mutagen/easyid3.py 27855 +usr/lib/python2.7/dist-packages/libmat/misc.py 27854 +usr/lib/python2.7/dist-packages/libmat/bencode/__init__.py 27853 +usr/lib/python2.7/dist-packages/libmat/bencode/bencode.py 27852 +usr/lib/python2.7/dist-packages/libmat/office.py 27851 +usr/lib/python2.7/xml/dom/__init__.py 27850 +usr/lib/python2.7/xml/dom/domreg.py 27849 +usr/lib/python2.7/xml/dom/minicompat.py 27848 +usr/lib/python2.7/xml/dom/minidom.py 27847 +usr/lib/python2.7/xml/dom/xmlbuilder.py 27846 +usr/lib/python2.7/xml/dom/NodeFilter.py 27845 +usr/lib/python2.7/dist-packages/cairo/__init__.py 27844 +usr/lib/python2.7/dist-packages/cairo/_cairo.x86_64-linux-gnu.so 27843 +usr/lib/x86_64-linux-gnu/girepository-1.0/Poppler-0.18.typelib 27842 +usr/bin/exiftool 27841 +usr/share/perl5/Image/ExifTool.pm 27840 +usr/share/perl5/File/RandomAccess.pm 27839 +usr/share/perl5/Image/ExifTool/MakerNotes.pm 27838 +usr/share/icons/Adwaita/16x16/actions/document-open-recent-symbolic.symbolic.png 27837 +usr/share/icons/Adwaita/16x16/places/user-home-symbolic.symbolic.png 27836 +usr/share/icons/Adwaita/16x16/places/user-desktop-symbolic.symbolic.png 27835 +usr/share/icons/Adwaita/16x16/places/folder-documents-symbolic.symbolic.png 27834 +usr/share/icons/Adwaita/16x16/places/folder-download-symbolic.symbolic.png 27833 +usr/share/icons/Adwaita/16x16/places/folder-music-symbolic.symbolic.png 27832 +usr/share/icons/Adwaita/16x16/places/folder-pictures-symbolic.symbolic.png 27831 +usr/share/icons/Adwaita/16x16/places/folder-videos-symbolic.symbolic.png 27830 +usr/share/icons/Adwaita/16x16/places/user-trash-symbolic.symbolic.png 27829 +usr/share/icons/Adwaita/16x16/devices/drive-harddisk-solidstate-symbolic.symbolic.png 27828 +usr/share/icons/Adwaita/16x16/devices/drive-harddisk-symbolic.symbolic.png 27827 +usr/share/icons/Adwaita/16x16/actions/pan-down-symbolic.symbolic.png 27826 +usr/share/icons/Adwaita/16x16/actions/window-close-symbolic.symbolic.png 27825 +usr/share/icons/Adwaita/22x22/apps/system-file-manager.png 27824 +usr/share/icons/Adwaita/16x16/apps/system-file-manager.png 27823 +usr/share/icons/Adwaita/24x24/apps/system-file-manager.png 27822 +usr/share/icons/Adwaita/32x32/apps/system-file-manager.png 27821 +usr/share/icons/Adwaita/256x256/apps/system-file-manager.png 27820 +usr/share/icons/Adwaita/48x48/apps/system-file-manager.png 27819 +usr/share/icons/Adwaita/cursors/left_ptr_watch 27818 +usr/lib/gvfs/gvfsd-burn 27817 +usr/share/icons/Adwaita/cursors/sb_h_double_arrow 27816 +usr/share/icons/Adwaita/48x48/places/user-home.png 27815 +usr/share/pixmaps/whisperback.svg 27814 +usr/share/icons/gnome/48x48/categories/system-help.png 27813 +usr/share/icons/Adwaita/48x48/places/user-trash.png 27812 +etc/NetworkManager/dispatcher.d/00-firewall.sh 27810 +usr/share/icons/Adwaita/16x16/devices/network-wired-symbolic.symbolic.png 27809 +etc/NetworkManager/dispatcher.d/00-resolv-over-clearnet 27808 +etc/NetworkManager/dispatcher.d/01-wait-for-notification-recipient.sh 27807 +usr/share/icons/Adwaita/48x48/devices/network-wired-symbolic.symbolic.png 27806 +etc/NetworkManager/dispatcher.d/01ifupdown 27805 +etc/NetworkManager/dispatcher.d/10-tor.sh 27804 +etc/NetworkManager/dispatcher.d/20-time.sh 27803 +usr/local/lib/tails-shell-library/gnome.sh 27802 +etc/NetworkManager/dispatcher.d/60-tor-ready.sh 27801 +etc/NetworkManager/dispatcher.d/70-upgrade-additional-software.sh 27800 +usr/sbin/ferm 27799 +etc/ferm/ferm.conf 27798 +sbin/xtables-multi 27797 +usr/lib/x86_64-linux-gnu/libip6tc.so.0.1.0 27796 +usr/lib/x86_64-linux-gnu/libxtables.so.12.0.0 27795 +usr/lib/x86_64-linux-gnu/xtables/libxt_conntrack.so 27794 +etc/protocols 27793 +usr/lib/x86_64-linux-gnu/xtables/libxt_tcp.so 27792 +usr/lib/x86_64-linux-gnu/xtables/libxt_owner.so 27791 +usr/lib/x86_64-linux-gnu/xtables/libxt_multiport.so 27790 +usr/lib/x86_64-linux-gnu/xtables/libxt_udp.so 27789 +usr/lib/x86_64-linux-gnu/xtables/libipt_LOG.so 27788 +usr/lib/x86_64-linux-gnu/xtables/libipt_REJECT.so 27787 +usr/lib/x86_64-linux-gnu/xtables/libipt_REDIRECT.so 27786 +usr/lib/x86_64-linux-gnu/xtables/libip6t_LOG.so 27785 +usr/lib/x86_64-linux-gnu/xtables/libip6t_REJECT.so 27784 +usr/lib/x86_64-linux-gnu/xtables/libxt_standard.so 27783 +usr/lib/x86_64-linux-gnu/xtables/libxt_state.so 27782 +usr/bin/seq 27779 +usr/bin/pgrep 27778 +bin/tempfile 27776 +usr/local/sbin/restart-tor 27775 +usr/lib/python3.5/encodings/ascii.py 27774 +bin/su 27771 +etc/pam.d/su 27770 +lib/x86_64-linux-gnu/security/pam_mail.so 27769 +usr/lib/python3/dist-packages/sh.py 27768 +usr/local/lib/tails-htp-notify-user 27758 +usr/lib/python3.5/inspect.py 27755 +usr/lib/python3.5/ast.py 27752 +usr/lib/python3.5/dis.py 27749 +usr/lib/python3.5/opcode.py 27746 +usr/lib/python3.5/lib-dynload/_opcode.cpython-35m-x86_64-linux-gnu.so 27743 +usr/lib/python3.5/pty.py 27736 +usr/lib/python3.5/tty.py 27733 +usr/lib/python3.5/lib-dynload/termios.cpython-35m-x86_64-linux-gnu.so 27730 +usr/lib/python3.5/lib-dynload/resource.cpython-35m-x86_64-linux-gnu.so 27729 +usr/lib/python3/dist-packages/stem/__init__.py 27728 +usr/lib/python3/dist-packages/stem/util/__init__.py 27726 +usr/lib/python3/dist-packages/stem/prereq.py 27724 +usr/lib/python3/dist-packages/stem/util/enum.py 27722 +usr/lib/python3/dist-packages/stem/util/str_tools.py 27720 +usr/lib/python3/dist-packages/stem/control.py 27718 +usr/share/perl5/URI.pm 27716 +usr/share/perl5/URI/Escape.pm 27715 +usr/lib/python3/dist-packages/stem/descriptor/__init__.py 27712 +usr/lib/python3.5/tarfile.py 27708 +usr/share/icons/gnome/32x32/status/dialog-information.png 27707 +usr/lib/python3/dist-packages/stem/util/system.py 27704 +usr/lib/python3.5/lib-dynload/_ctypes.cpython-35m-x86_64-linux-gnu.so 27700 +usr/lib/python3.5/distutils/__init__.py 27695 +usr/lib/python3.5/distutils/spawn.py 27693 +usr/lib/python3.5/distutils/errors.py 27691 +usr/lib/python3.5/distutils/debug.py 27689 +usr/lib/python3.5/distutils/log.py 27687 +usr/lib/python3.5/mimetypes.py 27685 +usr/lib/python3/dist-packages/stem/util/proc.py 27680 +usr/lib/python3/dist-packages/stem/util/connection.py 27678 +usr/lib/python3.5/hmac.py 27676 +usr/lib/python3/dist-packages/stem/util/conf.py 27673 +usr/lib/python3/dist-packages/stem/util/log.py 27671 +usr/lib/python3/dist-packages/stem/descriptor/server_descriptor.py 27669 +usr/lib/python3/dist-packages/stem/descriptor/extrainfo_descriptor.py 27667 +usr/lib/python3/dist-packages/stem/exit_policy.py 27665 +usr/lib/python3/dist-packages/stem/util/tor_tools.py 27661 +usr/lib/python3/dist-packages/stem/version.py 27659 +usr/lib/python3/dist-packages/stem/descriptor/networkstatus.py 27657 +usr/lib/python3/dist-packages/stem/descriptor/router_status_entry.py 27655 +usr/lib/python3/dist-packages/stem/descriptor/microdescriptor.py 27653 +usr/lib/python3/dist-packages/stem/descriptor/tordnsel.py 27651 +usr/lib/python3/dist-packages/stem/descriptor/hidden_service_descriptor.py 27649 +usr/lib/python3/dist-packages/stem/descriptor/reader.py 27647 +usr/lib/python3/dist-packages/stem/response/__init__.py 27645 +usr/lib/python3/dist-packages/stem/socket.py 27643 +usr/lib/python3/dist-packages/stem/response/events.py 27641 +usr/bin/tor 27637 +usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9 27636 +usr/lib/x86_64-linux-gnu/libzstd.so.1.1.2 27635 +usr/share/tor/geoip 27630 +usr/share/tor/geoip6 27629 +usr/bin/xxd 27628 +bin/nc.openbsd 27627 +usr/lib/python3/dist-packages/stem/connection.py 27626 +usr/lib/python3.5/getpass.py 27624 +usr/lib/python3/dist-packages/stem/response/add_onion.py 27621 +usr/lib/python3/dist-packages/stem/response/authchallenge.py 27619 +usr/lib/python3/dist-packages/stem/response/getinfo.py 27617 +usr/lib/python3/dist-packages/stem/response/getconf.py 27615 +usr/lib/python3/dist-packages/stem/response/mapaddress.py 27613 +usr/lib/python3/dist-packages/stem/response/protocolinfo.py 27611 +usr/bin/inotifywait 27609 +usr/lib/libinotifytools.so.0.4.1 27608 +usr/bin/sort 27604 +usr/share/icons/hicolor/scalable/status/tor-connected-symbolic.svg 27599 +usr/local/bin/tails-upgrade-frontend-wrapper 27596 +usr/local/bin/tails-security-check 27594 +usr/share/perl5/Carp/Assert/More.pm 27593 +usr/share/perl5/Carp/Assert.pm 27592 +usr/share/perl/5.24.1/Fatal.pm 27591 +usr/share/perl/5.24.1/Tie/RefHash.pm 27590 +usr/share/perl/5.24.1/autodie/Util.pm 27589 +usr/share/perl/5.24.1/autodie/Scope/GuardStack.pm 27588 +usr/share/perl/5.24.1/autodie/Scope/Guard.pm 27587 +usr/share/perl5/Tails/Download/HTTPS.pm 27586 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose.pm 27585 +usr/share/perl5/Class/Load.pm 27584 +usr/share/perl5/Data/OptList.pm 27583 +usr/lib/x86_64-linux-gnu/perl5/5.24/Params/Util.pm 27582 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Params/Util/Util.so 27581 +usr/share/perl5/Sub/Install.pm 27580 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/Load/XS.pm 27579 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Class/Load/XS/XS.so 27578 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Deprecated.pm 27577 +usr/share/perl5/Package/DeprecationManager.pm 27576 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Exporter.pm 27575 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP.pm 27574 +usr/share/perl5/MRO/Compat.pm 27573 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Mixin/AttributeCore.pm 27572 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Mixin.pm 27571 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Mixin/HasAttributes.pm 27570 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Mixin/HasMethods.pm 27569 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Meta.pm 27568 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method.pm 27567 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Object.pm 27566 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Mixin/HasOverloads.pm 27565 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Overload.pm 27564 +usr/share/perl5/Devel/OverloadInfo.pm 27563 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Class.pm 27562 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Instance.pm 27561 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Wrapped.pm 27558 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Accessor.pm 27555 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Generated.pm 27554 +usr/share/perl5/Eval/Closure.pm 27553 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Constructor.pm 27552 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Method/Inlined.pm 27551 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/MiniTrait.pm 27550 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Module.pm 27549 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Package.pm 27548 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Attribute.pm 27547 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Moose/Moose.so 27546 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Deprecated.pm 27535 +usr/lib/x86_64-linux-gnu/perl5/5.24/Class/MOP/Class/Immutable/Trait.pm 27534 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Util/MetaRole.pm 27525 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Util.pm 27524 +usr/share/perl5/Sub/Exporter.pm 27523 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Class.pm 27520 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Overridden.pm 27519 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method.pm 27518 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Object/Trait.pm 27517 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Augmented.pm 27516 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Class/Immutable/Trait.pm 27515 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Constructor.pm 27514 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Destructor.pm 27513 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Meta.pm 27512 +usr/lib/python3/dist-packages/psutil/_compat.py 27511 +usr/lib/python3/dist-packages/psutil/_pslinux.py 27510 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint.pm 27509 +usr/lib/x86_64-linux-gnu/perl5/5.24/metaclass.pm 27508 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeCoercion.pm 27507 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Attribute.pm 27506 +usr/lib/python3/dist-packages/psutil/_psposix.py 27503 +usr/lib/python3/dist-packages/psutil/_psutil_linux.cpython-35m-x86_64-linux-gnu.so 27502 +usr/lib/python3/dist-packages/psutil/_psutil_posix.cpython-35m-x86_64-linux-gnu.so 27501 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor.pm 27500 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Delegation.pm 27499 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Util/TypeConstraints.pm 27498 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Union.pm 27497 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeCoercion/Union.pm 27496 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Parameterized.pm 27495 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Parameterizable.pm 27494 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Class.pm 27493 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Role.pm 27492 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Enum.pm 27491 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/DuckType.pm 27490 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/TypeConstraint/Registry.pm 27489 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Util/TypeConstraints/Builtins.pm 27488 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Mixin/AttributeCore.pm 27487 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Instance.pm 27486 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Object.pm 27485 +usr/share/perl/5.24.1/if.pm 27484 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role.pm 27483 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Attribute.pm 27482 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Method.pm 27481 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Method/Required.pm 27480 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Method/Conflicting.pm 27479 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Composite.pm 27477 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Application.pm 27476 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Application/RoleSummation.pm 27475 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Application/ToClass.pm 27474 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Application/ToRole.pm 27473 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Role/Application/ToInstance.pm 27472 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Attribute/Native.pm 27471 +lib/systemd/system/htpdate.service 27470 +etc/default/htpdate.pools 27469 +etc/default/htpdate.user-agent 27468 +usr/share/perl5/MooseX/Method/Signatures.pm 27466 +usr/lib/x86_64-linux-gnu/perl5/5.24/Devel/Declare.pm 27465 +usr/lib/x86_64-linux-gnu/perl5/5.24/B/Hooks/OP/Check.pm 27464 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/B/Hooks/OP/Check/Check.so 27463 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Devel/Declare/Declare.so 27462 +usr/share/perl5/MooseX/LazyRequire.pm 27461 +usr/share/perl5/aliased.pm 27460 +usr/share/perl5/MooseX/LazyRequire/Meta/Attribute/Trait/LazyRequire.pm 27459 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Role.pm 27458 +usr/share/perl5/MooseX/Types/Moose.pm 27457 +usr/share/perl5/MooseX/Types.pm 27456 +usr/share/perl5/MooseX/Types/TypeDecorator.pm 27455 +usr/share/perl5/Carp/Clan.pm 27454 +usr/share/perl5/MooseX/Types/Base.pm 27453 +usr/share/perl5/MooseX/Types/Util.pm 27452 +usr/share/perl5/MooseX/Types/UndefinedType.pm 27451 +usr/share/perl5/MooseX/Types/CheckedUtilExports.pm 27450 +usr/share/perl5/Sub/Exporter/ForMethods.pm 27449 +usr/share/perl/5.24.1/Text/Balanced.pm 27448 +usr/share/perl/5.24.1/SelfLoader.pm 27447 +usr/share/perl5/MooseX/Method/Signatures/Meta/Method.pm 27446 +usr/share/perl5/Context/Preserve.pm 27445 +usr/share/perl5/Parse/Method/Signatures.pm 27444 +usr/share/perl5/PPI.pm 27443 +usr/share/perl5/PPI/Util.pm 27442 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Digest/MD5.pm 27441 +usr/share/perl/5.24.1/Digest/base.pm 27440 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Digest/MD5/MD5.so 27439 +usr/share/perl5/PPI/Exception.pm 27438 +usr/share/perl5/PPI/Element.pm 27437 +usr/lib/x86_64-linux-gnu/perl5/5.24/Clone.pm 27436 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Clone/Clone.so 27435 +usr/lib/x86_64-linux-gnu/perl5/5.24/List/MoreUtils.pm 27434 +usr/lib/x86_64-linux-gnu/perl5/5.24/List/MoreUtils/PP.pm 27433 +usr/lib/x86_64-linux-gnu/perl5/5.24/List/MoreUtils/XS.pm 27432 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/List/MoreUtils/MoreUtils.so 27431 +usr/share/perl5/Exporter/Tiny.pm 27430 +usr/share/perl5/PPI/Node.pm 27429 +usr/share/perl5/PPI/Token.pm 27428 +usr/share/perl5/PPI/Token/BOM.pm 27427 +usr/share/perl5/PPI/Token/Whitespace.pm 27426 +usr/share/perl5/PPI/Token/Comment.pm 27425 +usr/share/perl5/PPI/Token/Pod.pm 27424 +usr/share/perl5/PPI/Token/Number.pm 27423 +usr/share/perl5/PPI/Token/Number/Binary.pm 27422 +usr/share/perl5/PPI/Token/Number/Octal.pm 27421 +usr/share/perl5/PPI/Token/Number/Hex.pm 27420 +usr/share/perl5/PPI/Token/Number/Float.pm 27419 +usr/share/perl5/PPI/Token/Number/Exp.pm 27418 +usr/share/perl5/PPI/Token/Number/Version.pm 27417 +usr/share/perl5/PPI/Token/Word.pm 27416 +usr/share/perl5/PPI/Token/DashedWord.pm 27415 +usr/share/perl5/PPI/Token/Symbol.pm 27414 +usr/share/perl5/PPI/Token/ArrayIndex.pm 27413 +usr/share/perl5/PPI/Token/Magic.pm 27412 +usr/share/perl5/PPI/Token/Unknown.pm 27411 +usr/share/perl5/PPI/Token/Quote/Single.pm 27410 +usr/share/perl5/PPI/Token/Quote.pm 27409 +usr/share/perl5/PPI/Token/_QuoteEngine/Simple.pm 27408 +usr/share/perl5/PPI/Token/_QuoteEngine.pm 27407 +usr/share/perl5/PPI/Token/Quote/Double.pm 27406 +usr/share/perl5/PPI/Token/Quote/Literal.pm 27405 +usr/share/perl5/PPI/Token/_QuoteEngine/Full.pm 27404 +usr/share/perl5/PPI/Token/Quote/Interpolate.pm 27403 +usr/share/perl5/PPI/Token/QuoteLike/Backtick.pm 27402 +usr/share/perl5/PPI/Token/QuoteLike.pm 27401 +usr/share/perl5/PPI/Token/QuoteLike/Command.pm 27400 +usr/share/perl5/PPI/Token/QuoteLike/Regexp.pm 27399 +usr/share/perl5/PPI/Token/QuoteLike/Words.pm 27398 +usr/share/perl5/PPI/Token/QuoteLike/Readline.pm 27397 +usr/share/perl5/PPI/Token/Regexp/Match.pm 27396 +usr/share/perl5/PPI/Token/Regexp.pm 27395 +usr/share/perl5/PPI/Token/Regexp/Substitute.pm 27394 +usr/share/perl5/PPI/Token/Regexp/Transliterate.pm 27393 +usr/share/perl5/PPI/Token/Operator.pm 27392 +usr/share/perl5/PPI/Token/Cast.pm 27391 +usr/share/perl5/PPI/Token/Structure.pm 27390 +usr/share/perl5/PPI/Token/Label.pm 27389 +usr/share/perl5/PPI/Token/HereDoc.pm 27388 +usr/share/perl5/PPI/Token/Separator.pm 27387 +usr/share/perl5/PPI/Token/Data.pm 27386 +usr/share/perl5/IO/String.pm 27385 +usr/share/perl5/PPI/Token/End.pm 27384 +usr/share/perl5/PPI/Token/Prototype.pm 27383 +usr/share/perl5/PPI/Token/Attribute.pm 27382 +usr/share/perl5/PPI/Statement.pm 27381 +usr/share/perl5/PPI/Statement/Break.pm 27380 +usr/share/perl5/PPI/Statement/Compound.pm 27379 +usr/share/perl5/PPI/Statement/Data.pm 27378 +usr/share/perl5/PPI/Statement/End.pm 27377 +usr/share/perl5/PPI/Statement/Expression.pm 27376 +usr/share/perl5/PPI/Statement/Include.pm 27375 +usr/share/perl5/PPI/Statement/Include/Perl6.pm 27374 +usr/share/perl5/PPI/Statement/Null.pm 27373 +usr/share/perl5/PPI/Statement/Package.pm 27372 +usr/share/perl5/PPI/Statement/Scheduled.pm 27371 +usr/share/perl5/PPI/Statement/Sub.pm 27370 +usr/share/perl5/PPI/Statement/Given.pm 27369 +usr/share/perl5/PPI/Statement/UnmatchedBrace.pm 27368 +usr/share/perl5/PPI/Statement/Unknown.pm 27367 +usr/share/perl5/PPI/Statement/Variable.pm 27366 +usr/share/perl5/PPI/Statement/When.pm 27365 +usr/share/perl5/PPI/Structure.pm 27364 +usr/share/perl5/PPI/Structure/Block.pm 27363 +usr/share/perl5/PPI/Structure/Condition.pm 27362 +usr/share/perl5/PPI/Structure/Constructor.pm 27361 +usr/share/perl5/PPI/Structure/For.pm 27360 +usr/share/perl5/PPI/Structure/Given.pm 27359 +usr/share/perl5/PPI/Structure/List.pm 27358 +usr/share/perl5/PPI/Structure/Subscript.pm 27357 +usr/share/perl5/PPI/Structure/Unknown.pm 27356 +usr/share/perl5/PPI/Structure/When.pm 27355 +usr/share/perl5/PPI/Document.pm 27354 +usr/share/perl5/PPI/Exception/ParserTimeout.pm 27353 +usr/share/perl5/PPI/Document/Fragment.pm 27352 +usr/share/perl5/PPI/Document/File.pm 27351 +usr/share/perl5/PPI/Document/Normalized.pm 27350 +usr/share/perl5/PPI/Normal.pm 27349 +usr/share/perl5/PPI/Normal/Standard.pm 27348 +usr/share/perl5/PPI/Tokenizer.pm 27347 +usr/share/perl5/PPI/Exception/ParserRejection.pm 27346 +usr/share/perl5/PPI/Lexer.pm 27345 +usr/share/perl5/Parse/Method/Signatures/ParamCollection.pm 27344 +usr/share/perl5/Parse/Method/Signatures/Types.pm 27343 +usr/share/perl5/Parse/Method/Signatures/TypeConstraint.pm 27341 +usr/share/perl5/MooseX/Meta/TypeConstraint/ForceCoercion.pm 27340 +usr/share/perl5/MooseX/Types/Structured.pm 27339 +usr/share/perl5/MooseX/Meta/TypeConstraint/Structured.pm 27338 +usr/share/perl5/Devel/PartialDump.pm 27337 +usr/share/perl5/Class/Tiny.pm 27336 +usr/share/perl/5.24.1/utf8_heavy.pl 27335 +usr/share/perl/5.24.1/unicore/Heavy.pl 27334 +usr/share/perl/5.24.1/unicore/lib/Perl/Print.pl 27333 +usr/share/perl5/MooseX/Meta/TypeCoercion/Structured.pm 27332 +usr/share/perl5/MooseX/Meta/TypeConstraint/Structured/Optional.pm 27331 +usr/share/perl5/MooseX/Meta/TypeCoercion/Structured/Optional.pm 27330 +usr/share/perl5/MooseX/Types/Structured/OverflowHandler.pm 27329 +usr/share/perl5/MooseX/Types/Structured/MessageStack.pm 27328 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Attribute/Native/Trait/Counter.pm 27327 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Attribute/Native/Trait.pm 27326 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Counter/dec.pm 27325 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Writer.pm 27324 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native.pm 27323 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Counter/inc.pm 27322 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Attribute/Native/Trait/Array.pm 27321 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array/push.pm 27320 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array/Writer.pm 27319 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array.pm 27318 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Collection.pm 27317 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array/elements.pm 27316 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Reader.pm 27315 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array/count.pm 27314 +usr/share/perl5/MooseX/Method/Signatures/Types.pm 27313 +usr/share/perl5/Parse/Method/Signatures/Param/Named.pm 27312 +usr/share/perl5/Parse/Method/Signatures/Param/Placeholder.pm 27311 +usr/lib/x86_64-linux-gnu/perl5/5.24/Devel/Declare/Context/Simple.pm 27309 +usr/share/perl5/MooseX/Has/Sugar/Saccharin.pm 27308 +usr/share/perl/5.24.1/autodie.pm 27307 +usr/share/perl/5.24.1/autodie/exception/system.pm 27306 +usr/share/perl/5.24.1/autodie/exception.pm 27305 +usr/lib/x86_64-linux-gnu/perl5/5.24/WWW/Curl/Easy.pm 27304 +usr/lib/x86_64-linux-gnu/perl5/5.24/WWW/Curl.pm 27303 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/WWW/Curl/Curl.so 27302 +usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4.4.0 27301 +usr/lib/x86_64-linux-gnu/libnghttp2.so.14.12.3 27300 +usr/lib/x86_64-linux-gnu/libidn2.so.0.1.4 27299 +usr/lib/x86_64-linux-gnu/librtmp.so.1 27298 +usr/lib/x86_64-linux-gnu/libssh2.so.1.0.1 27297 +usr/lib/x86_64-linux-gnu/libpsl.so.5.1.1 27296 +usr/lib/x86_64-linux-gnu/liblber-2.4.so.2.10.7 27295 +usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2.10.7 27294 +usr/lib/x86_64-linux-gnu/libsasl2.so.2.0.25 27293 +usr/share/perl5/Parse/Method/Signatures/Sig.pm 27292 +usr/share/perl5/Parse/Method/Signatures/Param.pm 27291 +usr/share/perl5/MooseX/Traits.pm 27290 +usr/share/perl5/MooseX/Traits/Util.pm 27289 +usr/share/perl5/Parse/Method/Signatures/Param/Positional.pm 27288 +usr/share/perl5/Parse/Method/Signatures/Param/Bindable.pm 27287 +usr/share/perl5/XML/Atom.pm 27285 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML.pm 27284 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/Error.pm 27283 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/NodeList.pm 27282 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/Boolean.pm 27281 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/Number.pm 27280 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/Literal.pm 27279 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/XPathContext.pm 27278 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/XML/LibXML/LibXML.so 27277 +usr/lib/x86_64-linux-gnu/perl5/5.24/XML/LibXML/AttributeHash.pm 27276 +usr/share/perl5/XML/SAX/Exception.pm 27275 +usr/share/perl5/XML/Atom/ErrorHandler.pm 27274 +usr/share/perl5/XML/Atom/Feed.pm 27273 +usr/share/perl5/XML/Atom/Thing.pm 27272 +usr/share/perl5/XML/Atom/Base.pm 27271 +usr/share/perl5/Class/Data/Inheritable.pm 27270 +usr/share/perl5/XML/Atom/Util.pm 27269 +usr/share/perl5/XML/Atom/Category.pm 27268 +usr/share/perl5/XML/Atom/Link.pm 27267 +usr/share/perl5/LWP/UserAgent.pm 27266 +usr/share/perl5/HTTP/Request.pm 27265 +usr/share/perl5/HTTP/Message.pm 27264 +usr/share/perl5/HTTP/Headers.pm 27263 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Storable.pm 27262 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Storable/Storable.so 27261 +usr/share/perl5/HTTP/Response.pm 27260 +usr/share/perl5/HTTP/Status.pm 27259 +usr/share/perl5/HTTP/Date.pm 27258 +usr/share/perl/5.24.1/Time/Local.pm 27257 +usr/share/perl5/LWP.pm 27256 +usr/share/perl5/LWP/Protocol.pm 27255 +usr/share/perl5/LWP/MemberMixin.pm 27254 +usr/share/perl5/XML/Atom/Entry.pm 27253 +usr/lib/x86_64-linux-gnu/perl/5.24.1/MIME/Base64.pm 27252 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/MIME/Base64/Base64.so 27251 +usr/share/perl5/XML/Atom/Person.pm 27250 +usr/share/perl5/XML/Atom/Content.pm 27249 +usr/local/sbin/htpdate 27245 +usr/share/perl/5.24.1/version.pm 27244 +usr/share/perl/5.24.1/version/regex.pm 27243 +usr/lib/x86_64-linux-gnu/perl5/5.24/DateTime.pm 27242 +usr/lib/x86_64-linux-gnu/perl5/5.24/DateTime/Duration.pm 27241 +usr/lib/x86_64-linux-gnu/perl5/5.24/DateTime/Helpers.pm 27240 +usr/lib/x86_64-linux-gnu/perl5/5.24/DateTime/Types.pm 27239 +usr/share/perl5/Specio/Exporter.pm 27238 +usr/share/perl5/Specio/Helpers.pm 27237 +usr/share/perl5/Specio/Registry.pm 27236 +usr/share/perl5/Specio.pm 27235 +usr/share/perl5/Specio/Declare.pm 27234 +usr/share/perl5/Specio/Coercion.pm 27233 +usr/share/perl5/Specio/OO.pm 27232 +usr/share/perl5/Role/Tiny.pm 27231 +usr/share/perl5/Specio/PartialDump.pm 27230 +usr/share/perl5/Specio/TypeChecks.pm 27229 +usr/share/perl5/Role/Tiny/With.pm 27228 +usr/share/perl5/Specio/Role/Inlinable.pm 27227 +usr/share/perl5/Specio/Constraint/Simple.pm 27226 +usr/share/perl5/Specio/Constraint/Role/Interface.pm 27225 +usr/share/perl5/Specio/Exception.pm 27224 +usr/share/perl5/Devel/StackTrace.pm 27223 +usr/share/perl5/Devel/StackTrace/Frame.pm 27222 +usr/local/etc/ssl/certs/tails.boum.org-CA.pem 27221 +usr/share/perl5/Specio/DeclaredAt.pm 27220 +usr/share/perl5/Specio/Library/Builtins.pm 27219 +usr/share/perl5/Specio/Constraint/Parameterizable.pm 27218 +usr/share/perl5/Specio/Constraint/Parameterized.pm 27217 +usr/share/perl5/Specio/Library/Numeric.pm 27216 +usr/share/perl5/Specio/Library/String.pm 27215 +usr/share/perl5/Specio/Constraint/AnyCan.pm 27214 +usr/share/perl5/Specio/Constraint/Role/CanType.pm 27213 +usr/share/perl5/Specio/Constraint/ObjectIsa.pm 27212 +usr/share/perl5/Specio/Constraint/Role/IsaType.pm 27211 +usr/share/perl5/Specio/Constraint/Enum.pm 27210 +usr/share/perl5/Specio/Constraint/Union.pm 27209 +usr/share/perl5/Specio/Constraint/ObjectCan.pm 27208 +usr/share/perl5/Params/ValidationCompiler.pm 27207 +usr/share/perl5/Params/ValidationCompiler/Compiler.pm 27206 +usr/share/perl5/Params/ValidationCompiler/Exceptions.pm 27205 +usr/share/perl5/Exception/Class.pm 27204 +usr/share/perl5/Exception/Class/Base.pm 27203 +usr/share/perl5/DateTime/Locale.pm 27202 +usr/share/perl5/DateTime/Locale/Data.pm 27201 +usr/share/perl5/DateTime/Locale/FromData.pm 27200 +usr/share/perl5/DateTime/Locale/Util.pm 27199 +usr/share/perl5/DateTime/TimeZone.pm 27198 +usr/share/perl5/DateTime/TimeZone/Catalog.pm 27197 +usr/share/perl5/DateTime/TimeZone/Floating.pm 27196 +usr/share/perl5/Class/Singleton.pm 27195 +usr/share/perl5/DateTime/TimeZone/OffsetOnly.pm 27194 +usr/share/perl5/DateTime/TimeZone/UTC.pm 27193 +usr/share/perl5/DateTime/TimeZone/Local.pm 27192 +usr/share/perl5/DateTime/TimeZone/OlsonDB/Change.pm 27191 +usr/share/perl/5.24.1/integer.pm 27190 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/DateTime/DateTime.so 27189 +usr/lib/x86_64-linux-gnu/perl5/5.24/DateTime/Infinite.pm 27188 +usr/share/perl5/DateTime/Format/DateParse.pm 27187 +usr/share/perl5/Date/Parse.pm 27186 +usr/share/perl5/Time/Zone.pm 27185 +usr/lib/x86_64-linux-gnu/perl/5.24.1/File/Spec/Functions.pm 27184 +usr/share/perl5/Getopt/Long/Descriptive.pm 27183 +usr/lib/x86_64-linux-gnu/perl5/5.24/Params/Validate.pm 27182 +usr/lib/x86_64-linux-gnu/perl5/5.24/Params/Validate/Constants.pm 27181 +usr/lib/x86_64-linux-gnu/perl5/5.24/Params/Validate/XS.pm 27180 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Params/Validate/XS/XS.so 27179 +usr/share/perl5/Getopt/Long/Descriptive/Opts.pm 27178 +usr/share/perl5/Getopt/Long/Descriptive/Usage.pm 27177 +usr/share/perl5/Sub/Exporter/Util.pm 27176 +usr/share/perl/5.24.1/open.pm 27175 +usr/lib/x86_64-linux-gnu/perl/5.24.1/threads.pm 27174 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/threads/threads.so 27173 +usr/bin/curl 27172 +usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 27171 +usr/lib/x86_64-linux-gnu/libssl.so.1.0.2 27170 +usr/local/sbin/tor-has-bootstrapped 27167 +usr/bin/gettext 27166 +usr/local/sbin/tails-notify-user 27165 +lib/systemd/system/tails-additional-software-upgrade.path 27164 +lib/systemd/system/tails-additional-software-upgrade.service 27163 +usr/bin/notify-send 27155 +usr/local/lib/tor-browser/browser/chrome/icons/default/default128.png 27148 +usr/lib/ibus/ibus-engine-libpinyin 27147 +usr/lib/x86_64-linux-gnu/libpinyin.so.7.0.0 27146 +usr/lib/ibus/ibus-engine-hangul 27145 +usr/lib/x86_64-linux-gnu/libhangul.so.1.0.0 27144 +usr/lib/x86_64-linux-gnu/liblua5.1.so.0.0.0 27143 +usr/lib/x86_64-linux-gnu/libdb-5.3.so 27142 +usr/lib/ibus/ibus-engine-chewing 27141 +usr/lib/x86_64-linux-gnu/libchewing.so.3.3.1 27140 +usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0.2400.31 27139 +usr/share/libhangul/hanja/hanja.txt 27138 +usr/lib/x86_64-linux-gnu/libgdk-x11-2.0.so.0.2400.31 27137 +usr/lib/x86_64-linux-gnu/gtk-2.0/modules/libgail.so 27136 +usr/lib/x86_64-linux-gnu/libgailutil.so.18.0.1 27135 +usr/lib/x86_64-linux-gnu/gtk-2.0/modules/libatk-bridge.so 27134 +usr/share/themes/Adwaita/gtk-2.0/gtkrc 27133 +usr/share/themes/Adwaita/gtk-2.0/main.rc 27132 +usr/lib/x86_64-linux-gnu/gtk-2.0/2.10.0/engines/libadwaita.so 27131 +usr/lib/x86_64-linux-gnu/gtk-2.0/2.10.0/engines/libpixmap.so 27130 +usr/share/themes/Adwaita/gtk-2.0/apps.rc 27129 +usr/share/themes/Adwaita/gtk-2.0/hacks.rc 27128 +usr/share/themes/Default/gtk-2.0-key/gtkrc 27127 +usr/share/ibus-hangul/data/symbol.txt 27126 +usr/bin/xhost 27124 +usr/bin/tails-upgrade-frontend 27123 +usr/share/perl/5.24.1/FindBin.pm 27122 +usr/lib/x86_64-linux-gnu/perl/5.24.1/lib.pm 27121 +usr/share/perl5/Tails/IUK/Frontend.pm 27120 +usr/share/perl5/MooseX/Types/Path/Class.pm 27119 +usr/share/perl5/Path/Class.pm 27118 +usr/share/perl5/Path/Class/File.pm 27117 +usr/share/perl5/Path/Class/Dir.pm 27116 +usr/share/perl5/Path/Class/Entity.pm 27115 +usr/share/perl/5.24.1/File/stat.pm 27114 +usr/share/perl/5.24.1/Class/Struct.pm 27113 +usr/lib/x86_64-linux-gnu/perl/5.24.1/IO/Dir.pm 27112 +usr/share/perl5/MooseX/Getopt.pm 27111 +usr/share/perl5/MooseX/Getopt/GLD.pm 27110 +usr/share/perl5/MooseX/Role/Parameterized.pm 27109 +usr/share/perl5/MooseX/Role/Parameterized/Meta/Trait/Parameterizable.pm 27108 +usr/share/perl5/MooseX/Role/Parameterized/Meta/Role/Parameterized.pm 27107 +usr/share/perl5/MooseX/Role/Parameterized/Meta/Trait/Parameterized.pm 27106 +usr/share/perl5/MooseX/Role/Parameterized/Parameters.pm 27105 +usr/share/perl5/MooseX/Getopt/Basic.pm 27104 +usr/share/perl5/MooseX/Getopt/OptionTypeMap.pm 27103 +usr/share/perl5/MooseX/Getopt/Meta/Attribute.pm 27102 +usr/share/perl5/MooseX/Getopt/Meta/Attribute/Trait.pm 27101 +usr/share/perl5/MooseX/Getopt/Meta/Attribute/NoGetopt.pm 27100 +usr/share/perl5/MooseX/Getopt/Meta/Attribute/Trait/NoGetopt.pm 27099 +usr/share/perl5/MooseX/Getopt/ProcessedArgv.pm 27098 +usr/share/perl/5.24.1/Env.pm 27097 +usr/share/perl/5.24.1/Tie/Array.pm 27096 +usr/share/perl5/IPC/Run.pm 27095 +usr/share/perl5/IPC/Run/Debug.pm 27094 +usr/share/perl5/IPC/Run/IO.pm 27093 +usr/share/perl5/IPC/Run/Timer.pm 27092 +usr/share/perl5/Number/Format.pm 27091 +usr/share/perl5/String/Errf.pm 27090 +usr/share/perl5/String/Formatter.pm 27089 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Time/Piece.pm 27088 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Time/Seconds.pm 27087 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Time/Piece/Piece.so 27086 +usr/share/perl5/Tails/RunningSystem.pm 27085 +usr/lib/x86_64-linux-gnu/perl5/5.24/Function/Parameters.pm 27084 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Function/Parameters/Parameters.so 27083 +usr/share/perl5/Path/Tiny.pm 27082 +usr/share/perl5/Sys/Statistics/Linux/MemStats.pm 27081 +usr/share/perl5/Tails/Constants.pm 27080 +usr/share/perl5/Moo/HandleMoose.pm 27079 +usr/share/perl5/Moo/HandleMoose/FakeMetaClass.pm 27078 +usr/share/perl5/Type/Utils.pm 27077 +usr/share/perl5/Type/Library.pm 27076 +usr/share/perl5/Eval/TypeTiny.pm 27075 +usr/share/perl5/Type/Tiny.pm 27074 +usr/share/perl5/Types/TypeTiny.pm 27073 +usr/lib/x86_64-linux-gnu/perl5/5.24/Type/Tiny/XS.pm 27072 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Type/Tiny/XS/XS.so 27071 +usr/share/perl5/Type/Registry.pm 27070 +usr/share/perl5/Type/Parser.pm 27069 +usr/share/perl5/Types/Standard.pm 27068 +usr/share/perl5/Type/Coercion.pm 27067 +usr/share/perl5/Tails/UDisks.pm 27066 +usr/share/perl5/Syntax/Keyword/Junction.pm 27065 +usr/share/perl5/Syntax/Keyword/Junction/All.pm 27064 +usr/share/perl5/Syntax/Keyword/Junction/Base.pm 27063 +usr/share/perl5/Syntax/Keyword/Junction/Any.pm 27062 +usr/share/perl5/Syntax/Keyword/Junction/None.pm 27061 +usr/share/perl5/Syntax/Keyword/Junction/One.pm 27060 +usr/share/perl5/Types/Path/Tiny.pm 27059 +usr/share/perl5/Type/Tiny/Class.pm 27058 +usr/share/perl5/Type/Tiny/Intersection.pm 27057 +usr/lib/x86_64-linux-gnu/perl5/5.24/Unix/Mknod.pm 27056 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Unix/Mknod/Mknod.so 27055 +usr/share/perl5/Moo/Role.pm 27054 +usr/share/perl5/Tails/Role/HasDBus/System.pm 27053 +usr/lib/x86_64-linux-gnu/perl5/5.24/Net/DBus/GLib.pm 27052 +usr/lib/x86_64-linux-gnu/perl5/5.24/Glib.pm 27051 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Glib/Glib.so 27050 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Net/DBus/GLib/GLib.so 27049 +usr/share/perl5/Tails.pm 27048 +usr/share/perl5/Tails/Role/HasEncoding.pm 27047 +usr/share/perl5/Tails/Role/HasCodeset.pm 27046 +usr/share/perl5/Type/Tiny/Union.pm 27045 +usr/share/perl5/Tails/Role/DisplayError/Gtk3.pm 27044 +usr/lib/x86_64-linux-gnu/perl5/5.24/Cairo/GObject.pm 27043 +usr/lib/x86_64-linux-gnu/perl5/5.24/Cairo.pm 27042 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Cairo/Cairo.so 27041 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Cairo/GObject/GObject.so 27040 +usr/lib/x86_64-linux-gnu/perl5/5.24/Glib/Object/Introspection.pm 27039 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Glib/Object/Introspection/Introspection.so 27038 +usr/share/perl5/Tails/IUK/UpgradeDescriptionFile.pm 27037 +usr/share/perl5/Dpkg/Version.pm 27036 +usr/share/perl5/Dpkg/Gettext.pm 27035 +usr/share/perl5/Dpkg/ErrorHandling.pm 27034 +usr/share/perl/5.24.1/Term/ANSIColor.pm 27033 +usr/share/perl5/Dpkg.pm 27032 +usr/share/perl5/YAML/Any.pm 27031 +usr/lib/x86_64-linux-gnu/perl5/5.24/YAML/XS.pm 27030 +usr/lib/x86_64-linux-gnu/perl5/5.24/YAML/XS/LibYAML.pm 27029 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/YAML/XS/LibYAML/LibYAML.so 27028 +usr/lib/x86_64-linux-gnu/perl5/5.24/Moose/Meta/Method/Accessor/Native/Array/clear.pm 27027 +usr/share/perl5/Tails/IUK/Utils.pm 27026 +usr/share/perl/5.24.1/Archive/Tar.pm 27025 +usr/share/perl/5.24.1/IO/Zlib.pm 27024 +usr/share/perl/5.24.1/Compress/Zlib.pm 27023 +usr/share/perl/5.24.1/IO/Compress/Base/Common.pm 27022 +usr/share/perl/5.24.1/File/GlobMapper.pm 27021 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Compress/Raw/Zlib.pm 27020 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Compress/Raw/Zlib/Zlib.so 27019 +usr/share/perl/5.24.1/IO/Compress/Gzip.pm 27018 +usr/share/perl/5.24.1/IO/Compress/RawDeflate.pm 27017 +usr/share/perl/5.24.1/IO/Compress/Base.pm 27016 +usr/share/perl/5.24.1/IO/Compress/Adapter/Deflate.pm 27015 +usr/share/perl/5.24.1/IO/Compress/Gzip/Constants.pm 27014 +usr/share/perl/5.24.1/IO/Compress/Zlib/Extra.pm 27013 +usr/share/perl/5.24.1/IO/Uncompress/Gunzip.pm 27012 +usr/share/perl/5.24.1/IO/Uncompress/RawInflate.pm 27011 +usr/share/perl/5.24.1/IO/Uncompress/Base.pm 27010 +usr/share/perl/5.24.1/IO/Uncompress/Adapter/Inflate.pm 27009 +usr/share/perl/5.24.1/Tie/Handle.pm 27008 +usr/share/perl/5.24.1/Tie/StdHandle.pm 27007 +usr/share/perl/5.24.1/Archive/Tar/File.pm 27006 +usr/share/perl/5.24.1/Archive/Tar/Constant.pm 27005 +usr/share/perl/5.24.1/IO/Uncompress/Bunzip2.pm 27004 +usr/share/perl/5.24.1/IO/Uncompress/Adapter/Bunzip2.pm 27003 +usr/lib/x86_64-linux-gnu/perl/5.24.1/Compress/Raw/Bzip2.pm 27002 +usr/lib/x86_64-linux-gnu/perl/5.24.1/auto/Compress/Raw/Bzip2/Bzip2.so 27001 +usr/share/perl/5.24.1/IO/Compress/Bzip2.pm 27000 +usr/share/perl/5.24.1/IO/Compress/Adapter/Bzip2.pm 26999 +usr/share/perl/5.24.1/Math/BigInt.pm 26998 +usr/share/perl/5.24.1/Math/BigInt/Calc.pm 26997 +usr/share/perl5/GnuPG/Options.pm 26996 +usr/share/perl5/MooX/HandlesVia.pm 26995 +usr/share/perl5/GnuPG/HashInit.pm 26994 +usr/share/perl5/Data/Perl/Collection/Array/MooseLike.pm 26993 +usr/share/perl5/strictures.pm 26992 +usr/share/perl5/Class/Method/Modifiers.pm 26991 +usr/share/perl5/Data/Perl/Role/Collection/Array.pm 26990 +usr/share/perl5/GnuPG/Handles.pm 26989 +usr/lib/x86_64-linux-gnu/perl5/5.24/Filesys/Df.pm 26988 +usr/lib/x86_64-linux-gnu/perl5/5.24/auto/Filesys/Df/Df.so 26987 +usr/share/perl5/Method/Signatures/Simple.pm 26986 +usr/lib/x86_64-linux-gnu/perl5/5.24/Devel/Declare/MethodInstaller/Simple.pm 26985 +usr/share/perl5/Tails/MirrorPool.pm 26984 +usr/share/perl5/MooseX/Getopt/Dashes.pm 26983 +usr/bin/tails-iuk-get-upgrade-description-file 26982 +usr/share/perl5/Tails/IUK/UpgradeDescriptionFile/Download.pm 26981 +usr/share/perl5/Method/Generate/BuildAll.pm 26980 +etc/xdg/menus/gnome-applications.menu 26978 +etc/xdg/menus/applications-merged/Tails.menu 26977 +usr/share/icons/hicolor/32x32/apps/thunderbird.png 26976 +usr/share/icons/hicolor/32x32/apps/pidgin.png 26975 +usr/share/icons/hicolor/32x32/apps/keepassx.png 26974 +usr/share/icons/Adwaita/32x32/apps/utilities-terminal.png 26973 +usr/local/bin/tor-browser 26971 +usr/local/lib/tails-shell-library/tor-browser.sh 26970 +etc/tor-browser/locale-profiles/en-US.js 26969 +usr/local/lib/tor-browser/firefox.real 26968 +usr/local/lib/tor-browser/dependentlibs.list 26967 +usr/local/lib/tor-browser/libnspr4.so 26966 +usr/local/lib/tor-browser/libplc4.so 26965 +usr/local/lib/tor-browser/libplds4.so 26964 +usr/local/lib/tor-browser/libmozsandbox.so 26963 +usr/local/lib/tor-browser/liblgpllibs.so 26962 +usr/local/lib/tor-browser/libnssutil3.so 26961 +usr/local/lib/tor-browser/libnss3.so 26960 +usr/local/lib/tor-browser/libsmime3.so 26959 +usr/local/lib/tor-browser/libmozsqlite3.so 26958 +usr/local/lib/tor-browser/libssl3.so 26957 +usr/local/lib/tor-browser/libmozgtk.so 26956 +usr/local/lib/tor-browser/libxul.so 26955 +usr/lib/x86_64-linux-gnu/libXt.so.6.0.0 26954 +usr/lib/x86_64-linux-gnu/dri/i915_dri.so 26953 +usr/lib/x86_64-linux-gnu/dri/swrast_dri.so 26952 +usr/lib/x86_64-linux-gnu/libsensors.so.4.4.0 26951 +usr/lib/x86_64-linux-gnu/libdrm_amdgpu.so.1.0.0 26950 +usr/lib/x86_64-linux-gnu/libelf-0.168.so 26949 +usr/lib/x86_64-linux-gnu/libLLVM-6.0.so.1 26948 +usr/lib/x86_64-linux-gnu/libedit.so.2.0.55 26947 +lib/x86_64-linux-gnu/libncurses.so.5.9 26946 +usr/local/lib/tor-browser/TorBrowser/Data/Browser/profiles.ini 26945 +usr/local/lib/tor-browser/omni.ja 26944 +usr/local/lib/tor-browser/browser/omni.ja 26943 +usr/local/lib/tor-browser/chrome.manifest 26942 +usr/local/lib/tor-browser/defaults/pref/channel-prefs.js 26941 +usr/local/lib/tor-browser/browser/chrome.manifest 26940 +etc/ld.so.conf 26939 +etc/ld.so.conf.d/libc.conf 26938 +etc/ld.so.conf.d/x86_64-linux-gnu.conf 26937 +usr/bin/lsb_release 26936 +usr/local/lib/tor-browser/browser/blocklist.xml 26935 +usr/local/share/tor-browser-extensions/{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi 26934 +usr/local/lib/tor-browser/libsoftokn3.so 26933 +usr/local/lib/tor-browser/libfreeblpriv3.so 26932 +usr/local/lib/tor-browser/libnssckbi.so 26931 +usr/share/webext/ublock-origin/manifest.json 26930 +usr/share/webext/ublock-origin/_locales/en/messages.json 26929 +usr/share/webext/ublock-origin/_locales/ar/messages.json 26928 +usr/share/webext/ublock-origin/_locales/az/messages.json 26927 +usr/share/webext/ublock-origin/_locales/bg/messages.json 26926 +usr/share/webext/ublock-origin/_locales/bn/messages.json 26925 +usr/share/webext/ublock-origin/_locales/ca/messages.json 26924 +usr/share/webext/ublock-origin/_locales/cs/messages.json 26923 +usr/share/webext/ublock-origin/_locales/cv/messages.json 26922 +usr/share/webext/ublock-origin/_locales/da/messages.json 26921 +usr/share/webext/ublock-origin/_locales/el/messages.json 26920 +usr/share/webext/ublock-origin/_locales/de/messages.json 26919 +usr/share/webext/ublock-origin/_locales/eo/messages.json 26918 +usr/share/webext/ublock-origin/_locales/es/messages.json 26917 +usr/share/webext/ublock-origin/_locales/et/messages.json 26916 +usr/share/webext/ublock-origin/_locales/eu/messages.json 26915 +usr/share/webext/ublock-origin/_locales/fa/messages.json 26914 +usr/share/webext/ublock-origin/_locales/fi/messages.json 26913 +usr/share/webext/ublock-origin/_locales/fil/messages.json 26912 +usr/share/webext/ublock-origin/_locales/fy/messages.json 26911 +usr/share/webext/ublock-origin/_locales/fr/messages.json 26910 +usr/share/webext/ublock-origin/_locales/gl/messages.json 26909 +usr/share/webext/ublock-origin/_locales/he/messages.json 26908 +usr/share/webext/ublock-origin/_locales/hi/messages.json 26907 +usr/share/webext/ublock-origin/_locales/hr/messages.json 26906 +usr/share/webext/ublock-origin/_locales/hu/messages.json 26905 +usr/share/webext/ublock-origin/_locales/id/messages.json 26904 +usr/share/webext/ublock-origin/_locales/it/messages.json 26903 +usr/share/webext/ublock-origin/_locales/ja/messages.json 26902 +usr/share/webext/ublock-origin/_locales/ka/messages.json 26901 +usr/share/webext/ublock-origin/_locales/kk/messages.json 26900 +usr/share/webext/ublock-origin/_locales/kn/messages.json 26899 +usr/share/webext/ublock-origin/_locales/ko/messages.json 26898 +usr/share/webext/ublock-origin/_locales/lt/messages.json 26897 +usr/share/webext/ublock-origin/_locales/ml/messages.json 26896 +usr/share/webext/ublock-origin/_locales/mr/messages.json 26895 +usr/share/webext/ublock-origin/_locales/ms/messages.json 26894 +usr/share/webext/ublock-origin/_locales/nb/messages.json 26893 +usr/share/webext/ublock-origin/_locales/lv/messages.json 26892 +usr/share/webext/ublock-origin/_locales/nl/messages.json 26891 +usr/share/webext/ublock-origin/_locales/no/messages.json 26890 +usr/share/webext/ublock-origin/_locales/pl/messages.json 26889 +usr/share/webext/ublock-origin/_locales/pt_BR/messages.json 26888 +usr/share/webext/ublock-origin/_locales/pt_PT/messages.json 26887 +usr/share/webext/ublock-origin/_locales/ro/messages.json 26886 +usr/share/webext/ublock-origin/_locales/ru/messages.json 26885 +usr/share/webext/ublock-origin/_locales/sk/messages.json 26884 +usr/share/webext/ublock-origin/_locales/sl/messages.json 26883 +usr/share/webext/ublock-origin/_locales/sq/messages.json 26882 +usr/share/webext/ublock-origin/_locales/sr/messages.json 26881 +usr/share/webext/ublock-origin/_locales/sv/messages.json 26880 +usr/share/webext/ublock-origin/_locales/ta/messages.json 26879 +usr/share/webext/ublock-origin/_locales/te/messages.json 26878 +usr/share/webext/ublock-origin/_locales/th/messages.json 26877 +usr/share/webext/ublock-origin/_locales/tr/messages.json 26876 +usr/share/webext/ublock-origin/_locales/uk/messages.json 26875 +usr/share/webext/ublock-origin/_locales/vi/messages.json 26874 +usr/share/webext/ublock-origin/_locales/zh_CN/messages.json 26873 +usr/share/webext/ublock-origin/_locales/zh_TW/messages.json 26872 +usr/local/share/tor-browser-extensions/torbutton@torproject.org.xpi 26871 +usr/local/share/tor-browser-extensions/langpack-zh-TW@firefox.mozilla.org.xpi 26870 +usr/local/share/tor-browser-extensions/langpack-zh-CN@firefox.mozilla.org.xpi 26869 +usr/local/share/tor-browser-extensions/langpack-vi@firefox.mozilla.org.xpi 26868 +usr/local/share/tor-browser-extensions/langpack-tr@firefox.mozilla.org.xpi 26867 +usr/local/share/tor-browser-extensions/langpack-sv-SE@firefox.mozilla.org.xpi 26866 +usr/local/share/tor-browser-extensions/langpack-ru@firefox.mozilla.org.xpi 26865 +usr/local/share/tor-browser-extensions/langpack-pt-BR@firefox.mozilla.org.xpi 26864 +usr/local/share/tor-browser-extensions/langpack-pl@firefox.mozilla.org.xpi 26863 +usr/local/share/tor-browser-extensions/langpack-nl@firefox.mozilla.org.xpi 26862 +usr/local/share/tor-browser-extensions/langpack-nb-NO@firefox.mozilla.org.xpi 26861 +usr/local/share/tor-browser-extensions/langpack-ko@firefox.mozilla.org.xpi 26860 +usr/local/share/tor-browser-extensions/langpack-ka@firefox.mozilla.org.xpi 26859 +usr/local/share/tor-browser-extensions/langpack-ja@firefox.mozilla.org.xpi 26858 +usr/local/share/tor-browser-extensions/langpack-it@firefox.mozilla.org.xpi 26857 +usr/local/share/tor-browser-extensions/langpack-is@firefox.mozilla.org.xpi 26856 +usr/local/share/tor-browser-extensions/langpack-id@firefox.mozilla.org.xpi 26855 +usr/local/share/tor-browser-extensions/langpack-hu@firefox.mozilla.org.xpi 26854 +usr/local/share/tor-browser-extensions/langpack-he@firefox.mozilla.org.xpi 26853 +usr/local/share/tor-browser-extensions/langpack-ga-IE@firefox.mozilla.org.xpi 26852 +usr/local/share/tor-browser-extensions/langpack-fr@firefox.mozilla.org.xpi 26851 +usr/local/share/tor-browser-extensions/langpack-fa@firefox.mozilla.org.xpi 26850 +usr/local/share/tor-browser-extensions/langpack-es-ES@firefox.mozilla.org.xpi 26849 +usr/local/share/tor-browser-extensions/langpack-es-AR@firefox.mozilla.org.xpi 26848 +usr/local/share/tor-browser-extensions/langpack-el@firefox.mozilla.org.xpi 26847 +usr/local/share/tor-browser-extensions/langpack-de@firefox.mozilla.org.xpi 26846 +usr/local/share/tor-browser-extensions/langpack-da@firefox.mozilla.org.xpi 26845 +usr/local/share/tor-browser-extensions/langpack-cs@firefox.mozilla.org.xpi 26844 +usr/local/share/tor-browser-extensions/langpack-ca@firefox.mozilla.org.xpi 26843 +usr/local/share/tor-browser-extensions/langpack-ar@firefox.mozilla.org.xpi 26842 +usr/local/share/tor-browser-extensions/https-everywhere-eff@eff.org.xpi 26841 +usr/local/lib/tor-browser/browser/features/onboarding@mozilla.org.xpi 26840 +usr/local/lib/tor-browser/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}.xpi 26839 +usr/local/lib/tor-browser/TorBrowser/Data/fontconfig/fonts.conf 26838 +usr/local/lib/tor-browser/fonts/Arimo-Bold.ttf 26837 +usr/local/lib/tor-browser/fonts/Arimo-BoldItalic.ttf 26836 +usr/local/lib/tor-browser/fonts/Arimo-Italic.ttf 26835 +usr/local/lib/tor-browser/fonts/Arimo-Regular.ttf 26834 +usr/local/lib/tor-browser/fonts/Cousine-Regular.ttf 26833 +usr/local/lib/tor-browser/fonts/EmojiOneMozilla.ttf 26832 +usr/local/lib/tor-browser/fonts/NotoEmoji-Regular.ttf 26831 +usr/local/lib/tor-browser/fonts/NotoNaskhArabic-Regular.ttf 26830 +usr/local/lib/tor-browser/fonts/NotoSansArmenian-Regular.ttf 26829 +usr/local/lib/tor-browser/fonts/NotoSansBengali-Regular.ttf 26828 +usr/local/lib/tor-browser/fonts/NotoSansBuginese-Regular.ttf 26827 +usr/local/lib/tor-browser/fonts/NotoSansCanadianAboriginal-Regular.ttf 26826 +usr/local/lib/tor-browser/fonts/NotoSansCherokee-Regular.ttf 26825 +usr/local/lib/tor-browser/fonts/NotoSansDevanagari-Regular.ttf 26824 +usr/local/lib/tor-browser/fonts/NotoSansEthiopic-Regular.ttf 26823 +usr/local/lib/tor-browser/fonts/NotoSansGeorgian-Regular.ttf 26822 +usr/local/lib/tor-browser/fonts/NotoSansGujarati-Regular.ttf 26821 +usr/local/lib/tor-browser/fonts/NotoSansGurmukhi-Regular.ttf 26820 +usr/local/lib/tor-browser/fonts/NotoSansHebrew-Regular.ttf 26819 +usr/local/lib/tor-browser/fonts/NotoSansJP-Regular.otf 26818 +usr/local/lib/tor-browser/fonts/NotoSansKR-Regular.otf 26817 +usr/local/lib/tor-browser/fonts/NotoSansKannada-Regular.ttf 26816 +usr/local/lib/tor-browser/fonts/NotoSansKhmer-Regular.ttf 26815 +usr/local/lib/tor-browser/fonts/NotoSansLao-Regular.ttf 26814 +usr/local/lib/tor-browser/fonts/NotoSansMalayalam-Regular.ttf 26813 +usr/local/lib/tor-browser/fonts/NotoSansMongolian-Regular.ttf 26812 +usr/local/lib/tor-browser/fonts/NotoSansMyanmar-Regular.ttf 26811 +usr/local/lib/tor-browser/fonts/NotoSansOriya-Regular.ttf 26810 +usr/local/lib/tor-browser/fonts/NotoSansSC-Regular.otf 26809 +usr/local/lib/tor-browser/fonts/NotoSansSinhala-Regular.ttf 26808 +usr/local/lib/tor-browser/fonts/NotoSansTC-Regular.otf 26807 +usr/local/lib/tor-browser/fonts/NotoSansTamil-Regular.ttf 26806 +usr/local/lib/tor-browser/fonts/NotoSansTelugu-Regular.ttf 26805 +usr/local/lib/tor-browser/fonts/NotoSansThaana-Regular.ttf 26804 +usr/local/lib/tor-browser/fonts/NotoSansThai-Regular.ttf 26803 +usr/local/lib/tor-browser/fonts/NotoSansTibetan-Regular.ttf 26802 +usr/local/lib/tor-browser/fonts/NotoSansYi-Regular.ttf 26801 +usr/local/lib/tor-browser/fonts/NotoSerifArmenian-Regular.ttf 26800 +usr/local/lib/tor-browser/fonts/NotoSerifKhmer-Regular.ttf 26799 +usr/local/lib/tor-browser/fonts/NotoSerifLao-Regular.ttf 26798 +usr/local/lib/tor-browser/fonts/NotoSerifThai-Regular.ttf 26797 +usr/local/lib/tor-browser/fonts/STIXMath-Regular.otf 26796 +usr/local/lib/tor-browser/fonts/Tinos-Bold.ttf 26795 +usr/local/lib/tor-browser/fonts/Tinos-BoldItalic.ttf 26794 +usr/local/lib/tor-browser/fonts/Tinos-Italic.ttf 26793 +usr/local/lib/tor-browser/fonts/Tinos-Regular.ttf 26792 +usr/lib/locale/C.UTF-8/LC_IDENTIFICATION 26791 +usr/lib/locale/C.UTF-8/LC_MEASUREMENT 26790 +usr/lib/locale/C.UTF-8/LC_TELEPHONE 26789 +usr/lib/locale/C.UTF-8/LC_ADDRESS 26788 +usr/lib/locale/C.UTF-8/LC_NAME 26787 +usr/lib/locale/C.UTF-8/LC_PAPER 26786 +usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES 26785 +usr/lib/locale/C.UTF-8/LC_MONETARY 26784 +usr/lib/locale/C.UTF-8/LC_COLLATE 26783 +usr/lib/locale/C.UTF-8/LC_TIME 26782 +usr/lib/locale/C.UTF-8/LC_NUMERIC 26781 +usr/lib/locale/C.UTF-8/LC_CTYPE 26780 +usr/local/lib/tor-browser/browser/chrome/icons/default/default16.png 26779 +usr/local/lib/tor-browser/browser/chrome/icons/default/default32.png 26778 +usr/local/lib/tor-browser/browser/chrome/icons/default/default48.png 26777 +usr/local/lib/tor-browser/browser/chrome/icons/default/default64.png 26776 +etc/mime.types 26775 +etc/onion-grater.d/onioncircuits.yml 26774 +etc/onion-grater.d/onionshare.yml 26773 +etc/onion-grater.d/tor-browser.yml 26772 +etc/onion-grater.d/tor-launcher.yml 26771 +usr/lib/x86_64-linux-gnu/libXss.so.1.0.0 26770 +usr/share/icons/Adwaita/16x16/actions/window-maximize-symbolic.symbolic.png 26763 +usr/share/icons/Adwaita/16x16/actions/window-minimize-symbolic.symbolic.png 26762 +usr/share/webext/ublock-origin/img/icon_16.png 26761 +usr/share/webext/ublock-origin/background.html 26760 +usr/share/webext/ublock-origin/lib/lz4/lz4-block-codec-any.js 26759 +usr/share/webext/ublock-origin/lib/punycode.js 26758 +usr/share/webext/ublock-origin/lib/publicsuffixlist.js 26757 +usr/share/webext/ublock-origin/js/vapi.js 26756 +usr/share/webext/ublock-origin/js/vapi-common.js 26755 +usr/share/webext/ublock-origin/js/vapi-background.js 26754 +usr/share/webext/ublock-origin/js/vapi-webrequest.js 26753 +usr/share/webext/ublock-origin/js/background.js 26752 +usr/share/webext/ublock-origin/js/traffic.js 26751 +usr/share/webext/ublock-origin/js/hntrie.js 26750 +usr/share/webext/ublock-origin/js/utils.js 26749 +usr/share/webext/ublock-origin/js/uritools.js 26748 +usr/share/webext/ublock-origin/js/lz4.js 26747 +usr/share/webext/ublock-origin/js/cachestorage.js 26746 +usr/share/webext/ublock-origin/js/assets.js 26745 +usr/share/webext/ublock-origin/js/filtering-context.js 26744 +usr/share/webext/ublock-origin/js/redirect-engine.js 26743 +usr/share/webext/ublock-origin/js/dynamic-net-filtering.js 26742 +usr/share/webext/ublock-origin/js/static-net-filtering.js 26741 +usr/share/webext/ublock-origin/js/url-net-filtering.js 26740 +usr/share/webext/ublock-origin/js/static-ext-filtering.js 26739 +usr/share/webext/ublock-origin/js/cosmetic-filtering.js 26738 +usr/share/webext/ublock-origin/js/scriptlet-filtering.js 26737 +usr/share/webext/ublock-origin/js/html-filtering.js 26736 +usr/share/webext/ublock-origin/js/hnswitches.js 26735 +usr/share/webext/ublock-origin/js/ublock.js 26734 +usr/share/webext/ublock-origin/js/messaging.js 26733 +usr/share/webext/ublock-origin/js/storage.js 26732 +usr/share/webext/ublock-origin/js/logger.js 26731 +usr/share/webext/ublock-origin/js/pagestore.js 26730 +usr/share/webext/ublock-origin/js/tab.js 26729 +usr/share/webext/ublock-origin/js/text-encode.js 26728 +usr/share/webext/ublock-origin/js/contextmenu.js 26727 +usr/share/webext/ublock-origin/js/reverselookup.js 26726 +usr/share/webext/ublock-origin/js/start.js 26725 +usr/share/webext/ublock-origin/js/commands.js 26724 +usr/share/webext/ublock-origin/assets/assets.json 26723 +usr/share/webext/ublock-origin/assets/ublock/resources.txt 26722 +usr/share/webext/ublock-origin/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat 26721 +usr/share/webext/ublock-origin/web_accessible_resources/imported.txt 26720 +usr/share/webext/ublock-origin/lib/lz4/lz4-block-codec-wasm.js 26719 +usr/share/webext/ublock-origin/lib/lz4/lz4-block-codec-js.js 26718 +usr/share/webext/ublock-origin/assets/thirdparties/www.malwaredomainlist.com/hostslist/hosts.txt 26717 +usr/share/webext/ublock-origin/assets/thirdparties/easylist-downloads.adblockplus.org/easyprivacy.txt 26716 +usr/share/webext/ublock-origin/assets/thirdparties/easylist-downloads.adblockplus.org/easylist.txt 26715 +usr/share/webext/ublock-origin/assets/ublock/unbreak.txt 26714 +usr/share/webext/ublock-origin/assets/ublock/privacy.txt 26713 +usr/share/webext/ublock-origin/assets/ublock/badware.txt 26712 +usr/share/webext/ublock-origin/assets/ublock/resource-abuse.txt 26711 +usr/share/webext/ublock-origin/assets/ublock/filters.txt 26710 +usr/share/mime/application/pdf.xml 26709 +usr/share/webext/ublock-origin/js/vapi-client.js 26708 +usr/share/webext/ublock-origin/js/contentscript.js 26707 +usr/share/webext/ublock-origin/js/scriptlets/subscriber.js 26706 +usr/local/lib/tor-browser/libmozavutil.so 26705 +usr/local/lib/tor-browser/libmozavcodec.so 26704 +usr/lib/x86_64-linux-gnu/libavcodec.so.57.64.101 26703 +usr/lib/x86_64-linux-gnu/libswresample.so.2.3.100 26702 +usr/lib/x86_64-linux-gnu/libavutil.so.55.34.101 26701 +usr/lib/x86_64-linux-gnu/libva.so.1.3904.0 26700 +usr/lib/x86_64-linux-gnu/libzvbi.so.0.13.2 26699 +usr/lib/x86_64-linux-gnu/libxvidcore.so.4.3 26698 +usr/lib/x86_64-linux-gnu/libx265.so.95 26697 +usr/lib/x86_64-linux-gnu/libx264.so.148 26696 +usr/lib/x86_64-linux-gnu/libwebpmux.so.2.0.2 26695 +usr/lib/x86_64-linux-gnu/libwebp.so.6.0.2 26694 +usr/lib/x86_64-linux-gnu/libwavpack.so.1.2.0 26693 +usr/lib/x86_64-linux-gnu/libvpx.so.4.1.0 26692 +usr/lib/x86_64-linux-gnu/libtwolame.so.0.0.0 26691 +usr/lib/x86_64-linux-gnu/libtheoraenc.so.1.1.2 26690 +usr/lib/x86_64-linux-gnu/libtheoradec.so.1.1.4 26689 +usr/lib/x86_64-linux-gnu/libspeex.so.1.5.0 26688 +usr/lib/x86_64-linux-gnu/libsnappy.so.1.3.0 26687 +usr/lib/x86_64-linux-gnu/libshine.so.3.0.1 26686 +usr/lib/x86_64-linux-gnu/libopus.so.0.5.3 26685 +usr/lib/x86_64-linux-gnu/libopenjp2.so.2.1.2 26684 +usr/lib/x86_64-linux-gnu/libmp3lame.so.0.0.0 26683 +usr/lib/x86_64-linux-gnu/libgsm.so.1.0.12 26682 +usr/lib/x86_64-linux-gnu/libcrystalhd.so.3.6 26681 +usr/lib/x86_64-linux-gnu/libvdpau.so.1.0.0 26680 +usr/lib/x86_64-linux-gnu/libva-drm.so.1.3904.0 26679 +usr/lib/x86_64-linux-gnu/libva-x11.so.1.3904.0 26678 +usr/lib/x86_64-linux-gnu/libnuma.so.1.0.0 26677 diff --git a/config/build-manifest-extra-packages.yml b/config/build-manifest-extra-packages.yml new file mode 100644 index 0000000000000000000000000000000000000000..fc8cc93528582d693b24102b055b9ed755ca1d4a --- /dev/null +++ b/config/build-manifest-extra-packages.yml @@ -0,0 +1,12 @@ +# Extra packages that shall be added to the build manifest. +# +# Add here any package needed during the build, that is not identified by our +# debootstrap + apt-get wrapper tricks, when there is no better solution. +# +packages: + binary: + ### Example: + # - package: squashfs-tools + # arch: amd64 + # version: 1:4.2+20130409-2 + # explanation: pulled by lb_binary_rootfs, outside of the reach of our apt-get wrapper diff --git a/config/chroot_apt/preferences b/config/chroot_apt/preferences new file mode 100644 index 0000000000000000000000000000000000000000..331333e4b1797167c45672a8a15bf56e5738dfb2 --- /dev/null +++ b/config/chroot_apt/preferences @@ -0,0 +1,200 @@ +Package: amd64-microcode +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: aufs-dkms +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: b43-fwcutter +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Explanation: unavailable in stretch and stretch-backports, version in sid is intentionally broken (Debian#928518) +Package: electrum python3-electrum +Pin: origin deb.tails.boum.org +Pin-Priority: 999 + +Explanation: Electrum dependencies +Package: python3-jsonrpclib-pelix python3-pyaes +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Package: enigmail +Pin: origin deb.tails.boum.org +Pin-Priority: -1 + +Package: firmware-b43-installer +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: firmware-b43legacy-installer +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: firmware-linux-free +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Explanation: src:firmware-nonfree +Package: firmware-linux firmware-linux-nonfree firmware-atheros firmware-brcm80211 firmware-intel-sound firmware-ipw2x00 firmware-iwlwifi firmware-libertas firmware-misc-nonfree firmware-realtek firmware-ti-connectivity +Pin: release o=Debian,n=sid +Pin-Priority: 990 + +Explanation: Exception to src:firmware-nonfree pinning due to Debian#928631 +Package: firmware-amd-graphics +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 990 + +Package: firmware-zd1211 +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: fonts-noto* +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Explanation: src:gdk-pixbuf +Package: gir1.2-gdkpixbuf-2.0 libgdk-pixbuf2.0-* +Pin: version 2.36.5-2.0tails* +Pin-Priority: -1 + +Explanation: not available in Stretch; XXX:Buster: remove this entry +Package: hunspell-id hunspell-tr +Pin: release o=Debian,n=sid +Pin-Priority: 990 + +Package: intel-microcode +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 990 + +Package: libfunction-parameters-perl +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Package: linux-compiler-* linux-headers-* linux-image-* linux-kbuild-* linux-source-* +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Explanation: src:libdrm +Package: libdrm* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:libclc +Package: libclc* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:libglvnd +Package: libglvnd* libegl1 libgles2 libgl1 libglx0 libopengl0 +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:llvm-toolchain-5.0 +Package: clang* libclang* libfuzzer-* python-clang-* libllvm* llvm-* lld-* liblld-* lldb-* liblldb-* python-lldb-* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:mesa +Package: lib*-mesa* libgbm* libosmesa* libxatracker* mesa* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Package: obfs4proxy +Pin: release o=TorProject,n=obfs4proxy +Pin-Priority: 990 + +Explanation: src:systemd +Explanation: systemd >= v233 required for meek_lite and enable the unsafe browser and Tor launcher applications to do clearnet DNS resolution. (#8243) +Package: systemd systemd-sysv systemd-container systemd-journal-remote systemd-coredump systemd-tests libpam-systemd libnss-myhostname libnss-mymachines libnss-resolve libnss-systemd libsystemd0 libsystemd-dev udev libudev1 libudev-dev udev-udeb libudev1-udeb +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:systemd +Explanation: systemd >= v240 required to fix CVE-2018-16864, CVE-2018-16865 and CVE-2018-16866 (#16352) +Package: systemd systemd-sysv systemd-container systemd-journal-remote systemd-coredump systemd-tests libpam-systemd libnss-myhostname libnss-mymachines libnss-resolve libnss-systemd libsystemd0 libsystemd-dev udev libudev1 libudev-dev udev-udeb libudev1-udeb +Pin: origin deb.tails.boum.org +Pin-Priority: 999 + +Package: openpgp-applet +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Package: tails-installer +Pin: origin deb.tails.boum.org +Pin-Priority: 999 + +Package: tor tor-geoipdb +Pin: release o=TorProject,n=tor-experimental-0.4.0.x-stretch +Pin-Priority: 999 + +Package: virtualbox* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:vulkan +Package: vulcan* libvulkan* +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: src:wayland and src:wayland-protocols +Package: libwayland* wayland-protocols +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: #15833 +Package: xserver-xorg-video-nouveau +Pin: version 1:1.0.15-3~bpo9+0tails1 +Pin-Priority: -1 + +Explanation: src:xorg-server +Package: xserver-xorg-core xserver-xorg-dev xdmx xdmx-tools xnest xvfb xserver-xephyr xserver-common xorg-server-source xwayland xserver-xorg-legacy +Pin: release o=Debian,n=stretch +Pin-Priority: 999 + +Package: webext-ublock-origin +Pin: release o=Debian,n=sid +Pin-Priority: 999 + +Explanation: compatibility with TB60 +Package: xul-ext-torbirdy +Pin: release o=Debian,n=stretch-backports +Pin-Priority: 999 + +Explanation: weirdness in chroot_apt install-binary +Package: * +Pin: release o=chroot_local-packages +Pin-Priority: 1010 + +Package: * +Pin: origin deb.tails.boum.org +Pin-Priority: 990 + +Package: * +Pin: release o=Debian,n=stretch-updates +Pin-Priority: 990 + +Package: * +Pin: release l=Debian-Security,n=stretch/updates +Pin-Priority: 990 + +Package: * +Pin: release o=Debian,n=stretch +Pin-Priority: 990 + +Package: * +Pin: release o=TorProject,n=stretch +Pin-Priority: 990 + +Package: * +Pin: origin live.debian.net +Pin-Priority: -1 + +Package: * +Pin: release o=Debian +Pin-Priority: -10 + +Package: * +Pin: release o=TorProject +Pin-Priority: -10 diff --git a/config/chroot_local-hooks/00-install-tailslib b/config/chroot_local-hooks/00-install-tailslib new file mode 100755 index 0000000000000000000000000000000000000000..9943ed7b3b89239427968c8be19f093584d6d2f8 --- /dev/null +++ b/config/chroot_local-hooks/00-install-tailslib @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e +set -u + +echo "Installing the tailslib python library" + +# Import ensure_hook_dependency_is_installed() and +# strip_nondeterminism_wrapper() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed python3-setuptools + +( + cd /tmp/pythonlib + python3 setup.py clean + python3 setup.py install + + package_glob_pattern="/usr/local/lib/python3.*/dist-packages/Tailslib*.egg" + strip_nondeterminism_wrapper --type zip ${package_glob_pattern} +) +rm -rf /tmp/pythonlib diff --git a/config/chroot_local-hooks/01-check-for-dot-orig-files b/config/chroot_local-hooks/01-check-for-dot-orig-files new file mode 100755 index 0000000000000000000000000000000000000000..278e84c0c8fbe2dfa4bba1da6ecfc0b843f5b57e --- /dev/null +++ b/config/chroot_local-hooks/01-check-for-dot-orig-files @@ -0,0 +1,25 @@ +#! /bin/sh + +set -e + +echo "Checking for .orig files" + +DOT_ORIG_WHITELIST_DELETE=$(cat <&2 + echo "$DOT_ORIG_FILES" >&2 + exit 1 +fi diff --git a/config/chroot_local-hooks/02-loopback b/config/chroot_local-hooks/02-loopback new file mode 100755 index 0000000000000000000000000000000000000000..6bf216ab22394e0aa630566b0d615768468cdddd --- /dev/null +++ b/config/chroot_local-hooks/02-loopback @@ -0,0 +1,8 @@ +#! /bin/sh + +set -e + +echo "Configuring loopback network interface" + +echo " +iface lo inet loopback" >>/etc/network/interfaces diff --git a/config/chroot_local-hooks/04-change-gids-and-uids b/config/chroot_local-hooks/04-change-gids-and-uids new file mode 100755 index 0000000000000000000000000000000000000000..417b1fadc4c789d445aee7d077c4a3a2f6c515aa --- /dev/null +++ b/config/chroot_local-hooks/04-change-gids-and-uids @@ -0,0 +1,147 @@ +#!/bin/sh + +### Ensure GIDs are stable accross releases +# ... otherwise, things such as tor@service are broken +# after applying an automatic upgrade (#15695, #15424, #13426, #15407) + +# When installing packages apt may variate the order of package installations. +# That leads to different GID/UID for the created groups and users. This +# variation of GID/UID leads to problems, when we want to ship diffs for a +# smoother upgrade process. There are many different solutions flying around to +# fix this issue, but they were not elaborate for Tails and may have other nasty +# side-effects, as the maintainer scripts, may react differently, if they are +# not in charge of creating group/user themselves. + +# We may get rid of this script with the switch to overlayfs (#8415, #15689). + +set -e + +echo "Set fixed GIDs and UIDs" + +Debug_gids_and_uids () { + # Print content of /etc/{passwd, group}, if a difference against + # the expected content is detected. Otherwise only the content of + # those files is printed + + for file in passwd group; do + diff -Naur "/usr/share/tails/build/${file}" "/etc/${file}" >&2 || : + echo >&2 + echo "Content of '/etc/${file}':" >&2 + cat "/etc/${file}" >&2 + echo >&2 + done +} + +Change_uid () { + # Change_uid(NAME, NEW) + # change UID for $NAME to $NEW + # and update UID for all files, that were owned by the old UID + + NAME="$1" + NEW="$2" + old="$(getent passwd "${NAME}" | awk -F ':' '{print $3}')" + + if [ -n "${old}" ]; then + echo "Changing UID for ${NAME} (${old} -> ${NEW})" + if ! usermod --uid "${NEW}" "${NAME}"; then + Debug_gids_and_uids + exit 1 + fi + # chown(1) and chgrp(1) clear the setuid and setgid bits; + # let's preserve them. + # + # Using "-exec CMD +", find builds command lines incrementally, + # before executing chown. Which is why the operation below is + # not the "if a file has the setuid bit, then give it the setuid + # bit" no-op, but rather "if a file had the setuid bit before + # chown was run, then set it back". + find / -wholename /proc -prune -o \( \ + \! -type l -uid "${old}" \ + -exec chown "${NEW}" '{}' + \ + \( \ + -perm -6000 -exec chmod gu+s '{}' + \ + -o -perm -4000 -exec chmod u+s '{}' + \ + -o -perm -2000 -exec chmod g+s '{}' + \ + \) \ + \) + fi +} + +Change_gid () { + # Change_gid(NAME, NEW) + # change the GID for $NAME to $NEW + # and update GID for all files, that were owned by the old GID + + NAME="$1" + NEW="$2" + old="$(getent group "${NAME}" | awk -F ':' '{print $3}')" + + if [ -n "${old}" ]; then + echo "Changing GID for ${NAME} (${old} -> ${NEW})" + if ! groupmod --gid "${NEW}" "${NAME}"; then + Debug_gids_and_uids + exit 1 + fi + # See comments in Change_uid(). + find / -wholename /proc -prune -o \( \ + \! -type l -gid "${old}" \ + -exec chgrp "${NEW}" '{}' + \ + \( \ + -perm -6000 -exec chmod gu+s '{}' + \ + -o -perm -4000 -exec chmod u+s '{}' + \ + -o -perm -2000 -exec chmod g+s '{}' + \ + \) \ + \) + fi +} + +# Temporarily give these users and groups a UID/GID that's out of the way, +# to avoid collisions +Change_uid debian-tor 1070 +Change_uid speech-dispatcher 1080 +Change_uid colord 1090 +Change_uid saned 1100 +Change_uid pulse 1110 +Change_uid hplip 1120 +Change_uid Debian-gdm 1130 +Change_gid messagebus 1050 +Change_gid ssh 1090 +Change_gid memlockd 1100 +Change_gid ssl-cert 1110 +Change_gid vboxsf 1120 +Change_gid debian-tor 1140 +Change_gid lpadmin 1150 +Change_gid scanner 1160 +Change_gid colord 1170 +Change_gid saned 1180 +Change_gid pulse 1190 +Change_gid pulse-access 1200 +Change_gid Debian-gdm 1210 +Change_gid kvm 1500 +Change_gid render 1510 +Change_gid Debian-exim 1520 + +# Finally, give these users and groups the desired UID/GID +Change_uid debian-tor 107 +Change_uid speech-dispatcher 108 +Change_uid colord 109 +Change_uid saned 110 +Change_uid pulse 111 +Change_uid hplip 112 +Change_uid Debian-gdm 113 +Change_gid messagebus 105 +Change_gid ssh 109 +Change_gid memlockd 110 +Change_gid ssl-cert 111 +Change_gid vboxsf 112 +Change_gid debian-tor 114 +Change_gid lpadmin 115 +Change_gid scanner 116 +Change_gid colord 117 +Change_gid saned 118 +Change_gid pulse 119 +Change_gid pulse-access 120 +Change_gid Debian-gdm 121 +Change_gid kvm 150 +Change_gid render 151 +Change_gid Debian-exim 152 diff --git a/config/chroot_local-hooks/05-adduser_tails-persistence-setup b/config/chroot_local-hooks/05-adduser_tails-persistence-setup new file mode 100755 index 0000000000000000000000000000000000000000..1f93b7ba029da0825e3ba5886146f7d670e5e072 --- /dev/null +++ b/config/chroot_local-hooks/05-adduser_tails-persistence-setup @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +# Create the tails-persistence-setup user. +# +# The tails-persistence-setup program may be run as this user. +# This allows us to give it special privileges (e.g. access via udisk +# to internal disks and to the boot medium) that we don't want to give +# to the desktop user. + +echo "Creating the tails-persistence-setup user" + +# If this fails because UID 115 or GID 122 are already in use, +# move the "stealer" user/group out of the way in 04-change-gids-and-uids. + +addgroup --system --gid 122 tails-persistence-setup +adduser --system --uid 115 --gid 122 --no-create-home tails-persistence-setup diff --git a/config/chroot_local-hooks/05-disable_swapon b/config/chroot_local-hooks/05-disable_swapon new file mode 100755 index 0000000000000000000000000000000000000000..16af130d71373132a8a4e4bf6e949f598bba4096 --- /dev/null +++ b/config/chroot_local-hooks/05-disable_swapon @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +echo "Disabling swapon" + +# Disable swapon to avoid initscripts to setup swap space. +# Rationale: security-in-depth model. + +SWAPON=/sbin/swapon + +# Move any /sbin/swapon installed by any package out of the way, +# now (--rename) as well for any future one (hint: apt-get upgrade...). +dpkg-divert --rename --add /sbin/swapon + +# Install a custom noop swapon executable instead. +cat > $SWAPON << 'EOF' +#!/bin/sh +/bin/true +EOF +chmod 755 $SWAPON diff --git a/config/chroot_local-hooks/06-adduser_clearnet b/config/chroot_local-hooks/06-adduser_clearnet new file mode 100755 index 0000000000000000000000000000000000000000..2bd22dbbebc3e2668cab14a38eb973a1228e5b7f --- /dev/null +++ b/config/chroot_local-hooks/06-adduser_clearnet @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +# Create the clear user. +# +# We run unsafe-browser under this user, so that we can whitelist its +# non-Torified outgoing packets. + +echo "Creating the clearnet user" + +addgroup --system --quiet --gid 123 clearnet +adduser --system --quiet --uid 114 --gid 123 clearnet diff --git a/config/chroot_local-hooks/06-adduser_htp b/config/chroot_local-hooks/06-adduser_htp new file mode 100755 index 0000000000000000000000000000000000000000..b5869df2d17e0f310d33b95e885f152eb954ce4b --- /dev/null +++ b/config/chroot_local-hooks/06-adduser_htp @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +# Create the htp user. +# +# We run htpdate as this user, so that we can whitelist its +# non-Torified outgoing packets. + +echo "Creating the htp user" + +addgroup --system --quiet --gid 124 htp +adduser --system --quiet --uid 116 --gid 124 --no-create-home htp diff --git a/config/chroot_local-hooks/06-adduser_tails-iuk-get-target-file b/config/chroot_local-hooks/06-adduser_tails-iuk-get-target-file new file mode 100755 index 0000000000000000000000000000000000000000..a1ef6ebee4d3dd65e49d3db8c67ac530322f62fd --- /dev/null +++ b/config/chroot_local-hooks/06-adduser_tails-iuk-get-target-file @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Create the tails-iuk-get-target-file user. +# +# The tails-iuk-get-target-file program may be run as this user. +# This allows us, some day, to allow it to run in the clear, +# without going through Tor. + +echo "Creating the tails-iuk-get-target-file user" + +addgroup --system --quiet --gid 125 tails-iuk-get-target-file +adduser --system --quiet --uid 117 --gid 125 --no-create-home tails-iuk-get-target-file diff --git a/config/chroot_local-hooks/06-adduser_tails-upgrade-frontend b/config/chroot_local-hooks/06-adduser_tails-upgrade-frontend new file mode 100755 index 0000000000000000000000000000000000000000..89942d24ff11cd1cc83056173b895cd6a556eabb --- /dev/null +++ b/config/chroot_local-hooks/06-adduser_tails-upgrade-frontend @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Create the tails-upgrade-frontend user. +# +# The tails-upgrade-frontend program may be run as this user. +# This avoids having to grant the desktop user the right to install +# any arbitrary IUK. + +echo "Creating the tails-upgrade-frontend user" + +addgroup --system --quiet --gid 126 tails-upgrade-frontend +adduser --system --quiet --uid 118 --gid 126 --no-create-home tails-upgrade-frontend diff --git a/config/chroot_local-hooks/06-adduser_tor-launcher b/config/chroot_local-hooks/06-adduser_tor-launcher new file mode 100755 index 0000000000000000000000000000000000000000..79f0bf9f4d4423b4e95f4ee58fa30a02934210b1 --- /dev/null +++ b/config/chroot_local-hooks/06-adduser_tor-launcher @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Create the tor-launcher user. +# +# We run Tor Launcher under this user, and give it acces to Tor's +# control port via adding it to the debian-tor group. + +echo "creating the tor-launcher user" + +addgroup --system --quiet --gid 127 tor-launcher +adduser --system --quiet --uid 119 --gid 127 tor-launcher +adduser tor-launcher debian-tor diff --git a/config/chroot_local-hooks/07-adduser_tails-install-iuk b/config/chroot_local-hooks/07-adduser_tails-install-iuk new file mode 100755 index 0000000000000000000000000000000000000000..de55a0945ab90683d2bc2ff40932d0268f236de3 --- /dev/null +++ b/config/chroot_local-hooks/07-adduser_tails-install-iuk @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Create the tails-install-iuk user. +# +# The tails-install-iuk program may be run as this user, +# which is granted some passwordless sudo credentials. + +echo "Creating the tails-install-iuk user" + +addgroup --system --quiet --gid 128 tails-install-iuk +adduser --system --quiet --uid 120 --gid 128 --no-create-home tails-install-iuk +adduser tails-install-iuk tails-iuk-get-target-file diff --git a/config/chroot_local-hooks/09-remove_unsupported_pidgin_libs b/config/chroot_local-hooks/09-remove_unsupported_pidgin_libs new file mode 100755 index 0000000000000000000000000000000000000000..76a086670b680007d846dca2b086cac9f61f3938 --- /dev/null +++ b/config/chroot_local-hooks/09-remove_unsupported_pidgin_libs @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +# Remove pidgin's (libpurple's) support for protocols we don't support. + +echo "Removing Pidgin libraries for protocols we do not support" + +KEEP="irc|jabber|xmpp" + +find /usr/lib/purple-2/ -name 'lib*.so' \ + | /bin/grep -Ev "/lib($KEEP)\.so" \ + | xargs rm diff --git a/config/chroot_local-hooks/09-torsocks-apps b/config/chroot_local-hooks/09-torsocks-apps new file mode 100755 index 0000000000000000000000000000000000000000..ad9a6f2d6f7a0bee25e0e7b4de18b5918a9b2355 --- /dev/null +++ b/config/chroot_local-hooks/09-torsocks-apps @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +echo "Wrapping some applications with torsocks" + +APPS="openpgp-applet seahorse" +DBUS_SERVICES="org.gnome.seahorse.Application org.fedoraproject.Config.Printing" +WRAPPED_DBUS_SERVICES="" + +for app in $APPS; do + sed -i'' --regexp-extended 's,^Exec=(.*),Exec=torsocks \1,' \ + "/usr/share/applications/${app}.desktop" +done + +for dbus_service in $DBUS_SERVICES; do + sed -i'' --regexp-extended 's,^Exec=(.*),Exec=/usr/bin/torsocks \1,' \ + "/usr/share/dbus-1/services/${dbus_service}.service" +done + +# Wrapped by both torsocks and a binary in /usr/local +for dbus_service in $WRAPPED_DBUS_SERVICES; do + sed -i'' --regexp-extended 's,^Exec=/usr/(.*),Exec=/usr/bin/torsocks /usr/local/\1,' \ + "/usr/share/dbus-1/services/${dbus_service}.service" +done + +# Redirect to existing wrapper +sed -i'' --regexp-extended 's,^Exec=pidgin$,Exec=/usr/local/bin/pidgin,' \ + "/usr/share/applications/pidgin.desktop" +sed -i'' --regexp-extended 's,^Exec=/usr/bin/totem(\s+.*)?$,Exec=/usr/local/bin/totem,' \ + "/usr/share/dbus-1/services/org.gnome.Totem.service" diff --git a/config/chroot_local-hooks/09-torsocks-configuration b/config/chroot_local-hooks/09-torsocks-configuration new file mode 100755 index 0000000000000000000000000000000000000000..6614aea7165bd63e5916981573135fb7b2a5e975 --- /dev/null +++ b/config/chroot_local-hooks/09-torsocks-configuration @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +echo "Configure torsocks" + +# Allow TCP and UDP outbound connections to the loopback interface, so +# that we can wrap git with torsocks without breaking Git-over-SSH +# (SSH is torified via ProxyCommand already). +sed -i'' \ + --regexp-extended 's,^#?AllowOutboundLocalhost\s+.*,AllowOutboundLocalhost 2,' \ + /etc/tor/torsocks.conf diff --git a/config/chroot_local-hooks/10-tbb b/config/chroot_local-hooks/10-tbb new file mode 100755 index 0000000000000000000000000000000000000000..84688c871ff7dfc8eb4c1bf3462118c010944136 --- /dev/null +++ b/config/chroot_local-hooks/10-tbb @@ -0,0 +1,359 @@ +#!/bin/sh + +set -e +set -u + +echo "Install the Tor Browser" + +# Import the TBB_INSTALL, TBB_PROFILE, TBB_EXT and +# TOR_LAUNCHER_INSTALL variables, which contains the paths we will +# split TBB's actual browser (binaries etc), user data and extension +# into. While this differs from how the TBB organizes the files, the +# end result will be the same, and it's practical since when creating +# a new browser profile we can simply copy the profile directory +# without duplicating all extensions. +. /usr/local/lib/tails-shell-library/tor-browser.sh +# Import install_fake_package and strip_nondeterminism_wrapper +. /usr/local/lib/tails-shell-library/build.sh + +download_and_verify_files() { + local base_url bundles destination apt_proxy + base_url="${1}" + bundles="${2}" + destination="${3}" + + # Use the builder's caching APT proxy, if any + apt_proxy="$(apt-config --format '%v' dump Acquire::http::Proxy)" + if [ -n "${apt_proxy}" ]; then + export HTTP_PROXY="${apt_proxy}" + export http_proxy="${apt_proxy}" + export HTTPS_PROXY="${apt_proxy}" + export https_proxy="${apt_proxy}" + fi + + echo "${bundles}" | while read expected_sha256 tarball; do + ( + cd "${destination}" + echo "Fetching ${base_url}/${tarball} ..." + curl --retry 20 --remote-name "${base_url}/${tarball}" + ) + actual_sha256="$(sha256sum "${destination}/${tarball}" | cut -d' ' -f1)" + if [ "${actual_sha256}" != "${expected_sha256}" ]; then + echo "SHA256 mismatch for ${tarball}" >&2 + exit 1 + fi + done +} + +install_tor_browser() { + local bundle destination tmp prep torlauncher_xpi_path torlauncher_version + bundle="${1}" + destination="${2}" + + tmp="$(mktemp -d)" + tar -xf "${bundle}" -C "${tmp}" + if [ -d "${tmp}"/tor-browser_en-US ]; then + prep="${tmp}"/tor-browser_en-US/Browser + elif [ -d "${tmp}"/tor-browser ]; then + # TBB nightly builds + prep="${tmp}"/tor-browser/Browser + else + echo "The main bundle's top level directory is wrong" >&2 + exit 1 + fi + + # Enable our myspell/hunspell dictionaries. TBB only provides the + # one for en-US, but Debian's seems more comprehensive, so we'll + # only use Debian's dictionaries. + rm -f "${prep}"/dictionaries/* + for f in /usr/share/hunspell/*.aff /usr/share/hunspell/*.dic; do + ln -s "${f}" "${prep}"/dictionaries/ + done + + # Let's use the libstdc++ that the Tor Browser is intended to be used with, + # instead of the system one, whenever ours is too old. + # For details see projects/firefox/abicheck.cc in + # https://git.torproject.org/builders/tor-browser-build.git + # Tor Browser 8.0a10 requires GLIBCXX_3.4.22, which Stretch has + # so disable this for now. + # cp "${prep}"/TorBrowser/Tor/libstdc++.so.6 "${prep}" + + # We don't need the Tor binary, the shared libraries Tor needs + # (but Firefox doesn't) and documentation shipped in the TBB. + rm -r "${prep}"/TorBrowser/Tor "${prep}"/TorBrowser/Docs + + # We don't want tor-launcher to be part of the regular browser + # profile but we want to keep it as a standalone application + # when Tails is started in "bridge mode". + torlauncher_xpi_path="${prep}/TorBrowser/Data/Browser/profile.default/extensions/tor-launcher@torproject.org.xpi" + 7z x -o"${TOR_LAUNCHER_INSTALL}" "${torlauncher_xpi_path}" + torlauncher_version="$(sed -n \ + 's,^ \([0-9\.]\+\),\1,p' \ + "${TOR_LAUNCHER_INSTALL}/install.rdf")" + SOURCE_DATE_YYYYMMDD=$(date --utc --date="@$SOURCE_DATE_EPOCH" '+%Y%m%d') + cat > "${TOR_LAUNCHER_INSTALL}/application.ini" << EOF +[App] +Vendor=TorProject +Name=TorLauncher +Version=${torlauncher_version} +BuildID=${SOURCE_DATE_YYYYMMDD} +ID=tor-launcher@torproject.org + +[Gecko] +MinVersion=$(get_firefox_version "${prep}/application.ini") +MaxVersion=*.*.* + +[Shell] +Icon=icon.png +EOF + chmod -R a+rX "${TOR_LAUNCHER_INSTALL}" + rm "${torlauncher_xpi_path}" + + # The Tor Browser will fail, complaining about an incomplete profile, + # unless there's a readable TorBrowser/Data/Browser/Caches + # in the directory where the firefox executable is located. + mkdir -p "${prep}"/TorBrowser/Data/Browser/Caches + + # Otherwise the "General" section in the preferences is not displayed. + install -d -m 0755 "${prep}"/TorBrowser/UpdateInfo + + mv "${prep}" "${destination}" + + rm -r "${tmp}" +} + +# TBB works around the lack of code signing for its extensions by +# hacking in exceptions. We do the same! +apply_extension_code_signing_hacks () { + local tbb_install tbb_timestamp + tbb_install="${1}" + tbb_timestamp="${2}" + + tmp="$(mktemp -d)" + ( + cd "${tmp}" + 7z x -tzip "${tbb_install}/omni.ja" + patch -p1 <> defaults/preferences/000-tor-browser.js + touch --date="@${tbb_timestamp}" defaults/preferences/000-tor-browser.js + rm "${tbb_install}/browser/omni.ja" + 7z a -mtc=off -tzip "${tbb_install}/browser/omni.ja" * + ) + rm -r "${tmp}" +} + +strip_nondeterminism () { + local tbb_install tbb_timestamp + tbb_install="${1}" + tbb_timestamp="${2}" + + for archive in "${tbb_install}/omni.ja" "${tbb_install}/browser/omni.ja"; do + strip_nondeterminism_wrapper --type zip --timestamp "${tbb_timestamp}" \ + "${archive}" 2>/dev/null + done +} + +install_langpacks_from_bundles() { + local bundles_dir destination + bundles_dir="${1}" + destination="${2}" + + for tarball in "${bundles_dir}"/tor-browser-*.tar.xz; do + locale="$(echo "${tarball}" | sed "s@^.*/tor-browser-.*_\(.*\)\.tar\.xz@\1@")" + if [ "${locale}" = en-US ]; then + continue + fi + xpi="tor-browser_${locale}/Browser/TorBrowser/Data/Browser/profile.default/extensions/langpack-${locale}@firefox.mozilla.org.xpi" + ( + cd "${bundles_dir}" + tar -xf "${tarball}" "${xpi}" + mv "${xpi}" "${destination}" + ) + done +} + +get_firefox_version() { + # The application.ini file + local appini + appini="${1}" + sed -n 's/^Version=\(.*\)$/\1/p' "${appini}" +} + +install_debian_extensions() { + local destination + destination="${1}" + shift + apt-get install --yes "${@}" + ln -s /usr/share/webext/ublock-origin/ \ + "${destination}"/'uBlock0@raymondhill.net' + patch -p1 < /usr/share/tails/uBlock-disable-autoUpdate.diff +} + +create_default_profile() { + local tbb_profile extensions_dir destination + tbb_profile="${1}" + tbb_extensions_dir="${2}" + destination="${3}" + + rsync -a --exclude bookmarks.html --exclude extensions \ + "${tbb_profile}"/ "${destination}"/ + + mkdir -p "${destination}"/extensions + for ext in "${tbb_extensions_dir}"/*; do + ln -s "${ext}" "${destination}"/extensions/ + done +} + +# For consistency we'll set timestamps of files we modify to the +# same one used by the Tor Browser instead of SOURCE_DATE_EPOCH. +TBB_TIMESTAMP="$(date --date='2000-01-01 00:00:00' +%s)" + +TBB_SHA256SUMS_FILE=/usr/share/tails/tbb-sha256sums.txt +TBB_TARBALLS="$(grep "\/tor-browser.desktop/' \ + /usr/share/applications/gnome-mimeapps.list \ + > /etc/xdg/gnome-mimeapps.list +chmod 644 /etc/xdg/gnome-mimeapps.list diff --git a/config/chroot_local-hooks/11-enable-thunderbird-addons b/config/chroot_local-hooks/11-enable-thunderbird-addons new file mode 100755 index 0000000000000000000000000000000000000000..3280a2e5496328a031f7ea249baff8c600c8b163 --- /dev/null +++ b/config/chroot_local-hooks/11-enable-thunderbird-addons @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e +set -u + +EXT="/usr/lib/thunderbird/extensions" + +[ -d "$EXT" ] || exit 1 + +echo "Enabling Torbirdy and Enigmail in Thunderbird" +ln -s /usr/share/xul-ext/torbirdy "${EXT}/castironthunderbirdclub@torproject.org" +ln -s /usr/share/xul-ext/enigmail "${EXT}/{847b3a00-7ab1-11d4-8f02-006008948af5}" diff --git a/config/chroot_local-hooks/11-localize_browser b/config/chroot_local-hooks/11-localize_browser new file mode 100755 index 0000000000000000000000000000000000000000..3dd01f0158ae518cc43c85ea9db4849a45da66b6 --- /dev/null +++ b/config/chroot_local-hooks/11-localize_browser @@ -0,0 +1,96 @@ +#!/bin/sh + +set -e + +echo "Localize each supported browser locale" + +# Import the TBB_INSTALL and TBB_EXT variables and +# supported_tor_browser_locales() +. /usr/local/lib/tails-shell-library/tor-browser.sh + +# Import language_code_from_locale() +. /usr/local/lib/tails-shell-library/localization.sh + +# Import TAILS_WIKI_SUPPORTED_LANGUAGES +. /etc/amnesia/environment + +BROWSER_LOCALIZATION_DIR="/usr/share/tails/browser-localization" +DESCRIPTIONS_FILE="${BROWSER_LOCALIZATION_DIR}/descriptions" +LOCALE_PROFILES_DIR="/etc/tor-browser/locale-profiles/" + +# Sanity check that each supported Tor Browser locale has a +# description for how to localize it further. +BROKEN_LOCALES="" +for LOCALE in $(supported_tor_browser_locales); do + if ! grep -q "^${LOCALE}:" "${DESCRIPTIONS_FILE}" 2>/dev/null; then + BROKEN_LOCALES="${BROKEN_LOCALES} ${LOCALE}" + fi +done +if [ -n "${BROKEN_LOCALES}" ]; then + echo "The following supported browser locales lack descriptions in ${DESCRIPTIONS_FILE}:${BROKEN_LOCALES}" >&2 + exit 1 +fi + +# This very long while-loop is fed the DESCRIPTIONS_FILE (IO +# redirection at the bottom), which describes how we will localize +# each supported Tor Browser locale. The format is: +# MOZILLA_LOCALE:LOCATION +# Note that we're forced to pick some representative location for the +# language-only locales, like Egypt (EG) for Arabic (ar). +while IFS=: read MOZILLA_LOCALE LOCATION; do + if [ -z "${MOZILLA_LOCALE}" ] || [ -z "${LOCATION}" ]; then + echo "Something is wrong with ${DESCRIPTIONS_FILE}" >&2 + echo "Description: ${MOZILLA_LOCALE}:${LOCATION}" >&2 + exit 1 + fi + + echo "- Localizing ${MOZILLA_LOCALE} for browsers..." + + # In some places we'll need the locale in xx_YY format instead of + # Mozilla's xx-YY fromat. Over all, the greatest difficulty in + # this whole script is really to know when to use the correct + # locale format, since Firefox isn't very consistent in it. + if echo "${MOZILLA_LOCALE}" | grep -q '-'; then + NORMAL_LOCALE="$(echo "${MOZILLA_LOCALE}" | tr - _)" + else + NORMAL_LOCALE="${MOZILLA_LOCALE}_${LOCATION}" + fi + LANG_CODE="$(language_code_from_locale "${NORMAL_LOCALE}")" + + # Our Tor Browser wrapper script will make use of the following + # per-locale profiles to set localized defaults for various prefs. + mkdir -p "${LOCALE_PROFILES_DIR}" + LOCALE_PROFILE_FILE="${LOCALE_PROFILES_DIR}/${MOZILLA_LOCALE}.js" + TBB_DICTIONARIES_DIR="${TBB_INSTALL}/dictionaries" + unset SPELLCHECKER_LOCALE + for LOCALE in "${NORMAL_LOCALE}" "${LANG_CODE}"; do + if [ -e "${TBB_DICTIONARIES_DIR}/${LOCALE}.dic" ]; then + SPELLCHECKER_LOCALE="${LOCALE}" + fi + done + if [ -z "${SPELLCHECKER_LOCALE}" ]; then + SPELLCHECKER_LOCALE="en_US" + fi + set_mozilla_pref "${LOCALE_PROFILE_FILE}" \ + "spellchecker.dictionary" \ + "\"${SPELLCHECKER_LOCALE}\"" \ + "user_pref" + HOMEPAGE="https://tails.boum.org/home/" + . /etc/os-release # get $TAILS_CHANNEL and $TAILS_DISTRIBUTION + if [ "${TAILS_DISTRIBUTION}" = UNRELEASED ] \ + || [ "${TAILS_CHANNEL:-stable}" != stable ]; then + HOMEPAGE="${HOMEPAGE}testing/" + fi + if echo "${TAILS_WIKI_SUPPORTED_LANGUAGES}" | grep -qw "${LANG_CODE}"; then + HOMEPAGE="${HOMEPAGE}index.${LANG_CODE}.html" + fi + set_mozilla_pref "${LOCALE_PROFILE_FILE}" \ + "browser.startup.homepage" "\"${HOMEPAGE}\"" "user_pref" +done < "${DESCRIPTIONS_FILE}" + +# This directory is not needed after build time. +rm -r "${BROWSER_LOCALIZATION_DIR}" + +# All generated and modified files must remain world-readable. +chmod -R a+rX "${LOCALE_PROFILES_DIR}" \ + "${TBB_EXT}" diff --git a/config/chroot_local-hooks/11-patch-thunderbird b/config/chroot_local-hooks/11-patch-thunderbird new file mode 100755 index 0000000000000000000000000000000000000000..8124ca225143c05321a24eb48bb752df54a38eb1 --- /dev/null +++ b/config/chroot_local-hooks/11-patch-thunderbird @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e +set -u + +echo "Patching the Thunderbird account setup wizard" + +# Import strip_nondeterminism_wrapper +. /usr/local/lib/tails-shell-library/build.sh + +OMNI_JA=/usr/share/thunderbird/omni.ja + +/usr/share/tails/build/patch-thunderbird \ + "$OMNI_JA" \ + /usr/share/tails/build/thunderbird-patches + +strip_nondeterminism_wrapper \ + --type zip \ + --timestamp "$SOURCE_DATE_EPOCH" \ + "$OMNI_JA" 2>/dev/null diff --git a/config/chroot_local-hooks/12-kernel-modules-build-environment b/config/chroot_local-hooks/12-kernel-modules-build-environment new file mode 100755 index 0000000000000000000000000000000000000000..cbb88645a17e484bdceed08b2255e885bf8b907b --- /dev/null +++ b/config/chroot_local-hooks/12-kernel-modules-build-environment @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e +set -u +set -x + +echo "Setting up a build environment for kernel modules" + +. /usr/share/tails/build/variables + +# Import ensure_hook_dependency_is_installed() and +# install_fake_package() +. /usr/local/lib/tails-shell-library/build.sh + +# Install gcc-6 and fake linux-compiler-gcc-8-x86 +# (linux-headers-4.19+ depends on it, but Stretch hasn't GCC 8) +# XXX:Buster: remove this hack. +ensure_hook_dependency_is_installed gcc-6 +NEWEST_INSTALLED_KERNEL_VERSION="$( + dpkg-query --showformat '${Version}\n' --show 'linux-image-*-amd64' \ + | sort --version-sort | tail -n1 +)" +install_fake_package \ + linux-compiler-gcc-8-x86 \ + "${NEWEST_INSTALLED_KERNEL_VERSION}~0tails1" +ln -s /usr/bin/gcc-6 /usr/bin/gcc-8 + +ensure_hook_dependency_is_installed \ + build-essential \ + libelf-dev \ + "linux-headers-${KERNEL_VERSION}-amd64" diff --git a/config/chroot_local-hooks/13-aufs b/config/chroot_local-hooks/13-aufs new file mode 100755 index 0000000000000000000000000000000000000000..b6267fd244e2d18cf7de5676d404ad9aa9d1a5d8 --- /dev/null +++ b/config/chroot_local-hooks/13-aufs @@ -0,0 +1,46 @@ +#! /bin/sh + +set -e +set -u + +echo "Building the aufs module" + +. /usr/share/tails/build/variables + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed \ + "linux-source-${KERNEL_SOURCE_VERSION}" + +# aufs build needs fs/mount.h, which is in linux-source-* but not +# in linux-headers-*, so we'll symlink it. +tar --directory=/usr/src \ + -xf "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}.tar."* + +arch=amd64 +ln -s \ + "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}/fs" \ + "/usr/src/linux-headers-${KERNEL_VERSION}-${arch}/fs" +( + cd /usr/src/aufs4-standalone + perl -pi -E \ + 's{\A CONFIG_AUFS_DEBUG \s* = \s* y $}{CONFIG_AUFS_DEBUG =}xms' \ + config.mk + KDIR="/usr/src/linux-headers-${KERNEL_VERSION}-${arch}" + make clean KDIR="$KDIR" + make install KDIR="$KDIR" +) + +for modules_dir in /lib/modules/*/extra ; do + if [ ! -f "${modules_dir}/aufs.ko" ]; then + echo "Can not find aufs.ko module in '${modules_dir}" >&2 + exit 1 + fi +done + +strip --strip-debug /lib/modules/*/extra/aufs.ko + +depmod "${KERNEL_VERSION}-${arch}" +rm -r /usr/src/aufs4-standalone +rm -r "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}" diff --git a/config/chroot_local-hooks/14-generate-tor-browser-profile b/config/chroot_local-hooks/14-generate-tor-browser-profile new file mode 100755 index 0000000000000000000000000000000000000000..300abe6d6e7210bd308ff8048f901d9049af5108 --- /dev/null +++ b/config/chroot_local-hooks/14-generate-tor-browser-profile @@ -0,0 +1,10 @@ +#!/bin/sh + +echo "Generating Tor Browser profile" + +# Generate Tor Browser profile at build time so it won't reside in RAM + +set -e + +/usr/local/lib/generate-tor-browser-profile +mv ~/.tor-browser /etc/skel diff --git a/config/chroot_local-hooks/15-tor-browser-bookmarks b/config/chroot_local-hooks/15-tor-browser-bookmarks new file mode 100755 index 0000000000000000000000000000000000000000..441b7dcbbd6886f90aa299a978f64b39fda2d775 --- /dev/null +++ b/config/chroot_local-hooks/15-tor-browser-bookmarks @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +echo "Set up Tor Browser bookmarks" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed sqlite3 + +# Create a symlink to places.sqlite in browser profile from a +# dedicated "bookmarks" directory, so that it can be easily made +# persistent +ln -s /home/amnesia/.mozilla/firefox/bookmarks/places.sqlite \ + /etc/skel/.tor-browser/profile.default/places.sqlite + +# Create the bookmarks database +sqlite3 /etc/skel/.mozilla/firefox/bookmarks/places.sqlite \ + < /etc/skel/.mozilla/firefox/bookmarks/places.sqlite.in +rm /etc/skel/.mozilla/firefox/bookmarks/places.sqlite.in diff --git a/config/chroot_local-hooks/18-fix_offline_website_css_for_yelp b/config/chroot_local-hooks/18-fix_offline_website_css_for_yelp new file mode 100755 index 0000000000000000000000000000000000000000..4355db58d8918bae3deb2819dd4927bba945054d --- /dev/null +++ b/config/chroot_local-hooks/18-fix_offline_website_css_for_yelp @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +echo "Tweaking the offline website's CSS" + +# Yelp becomes awfully slow when 'box-shadow' properties are used. +# So let's just remove the bling-bling to get a better offline browsing +# experience. + +sed -e '/box-shadow/d' -i /usr/share/doc/tails/website/local.css diff --git a/config/chroot_local-hooks/19-install-tor-browser-AppArmor-profile b/config/chroot_local-hooks/19-install-tor-browser-AppArmor-profile new file mode 100755 index 0000000000000000000000000000000000000000..831146c5cbc598650ddbf7e8d62e68b2e5a36c6a --- /dev/null +++ b/config/chroot_local-hooks/19-install-tor-browser-AppArmor-profile @@ -0,0 +1,61 @@ +#!/bin/sh + +set -e + +echo "Installing AppArmor profiles for Tor Browser" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed patch + +PATCH='/usr/share/tails/torbrowser-AppArmor-profile.patch' + +### Functions + +toggle_src_APT_sources() { + MODE="$1" + TEMP_APT_SOURCES='/etc/apt/sources.list.d/tmp-deb-src.list' + + case "$MODE" in + on) + cat /etc/apt/sources.list /etc/apt/sources.list.d/*.list \ + | grep --extended-regexp --invert-match \ + 'file:/root/local-packages' \ + | grep --extended-regexp --invert-match \ + '^deb\s+http://tagged\.snapshots\.deb\.tails\.boum.org/[^/]+/torproject(/|\s)' \ + | grep --extended-regexp --invert-match \ + '^deb\s+http://time-based\.snapshots\.deb\.tails\.boum.org/torproject/' \ + | sed --regexp-extended -e 's,^deb(\s+),deb-src\1,' \ + > "$TEMP_APT_SOURCES" + ;; + off) + rm "$TEMP_APT_SOURCES" + ;; + esac + + apt-get --yes update +} + +install_torbrowser_AppArmor_profiles() { + tmpdir="$(mktemp -d)" + ( + cd "$tmpdir" + apt-get source torbrowser-launcher/sid + install -m 0644 \ + torbrowser-launcher-*/apparmor/torbrowser.Browser.* \ + /etc/apparmor.d/ + install -m 0644 \ + torbrowser-launcher-*/apparmor/tunables/* \ + /etc/apparmor.d/tunables/ + ) + rm -r "$tmpdir" +} + +### Main + +toggle_src_APT_sources on +install_torbrowser_AppArmor_profiles +toggle_src_APT_sources off +(cd / && patch --forward --batch -p1 < "$PATCH") +rm "$PATCH" diff --git a/config/chroot_local-hooks/20-dconf_update b/config/chroot_local-hooks/20-dconf_update new file mode 100755 index 0000000000000000000000000000000000000000..6bcf8d30ef5c174a76307826081ebf2e3f2f42df --- /dev/null +++ b/config/chroot_local-hooks/20-dconf_update @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +# Update the system dconf databases so that /etc/dconf/db/local.d is +# taken into account. + +echo "Updating the system DConf databases" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed dconf-cli + +dconf update +chmod 0644 /etc/dconf/db/local diff --git a/config/chroot_local-hooks/20-root_bash_env b/config/chroot_local-hooks/20-root_bash_env new file mode 100755 index 0000000000000000000000000000000000000000..6f7cbceb8a5bb3069feb3411bf07cfea0b29fd2c --- /dev/null +++ b/config/chroot_local-hooks/20-root_bash_env @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +echo "Setting the root's bash environment" + +# ... so we have the expected environment in the Root Terminal + +echo ' +for dir in /usr/local/sbin /usr/local/bin; do + if ! echo "${PATH}" | grep -q --extended-regexp "(^|:)${dir}($|:)"; then + PATH="${dir}:${PATH}" + fi +done +' >> /root/.bashrc diff --git a/config/chroot_local-hooks/20-root_terminal b/config/chroot_local-hooks/20-root_terminal new file mode 100755 index 0000000000000000000000000000000000000000..71e40c3159acf93ca38840ae008f45ceca00b0d5 --- /dev/null +++ b/config/chroot_local-hooks/20-root_terminal @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +echo "Creating the Root Terminal .desktop file" + +TMP="$(mktemp -d)" +cd "${TMP}" +apt-get download gksu +dpkg-deb --extract gksu_*.deb . +mv ./usr/share/pixmaps/gksu-root-terminal.png /usr/share/pixmaps/ +sed 's@^Exec=.*$@Exec=/usr/local/bin/gnome-terminal-pkexec@' \ + ./usr/share/applications/gksu.desktop \ + > /usr/share/applications/root-terminal.desktop +cd / +rm -r "${TMP}" diff --git a/config/chroot_local-hooks/20-vim-symlink b/config/chroot_local-hooks/20-vim-symlink new file mode 100755 index 0000000000000000000000000000000000000000..8968eaf7d512dfd1ad9046657ca9ad4f34cd9071 --- /dev/null +++ b/config/chroot_local-hooks/20-vim-symlink @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +echo "Creating vim symlink" + +if [ -e /usr/bin/vim.tiny ]; then + update-alternatives --install /usr/bin/vim vim /usr/bin/vim.tiny 15 +else + echo "/usr/bin/vim.tiny doesn't exist; either that is a problem," \ + "or this hook should be removed" >&2 + exit 1 +fi diff --git a/config/chroot_local-hooks/20-xul-ext_symlinks b/config/chroot_local-hooks/20-xul-ext_symlinks new file mode 100755 index 0000000000000000000000000000000000000000..68a3de44f32cadc6f6ae7f36d690dca3c4c7ca97 --- /dev/null +++ b/config/chroot_local-hooks/20-xul-ext_symlinks @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +echo "Creating prefs override for Tor Launcher" + +# Import the TOR_LAUNCHER_INSTALL variable. +. /usr/local/lib/tails-shell-library/tor-browser.sh + +ln -s /etc/xul-ext/tor-launcher.js \ + "${TOR_LAUNCHER_INSTALL}/defaults/preferences/000system.js" diff --git a/config/chroot_local-hooks/22-plymouth b/config/chroot_local-hooks/22-plymouth new file mode 100755 index 0000000000000000000000000000000000000000..83b14febf0813eac6cba94a2c11b26791e363748 --- /dev/null +++ b/config/chroot_local-hooks/22-plymouth @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +# Install Plymouth (in lb 2.x, the "standard" packages list pulls +# console-common in, which plymouth conflicts with, so we have to deal +# with that at this stage.) + +echo "Installing Plymouth" + +apt-get --yes purge console-common +apt-get --yes install plymouth diff --git a/config/chroot_local-hooks/23-fake-gnome-backgrounds b/config/chroot_local-hooks/23-fake-gnome-backgrounds new file mode 100755 index 0000000000000000000000000000000000000000..cfd7eb2fef0494a5220705af513a0c2af74d1d48 --- /dev/null +++ b/config/chroot_local-hooks/23-fake-gnome-backgrounds @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e +set -u + +echo "Install a fake gnome-backgrounds package" + +# Import install_fake_package +. /usr/local/lib/tails-shell-library/build.sh + +REAL_PKG_VERSION=$(dpkg-query -W -f='${Version}\n' gnome-backgrounds) +FAKE_PKG_VERSION=${REAL_PKG_VERSION}+tails.fake1 +install_fake_package gnome-backgrounds "${FAKE_PKG_VERSION}" gnome diff --git a/config/chroot_local-hooks/30-disable-wayland-in-gdm b/config/chroot_local-hooks/30-disable-wayland-in-gdm new file mode 100755 index 0000000000000000000000000000000000000000..efe4107a3c7996b4ca8407e7fabbc675dd6a9802 --- /dev/null +++ b/config/chroot_local-hooks/30-disable-wayland-in-gdm @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +set -u +echo "Explicitly disable Wayland in GDM" +sed --in-place --regexp-extended \ + 's/^#WaylandEnable=false$/WaylandEnable=false/' /etc/gdm3/daemon.conf diff --git a/config/chroot_local-hooks/40-pinentry b/config/chroot_local-hooks/40-pinentry new file mode 100755 index 0000000000000000000000000000000000000000..0736147045e62a856b5201935101b957a9c34aee --- /dev/null +++ b/config/chroot_local-hooks/40-pinentry @@ -0,0 +1,23 @@ +#!/bin/sh + +set -eu + +echo "Selecting our preferred pinentry" + +for alternative in pinentry pinentry-x11 ; do + update-alternatives --set "$alternative" /usr/bin/pinentry-gtk-2 +done + +# XXX:Buster remove once Debian bug #869416 is fixed +mkdir -p /usr/lib/pinentry +dpkg-divert --add --rename --divert \ + /usr/lib/pinentry/pinentry-gtk-2 \ + /usr/bin/pinentry-gtk-2 + +cat > /usr/bin/pinentry-gtk-2 << 'EOF' +#!/bin/sh +. /usr/local/lib/tails-shell-library/gnome.sh +export_gnome_env +exec /usr/lib/pinentry/pinentry-gtk-2 "$@" +EOF +chmod 755 /usr/bin/pinentry-gtk-2 diff --git a/config/chroot_local-hooks/41-disable-ssh-agent b/config/chroot_local-hooks/41-disable-ssh-agent new file mode 100755 index 0000000000000000000000000000000000000000..6000a5d7d910cc28c9e0be8044bd4c80890c7436 --- /dev/null +++ b/config/chroot_local-hooks/41-disable-ssh-agent @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# Disable ssh-agent in /etc/X11/Xsession.options +# (seahorse / gnome-keyring are more user-friendly) + +echo "Disabling ssh-agent" + +OPTS_FILE='/etc/X11/Xsession.options' + +[ -f "${OPTS_FILE}" ] || exit 11 + +sed -i'' 's,^use-ssh-agent,#use-ssh-agent,' "${OPTS_FILE}" diff --git a/config/chroot_local-hooks/42-wrap-gdm-x-session b/config/chroot_local-hooks/42-wrap-gdm-x-session new file mode 100755 index 0000000000000000000000000000000000000000..b11363d42ed2a109daa171e865b8a8ebab8bafb0 --- /dev/null +++ b/config/chroot_local-hooks/42-wrap-gdm-x-session @@ -0,0 +1,11 @@ +#!/bin/sh + +set -eu + +echo "Wrapping gdm-x-session to limit the number of allowed failures" + +dpkg-divert --add --rename --divert \ + /usr/lib/gdm3/gdm-x-session.real \ + /usr/lib/gdm3/gdm-x-session + +ln -s /usr/lib/gdm3/gdm-x-session.tails /usr/lib/gdm3/gdm-x-session diff --git a/config/chroot_local-hooks/44-configure_console-setup b/config/chroot_local-hooks/44-configure_console-setup new file mode 100755 index 0000000000000000000000000000000000000000..932619ee91f796a6d2ffae15a91fcd4e21192a8c --- /dev/null +++ b/config/chroot_local-hooks/44-configure_console-setup @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "Configuring the console codeset to support more languages" + +sed -i -e 's,^CODESET=.*$,CODESET="Uni1",' /etc/default/console-setup diff --git a/config/chroot_local-hooks/44-remove-unused-AppArmor-profiles b/config/chroot_local-hooks/44-remove-unused-AppArmor-profiles new file mode 100755 index 0000000000000000000000000000000000000000..b2c113d1b71a819b644214bbc81b5f62562f886f --- /dev/null +++ b/config/chroot_local-hooks/44-remove-unused-AppArmor-profiles @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +echo "Deleting unused AppArmor profiles" + +( + cd /etc/apparmor.d + rm \ + apache2.d/phpsysinfo \ + sbin.klogd \ + sbin.syslogd \ + sbin.syslog-ng \ + usr.lib.dovecot.* \ + usr.sbin.dnsmasq \ + usr.sbin.dovecot \ + usr.sbin.identd \ + usr.sbin.mdnsd \ + usr.sbin.nmbd \ + usr.sbin.nscd \ + usr.sbin.smb* +) diff --git a/config/chroot_local-hooks/45-disable-unneeded-dbus-services b/config/chroot_local-hooks/45-disable-unneeded-dbus-services new file mode 100755 index 0000000000000000000000000000000000000000..8fb64b01e14cb22df4360046a16898cd5d9002b3 --- /dev/null +++ b/config/chroot_local-hooks/45-disable-unneeded-dbus-services @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +echo "Disabling unneeded D-Bus services" + +SERVICES_DIR=/usr/share/dbus-1/services + +[ -d "${SERVICES_DIR}" ] || exit 11 + +sed -i'' 's,^Exec=.*$,Exec=/bin/false,' \ + "${SERVICES_DIR}"/org.gnome.evolution.dataserver.*.service \ + "${SERVICES_DIR}"/org.gnome.Shell.CalendarServer.service + +for service in \ + "${SERVICES_DIR}"/org.freedesktop.Telepathy.AccountManager.service \ + "${SERVICES_DIR}"/org.freedesktop.Telepathy.MissionControl5.service ; do + if [ -f "$service" ]; then + echo "$service is back: consider disabling it" >&2 + exit 1 + fi +done diff --git a/config/chroot_local-hooks/45-enable-AppArmor-profiles b/config/chroot_local-hooks/45-enable-AppArmor-profiles new file mode 100755 index 0000000000000000000000000000000000000000..c83de47804011c63a3c6044e5dc1129187f84ecb --- /dev/null +++ b/config/chroot_local-hooks/45-enable-AppArmor-profiles @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "Enable various AppArmor profiles" + +rm /etc/apparmor.d/disable/usr.bin.thunderbird diff --git a/config/chroot_local-hooks/47-tweak_laptop-mode-tools b/config/chroot_local-hooks/47-tweak_laptop-mode-tools new file mode 100755 index 0000000000000000000000000000000000000000..ded180d3fb440372cdf87aab7eb49d9fc25f7b3d --- /dev/null +++ b/config/chroot_local-hooks/47-tweak_laptop-mode-tools @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +echo "Tweaking laptop-mode-tools" + +sed -i 's,^ENABLE_AUTO_MODULES=1$,ENABLE_AUTO_MODULES=0,' \ + /etc/laptop-mode/laptop-mode.conf + +sed -i 's,^CONTROL_RUNTIME_AUTOSUSPEND=1$,CONTROL_RUNTIME_AUTOSUSPEND=0,' \ + /etc/laptop-mode/conf.d/runtime-pm.conf diff --git a/config/chroot_local-hooks/50-dkms b/config/chroot_local-hooks/50-dkms new file mode 100755 index 0000000000000000000000000000000000000000..513a092f8466f258eca14590519cd464189f2256 --- /dev/null +++ b/config/chroot_local-hooks/50-dkms @@ -0,0 +1,50 @@ +#!/bin/sh + +set -e +set -u +set -x + +echo "Building VirtualBox guest modules" + +. /usr/share/tails/build/variables + +# Import ensure_hook_dependency_is_installed() +# and install_fake_package() +. /usr/local/lib/tails-shell-library/build.sh + +# Any -dkms package must be installed *after* dkms to be properly registered +ensure_hook_dependency_is_installed dkms + +ensure_hook_dependency_is_installed \ + virtualbox-guest-dkms + +for log in $(ls /var/lib/dkms/*/*/build/make.log); do + echo "---- $log" + cat "$log" +done + +# Ensure the modules were actually built and installed: when +# dkms.conf for a DKMS module includes a BUILD_EXCLUSIVE directive +# which does not match our kernel version, the modules won't be built +# and then we should abort the build. +for module in vboxguest vboxsf vboxvideo ; do + for modules_dir in /lib/modules/* ; do + found=$(find "$modules_dir" -name "${module}.ko" | wc -l) + if [ "$found" = 0 ]; then + echo "Can not find ${module} module in '${modules_dir}" >&2 + exit 1 + fi + done +done + +# virtualbox-guest-dkms's postrm script deletes any previously +# built binary module; let's delete it before the package gets purged. +rm /var/lib/dpkg/info/virtualbox-guest-dkms.prerm + +# Install a fake package so that the real virtualbox-guest-dkms can be purged +# when the clean-up for this hook happens, even if virtualbox-guest-utils +# depends on it. The 4th parameter needs to embed the real package version +# since there's a dependency on the source version between packages. +REAL_PKG_VERSION=$(dpkg-query -W -f='${Version}\n' virtualbox-guest-dkms) +FAKE_PKG_VERSION=${REAL_PKG_VERSION}+tails.fake1 +install_fake_package virtualbox-guest-dkms-dummy "${FAKE_PKG_VERSION}" kernel "virtualbox-guest-dkms (= ${REAL_PKG_VERSION})" diff --git a/config/chroot_local-hooks/51-update-bash.bashrc b/config/chroot_local-hooks/51-update-bash.bashrc new file mode 100755 index 0000000000000000000000000000000000000000..03cab0b20219c4578ea72d30748308a19007984e --- /dev/null +++ b/config/chroot_local-hooks/51-update-bash.bashrc @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e +set -u + +# Make /etc/bash.bashrc source /etc/bash.bashrc.d/* + +echo "Updating /etc/bash.bashrc" + +cat <> /etc/bash.bashrc +# The following code snippet is added by 'config/chroot_local-hooks/51-update-bash.bashrc' + +for file in /etc/bash.bashrc.d/*; +do + source "\$file" +done +EOF diff --git a/config/chroot_local-hooks/52-udev-watchdog b/config/chroot_local-hooks/52-udev-watchdog new file mode 100755 index 0000000000000000000000000000000000000000..3bcc31f2c7378874db9a2475a9759ad67e160d9a --- /dev/null +++ b/config/chroot_local-hooks/52-udev-watchdog @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +# Compile and install a custom udev-watchdog program + +echo "Compiling and installing a custom udev-watchdog program" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed build-essential binutils libudev-dev + +SRC="/usr/src/udev-watchdog.c" +DST="/usr/local/sbin/udev-watchdog" + +gcc -o "$DST" "$SRC" -Wall -ludev -lrt +strip --strip-all "$DST" diff --git a/config/chroot_local-hooks/52-update-rc.d b/config/chroot_local-hooks/52-update-rc.d new file mode 100755 index 0000000000000000000000000000000000000000..b0834f459df8380bba0573820276e0bf0435ffff --- /dev/null +++ b/config/chroot_local-hooks/52-update-rc.d @@ -0,0 +1,69 @@ +#!/bin/sh + +set -e + +### Tweak systemd unit files + +# Workaround for https://bugs.debian.org/714957 +systemctl enable memlockd.service + +# Enable our own systemd unit files +systemctl enable initramfs-shutdown.service +systemctl enable onion-grater.service +systemctl enable tails-synchronize-data-to-new-persistent-volume-on-shutdown.service +systemctl enable tails-autotest-broken-Xorg.service +systemctl enable tails-autotest-remote-shell.service +systemctl enable tails-set-wireless-devices-state.service +systemctl enable tails-shutdown-on-media-removal.service +systemctl enable tails-tor-has-bootstrapped.target +systemctl enable tails-wait-until-tor-has-bootstrapped.service +systemctl enable tails-tor-has-bootstrapped-flag-file.service +systemctl enable run-initramfs.mount +systemctl enable var-tmp.mount + +# Enable our own systemd user unit files +systemctl --global enable tails-add-GNOME-bookmarks.service +systemctl --global enable tails-additional-software-install.service +systemctl --global enable tails-configure-keyboard.service +systemctl --global enable tails-create-tor-browser-directories.service +systemctl --global enable tails-security-check.service +systemctl --global enable tails-upgrade-frontend.service +systemctl --global enable tails-virt-notify-user.service +systemctl --global enable tails-wait-until-tor-has-bootstrapped.service + +# Use socket activation only, to delay the startup of cupsd. +# In practice, on Jessie this means that cupsd is started during +# the initialization of the GNOME session, which is fine: by then, +# the persistent /etc/cups has been mounted. +# XXX: make sure it's the case on Stretch, adjust if not. +systemctl disable cups.service +systemctl enable cups.socket + +# We're starting NetworkManager and Tor ourselves. +# We disable tor.service (as opposed to tor@default.service) because +# it's an important goal to never start Tor before the user has had +# a chance to choose to do so in an obfuscated way: if some other +# package enables tor@whatever.service someday, disabling tor.service +# will disable it as well, while disabling tor@default.service would not. +systemctl disable tor.service +systemctl disable NetworkManager.service +systemctl disable NetworkManager-wait-online.service + +# systemd-networkd fallbacks to Google's nameservers when no other nameserver +# is provided by the network configuration. In Jessie, this service is disabled +# by default, but it feels safer to make this explicit. Besides, it might be +# that systemd-networkd vs. firewall setup ordering is suboptimal in this respect, +# so let's avoid any risk of DNS leaks here. +systemctl mask systemd-networkd.service + +# Do not sync the system clock to the hardware clock on shutdown +systemctl mask hwclock-save.service + +# Do not run timesyncd: we have our own time synchronization mechanism +systemctl mask systemd-timesyncd.service + +# apt-daily.service can only cause problems in our context (#12390) +systemctl mask apt-daily.timer + +# Do not let pppd-dns manage /etc/resolv.conf +systemctl mask pppd-dns.service diff --git a/config/chroot_local-hooks/53-thunderbird-menu b/config/chroot_local-hooks/53-thunderbird-menu new file mode 100755 index 0000000000000000000000000000000000000000..9501446840c01a79a9f987b1511fb86219eb042f --- /dev/null +++ b/config/chroot_local-hooks/53-thunderbird-menu @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +echo 'Updating thunderbird.desktop' +sed -i --regexp-extended \ + 's;^Exec=\S+;Exec=/usr/local/bin/thunderbird;' \ + /usr/share/applications/thunderbird.desktop diff --git a/config/chroot_local-hooks/53-vmlinuz_symlink b/config/chroot_local-hooks/53-vmlinuz_symlink new file mode 100755 index 0000000000000000000000000000000000000000..6cd08f8bd60971182b226f90cf4c5279a7c3fe1f --- /dev/null +++ b/config/chroot_local-hooks/53-vmlinuz_symlink @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +echo "Creating kernel and ramdisk symlinks" + +# Get version information for the (newest) installed kernel. +KERNEL="`/bin/ls -1 /boot/vmlinuz-* | tail -n 1`" +INITRD="`/bin/ls -1 /boot/initrd.img-* | tail -n 1`" + +if [ ! -e /vmlinuz ]; then + ln -s "$KERNEL" /vmlinuz +fi + +if [ ! -e /initrd.img ]; then + ln -s "$INITRD" /initrd.img +fi diff --git a/config/chroot_local-hooks/54-menu b/config/chroot_local-hooks/54-menu new file mode 100755 index 0000000000000000000000000000000000000000..3ba19a06f57717c9f669801bc4722056a364ed9a --- /dev/null +++ b/config/chroot_local-hooks/54-menu @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +echo "Registering and tweaking menus" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed xdg-utils + +for app in tails-installer tails-persistence-delete tails-persistence-setup tails-about tails-documentation org.boum.tails.additional-software-config ; do + xdg-desktop-menu install --novendor \ + /usr/share/desktop-directories/Tails.directory \ + "/usr/share/applications/${app}.desktop" +done + +rm \ + /usr/share/applications/gnome-online-accounts-panel.desktop \ + /usr/share/applications/laptop-mode-tools.desktop \ + /usr/share/applications/sniff.desktop + +sed -i'' --regexp-extended 's,^Exec=pidgin$,Exec=/usr/local/bin/pidgin,' \ + /usr/share/applications/pidgin.desktop + +# Run OpenPGP Applet automatically, but do not show it in the Applications menu +rm /etc/xdg/autostart/openpgp-applet.desktop +mv /usr/share/applications/openpgp-applet.desktop \ + /etc/xdg/autostart/ + +xdg-desktop-menu forceupdate diff --git a/config/chroot_local-hooks/55-update-mime-database b/config/chroot_local-hooks/55-update-mime-database new file mode 100755 index 0000000000000000000000000000000000000000..9c2ad512239aaa9945b6ef6e91a357833c903a95 --- /dev/null +++ b/config/chroot_local-hooks/55-update-mime-database @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e +set -u + +echo "Updating the shared MIME-Info database cache with our custom file associations" + +update-mime-database /usr/local/share/mime +update-mime-database /usr/share/mime diff --git a/config/chroot_local-hooks/56-disable-live-config-hooks b/config/chroot_local-hooks/56-disable-live-config-hooks new file mode 100755 index 0000000000000000000000000000000000000000..a85b423210e82c93e9615f11d23ecbb0c78d34be --- /dev/null +++ b/config/chroot_local-hooks/56-disable-live-config-hooks @@ -0,0 +1,9 @@ +#! /bin/sh + +set -e + +echo "Disabling some live-config hooks" + +# workaround live-config bug (LIVE_NOCONFIGS is not taken into account) +touch /var/lib/live/config/policykit +touch /var/lib/live/config/sudo diff --git a/config/chroot_local-hooks/58-create-tails-website-CA-bundle b/config/chroot_local-hooks/58-create-tails-website-CA-bundle new file mode 100755 index 0000000000000000000000000000000000000000..1bfb2435a49ed5ded671cd97e095db00377e3177 --- /dev/null +++ b/config/chroot_local-hooks/58-create-tails-website-CA-bundle @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +echo "Creating CA bundle for authenticating https://tails.boum.org/" + +BUNDLE=/usr/local/etc/ssl/certs/tails.boum.org-CA.pem + +mkdir -p $(dirname "${BUNDLE}") + +cat /etc/ssl/certs/AddTrust_External_Root.pem \ + /etc/ssl/certs/Lets-Encrypt-Authority-X3.pem \ + > "$BUNDLE" + +chmod a+r "$BUNDLE" diff --git a/config/chroot_local-hooks/59-libdvd-pkg b/config/chroot_local-hooks/59-libdvd-pkg new file mode 100755 index 0000000000000000000000000000000000000000..3c1d835b153d63020dd9fd1afbe1e8e145da4457 --- /dev/null +++ b/config/chroot_local-hooks/59-libdvd-pkg @@ -0,0 +1,32 @@ +#!/bin/sh +set -e +set -u + +echo "Installing libdvd-pkg" + +# Import install_fake_package +. /usr/local/lib/tails-shell-library/build.sh + +apt-get --yes install libdvd-pkg +dpkg-reconfigure libdvd-pkg + +# Create and install a fake libdvd-pkg package. This is necessary for +# libdvdcss2 (the actual dvd decoding package) which depends on +# libdvd-pkg. libdvd-pkg however depends on build-essential, which is +# explicitly removed. So instead we build/install a fake libdvd-pkg +# without the build-essential dependency to satisfy libdvdcss2. +LIBDVD_PKG_VERSION="$(dpkg-query -s libdvd-pkg | grep Version | cut -d ' ' -f2)+fake1" +install_fake_package libdvd-pkg "${LIBDVD_PKG_VERSION}" multimedia +rm -r /usr/src/libdvd-pkg + +# Verify installed packages: +for x in libdvd-pkg +do + dpkg -s $x + dpkg-query -W -f='${Version}\n' $x +done + +# Remove dangling symlink -- note that we absolutely do not want the +# functionality (automatic checks and upgrades for new css sources) +# that the removed script provides. +rm -f /etc/apt/apt.conf.d/88libdvdcss-pkg diff --git a/config/chroot_local-hooks/60-copy-syslinux-modules b/config/chroot_local-hooks/60-copy-syslinux-modules new file mode 100755 index 0000000000000000000000000000000000000000..d2926634570c636e79d3dc35b60dafc67dfe7962 --- /dev/null +++ b/config/chroot_local-hooks/60-copy-syslinux-modules @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +echo 'Adapting syslinux 6.x packaging to play well with live-build 2.x' + +cp -a /usr/lib/syslinux/modules/bios/ifcpu64.c32 \ + /usr/lib/syslinux/modules/bios/vesamenu.c32 \ + /usr/lib/ISOLINUX/isolinux.bin \ + /usr/lib/syslinux/ diff --git a/config/chroot_local-hooks/62-haveged b/config/chroot_local-hooks/62-haveged new file mode 100755 index 0000000000000000000000000000000000000000..8b977687e4d28e67578419b7399e23f0a58fcf26 --- /dev/null +++ b/config/chroot_local-hooks/62-haveged @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "Configuring haveged" + +echo 'DAEMON_ARGS="-w 2048"' >> /etc/default/haveged diff --git a/config/chroot_local-hooks/70-wget b/config/chroot_local-hooks/70-wget new file mode 100755 index 0000000000000000000000000000000000000000..291824f4c55fc2820fbd217601dc98eca564ae49 --- /dev/null +++ b/config/chroot_local-hooks/70-wget @@ -0,0 +1,23 @@ +#!/bin/sh +set -e + +echo 'Configuring wget' + +# We don't want the real binary to be in $PATH: +# Also note that wget uses the executable name in some help/error messages, +# so wget-real/etc. should be avoided. +mkdir -p /usr/lib/wget +dpkg-divert --add --rename --divert /usr/lib/wget/wget /usr/bin/wget + +# We don't want users or other applications using wget directly: +cat > /usr/bin/wget << 'EOF' +#!/bin/sh +unset http_proxy +unset HTTP_PROXY +unset https_proxy +unset HTTPS_PROXY + +exec torsocks /usr/lib/wget/wget --passive-ftp "$@" +EOF + +chmod 755 /usr/bin/wget diff --git a/config/chroot_local-hooks/80-block-network b/config/chroot_local-hooks/80-block-network new file mode 100755 index 0000000000000000000000000000000000000000..294958f0a98b9a39971c9baed192e9b80311c179 --- /dev/null +++ b/config/chroot_local-hooks/80-block-network @@ -0,0 +1,46 @@ +#!/bin/sh + +set -e + +echo "Generating blocklist for all network devices" + +is_net_module() { + # Here we assume that if any of the patterns below are matched, it + # is a network driver. This is not comprehensive, but should be + # enough for the staging directory (worst case we blacklist some + # shitty non-network driver by mistake). + /sbin/modinfo "${1}" | \ + grep -q --extended-regexp \ + -e "^depends:\s*(cfg|lib|mac)80211" \ + -e "^parm:\s*ifname:" +} + +net_module_filter() { + local path + while read path; do + if is_net_module "${path}"; then + echo "${path}" + fi + done +} + +generate_blocking_line() { + local name + local path + while read path; do + name="$(basename "${path}" .ko)" + printf "install ${name} /bin/true\n" + done +} + +BLACKLIST=/etc/modprobe.d/all-net-blacklist.conf + +( + find /lib/modules/*/kernel/drivers/net -name "*.ko" | \ + generate_blocking_line && \ + + # Let's try to find the network drivers in the staging directory as well + find /lib/modules/*/kernel/drivers/staging/ -name "*.ko" | \ + net_module_filter | \ + generate_blocking_line +) | sort -u > "${BLACKLIST}" diff --git a/config/chroot_local-hooks/97-versions b/config/chroot_local-hooks/97-versions new file mode 100755 index 0000000000000000000000000000000000000000..c7709645a8e3dd45e016064ca5a2bf86478826a8 --- /dev/null +++ b/config/chroot_local-hooks/97-versions @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +# Append some version information to /etc/amnesia/version + +echo "Appending some version information to /etc/amnesia/version" + +echo "live-boot: `dpkg-query -W -f='${Version}\n' live-boot`" \ + >> /etc/amnesia/version + +echo "live-config: `dpkg-query -W -f='${Version}\n' live-config`" \ + >> /etc/amnesia/version diff --git a/config/chroot_local-hooks/98-remove_unwanted_files b/config/chroot_local-hooks/98-remove_unwanted_files new file mode 100755 index 0000000000000000000000000000000000000000..43189ce75e9a8ba5d334a34b85082e76b1d41845 --- /dev/null +++ b/config/chroot_local-hooks/98-remove_unwanted_files @@ -0,0 +1,34 @@ +#!/bin/sh + +set -e + +echo "Removing unwanted files" + +# Get POTFILES_DOT_IN +. /usr/share/tails/build/variables + +find /usr/share/doc -type f -name changelog.gz -delete +find /usr/share/doc -type f -name changelog.Debian.gz -delete +find /usr/share/doc -type f -name NEWS.Debian.gz -delete + +# Remove .in files managed by intltool +rm $POTFILES_DOT_IN + +# These files are not needed after the Tor Browser has been installed +# (by the 10-tbb hook) +rm /usr/share/tails/tbb-*.txt + +# Remove the snakeoil SSL key pair generated by ssl-cert +find /etc/ssl/certs /etc/ssl/private | + while read f; do + if [ "$(readlink -f "$f")" = "/etc/ssl/certs/ssl-cert-snakeoil.pem" ] || \ + [ "$(readlink -f "$f")" = "/etc/ssl/private/ssl-cert-snakeoil.key" ]; then + rm "${f}" + fi + done +update-ca-certificates + +# Remove the kernel .map files which are only useful for kernel +# debugging (and slightly make things easier for malware, perhaps) and +# otherwise just occupy disk space. +rm -f /boot/*.map /boot/*.map-* diff --git a/config/chroot_local-hooks/98-remove_unwanted_packages b/config/chroot_local-hooks/98-remove_unwanted_packages new file mode 100755 index 0000000000000000000000000000000000000000..ce4d161c21e9cfb0dba8c58661d782028e2b702b --- /dev/null +++ b/config/chroot_local-hooks/98-remove_unwanted_packages @@ -0,0 +1,87 @@ +#!/bin/sh + +set -e + +# Import is_package_installed +. /usr/local/lib/tails-shell-library/common.sh + +echo "Removing unwanted packages" + +### Deinstall dev packages. + +# We use apt-get as aptitude doesn't know about globs. +# There are packages we could be tempted to remove but we can't: +# - gcc-*-base (libstdc++6 depends on it) +# - libgcc1 (apt depends on it) +# - cpp, cpp-* (big parts of GNOME depend on it) +apt-get --yes purge \ + '^linux-compiler-*' \ + '^linux-kbuild-*' \ + debhelper dpkg-dev \ + gcc gcc-6 \ + intltool-debian \ + libc6-dev \ + libelf-dev \ + linux-libc-dev \ + make \ + po-debconf \ + rsyslog \ + libdvdcss-dev + +### Deinstall a few unwanted packages that were pulled by tasksel +### since they have Priority: standard. +apt-get --yes purge \ + apt-listchanges \ + debian-faq \ + doc-debian \ + '^exim4*' \ + m4 \ + mlocate \ + ncurses-term \ + nfs-common \ + python3-reportbug \ + reportbug \ + telnet \ + texinfo \ + wamerican + +### Deinstall a few unwanted packages that were pulled by the xorg +### metapackage. +apt-get --yes purge \ + xfonts-100dpi \ + xfonts-75dpi \ + xfonts-base \ + xfonts-scalable + +### Remove packages that can get a different priority in the security +### archive (see https://bugs.debian.org/867668): +if is_package_installed mutt; then + apt-get --yes purge mutt +fi + +### Hotfix for 3.14: procmail is no longer known by apt in tagged +### snapshots, likely because no longer pulled by monkeysphere: +if is_package_installed procmail; then + apt-get --yes purge procmail +fi + +### Deinstall some other unwanted packages. +apt-get --yes purge \ + '^aptitude*' \ + krb5-locales \ + libdvdcss2-dbgsym \ + live-build \ + locales \ + rpcbind \ + tasksel \ + tasksel-data \ + tcpd + +### Deinstall some other unwanted packages whose regexp might not be match +### anything when building with partial, tagged APT snapshots. +if dpkg --get-selections | grep -qs -E '^geoclue'; then + apt-get --yes purge '^geoclue*' +fi + +### Deinstall dependencies of the just removed packages. +apt-get --yes --purge autoremove diff --git a/config/chroot_local-hooks/99-dedup_usr_share_doc b/config/chroot_local-hooks/99-dedup_usr_share_doc new file mode 100755 index 0000000000000000000000000000000000000000..b9e6c97552da8063938fc193d538827d54cd6f64 --- /dev/null +++ b/config/chroot_local-hooks/99-dedup_usr_share_doc @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +echo "Deduplicating files in /usr/share/doc" + +/usr/bin/hardlink -t /usr/share/doc +apt-get --yes purge hardlink diff --git a/config/chroot_local-hooks/99-disable-pam-secure-password-check b/config/chroot_local-hooks/99-disable-pam-secure-password-check new file mode 100755 index 0000000000000000000000000000000000000000..690edce6236ba3c4d9564bb1444c9d3dc8fb2c40 --- /dev/null +++ b/config/chroot_local-hooks/99-disable-pam-secure-password-check @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "Disabling PAM secure password check" + +sed -i 's/pam_unix.so obscure/pam_unix.so minlen=1/' /etc/pam.d/common-password diff --git a/config/chroot_local-hooks/99-etc-default-locale b/config/chroot_local-hooks/99-etc-default-locale new file mode 100755 index 0000000000000000000000000000000000000000..465e0ce0a576f2e74278fa0f1eee02f02b193919 --- /dev/null +++ b/config/chroot_local-hooks/99-etc-default-locale @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +echo "Creating /etc/default/locale" + +# /etc/default/locale is not a conffile. It is unowned, but primarily managed +# by the "locales" package's maintainer scripts. We purge that package +# in 98-remove_unwanted_packages (because we use locales-all instead), +# thus /etc/default/locale is removed. Various scripts of ours depend on this +# file to exist and contain a valid $LANG value. +# +# Tails Greeter's PostLogin script will later change this value according to +# the user's choice. + +echo 'LANG=en_US.UTF-8' > /etc/default/locale diff --git a/config/chroot_local-hooks/99-initramfs-compress b/config/chroot_local-hooks/99-initramfs-compress new file mode 100755 index 0000000000000000000000000000000000000000..ee9743085536552be753903c9b398d2684d77883 --- /dev/null +++ b/config/chroot_local-hooks/99-initramfs-compress @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +echo "Configuring compression of the initramfs" + +# Import ensure_hook_dependency_is_installed() +. /usr/local/lib/tails-shell-library/build.sh + +ensure_hook_dependency_is_installed initramfs-tools xz-utils fatresize + +# Compress the initramfs using a more size-wise efficient algorithm. +# We do this late in the build process because compressing with XZ +# takes much longer than compressing with the default algorithm +# and earlier stages of the build generate the initramfs quite a few times. +# live-build will regenerate it later on anyway, which will apply +# the settings we configure here. + +OPTS_FILE='/etc/initramfs-tools/initramfs.conf' + +[ -f "${OPTS_FILE}" ] || exit 11 + +sed -i'' 's,^COMPRESS=.*,COMPRESS=xz,' "${OPTS_FILE}" diff --git a/config/chroot_local-hooks/99-permissions b/config/chroot_local-hooks/99-permissions new file mode 100755 index 0000000000000000000000000000000000000000..fbf0c2237c52be507d2b922159eb3b7815a466a9 --- /dev/null +++ b/config/chroot_local-hooks/99-permissions @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +echo "Setting correct file permissions" + +chmod 00440 /etc/sudoers.d/* + +# NetworkManager requires these permissions +chmod 00600 /etc/NetworkManager/system-connections/* + +# For persistent Tor settings via Tor Launcher, the debian-tor user +# must be able to write into `/etc/tor`. +chown -R debian-tor:debian-tor /etc/tor + +# Otherwise, such files may be copied to /home/amnesia, and in turn +# to the persistent volume, with unsafe permissions. That's no big deal +# in /home/amnesia (that is itself not world-readable), *but* the root +# of the persistent volume has to be world-readable. +chmod -R go= /etc/skel/* /etc/skel/.[a-z]* diff --git a/config/chroot_local-hooks/99-remove_pyc b/config/chroot_local-hooks/99-remove_pyc new file mode 100755 index 0000000000000000000000000000000000000000..50220bdd02511f108fdbcce64e78b649f7897d2d --- /dev/null +++ b/config/chroot_local-hooks/99-remove_pyc @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +# Note: this must happen *after* 99-dedup_usr_share_doc +echo "Removing *.pyc" +find /usr -type f -name "*.pyc" -delete diff --git a/config/chroot_local-hooks/99-set_mtimes b/config/chroot_local-hooks/99-set_mtimes new file mode 100755 index 0000000000000000000000000000000000000000..6f33d4a764d917861fe1f669f0ed88644f09d42c --- /dev/null +++ b/config/chroot_local-hooks/99-set_mtimes @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +# Make IUKs smaller +echo "Setting mtime on large files whose content generally do not change" +touch --no-create -t 197001010000 \ + /usr/lib/locale/locale-archive \ + /usr/share/ppd/hplip/HP/*.ppd \ + /var/lib/anthy/anthy.dic \ + /var/lib/anthy/mkworddic/anthy.wdic diff --git a/config/chroot_local-hooks/99-zz-install-ASP-DPKG-hooks b/config/chroot_local-hooks/99-zz-install-ASP-DPKG-hooks new file mode 100644 index 0000000000000000000000000000000000000000..91a4519034ae46b21031483f151e097bfd45eb26 --- /dev/null +++ b/config/chroot_local-hooks/99-zz-install-ASP-DPKG-hooks @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e +set -u + +mv /etc/apt/apt.conf.d/80tails-additional-software.disabled \ + /etc/apt/apt.conf.d/80tails-additional-software diff --git a/config/chroot_local-hooks/99-zzz_check-for-dot-orig-files b/config/chroot_local-hooks/99-zzz_check-for-dot-orig-files new file mode 120000 index 0000000000000000000000000000000000000000..c1d644d71c88957c3771011fdbd3534b153897c7 --- /dev/null +++ b/config/chroot_local-hooks/99-zzz_check-for-dot-orig-files @@ -0,0 +1 @@ +01-check-for-dot-orig-files \ No newline at end of file diff --git a/config/chroot_local-hooks/99-zzz_check_uids_and_gids b/config/chroot_local-hooks/99-zzz_check_uids_and_gids new file mode 100755 index 0000000000000000000000000000000000000000..785b08072a86f92143afddfb9b92ebb7834c9347 --- /dev/null +++ b/config/chroot_local-hooks/99-zzz_check_uids_and_gids @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +echo "Checking UIDs and GIDs stability" + +if ! cmp "/usr/share/tails/build/passwd" "/etc/passwd" \ + || ! cmp "/usr/share/tails/build/group" "/etc/group" ; then + echo "/etc/passwd and/or /etc/group differs from expected:" >&2 + for file in passwd group; do + diff -Naur "/usr/share/tails/build/${file}" "/etc/${file}" >&2 || : + echo >&2 + echo "Content of '/etc/${file}':" >&2 + cat "/etc/${file}" >&2 + echo >&2 + done + echo "If these changes are innocuous, update these files in" \ + "config/chroot_local-includes/usr/share/tails/build/." >&2 + echo "See #15407 and #13426 for more context." >&2 + exit 1 +fi diff --git a/config/chroot_local-hooks/99-zzz_truncate_logs b/config/chroot_local-hooks/99-zzz_truncate_logs new file mode 100755 index 0000000000000000000000000000000000000000..1542fcd8c7b26d1862fe0418c90931f27a9cb5d9 --- /dev/null +++ b/config/chroot_local-hooks/99-zzz_truncate_logs @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +echo "Truncating log files" +for file in $(find /var/log/ -type f); do + : > "${file}" +done diff --git a/config/chroot_local-hooks/99-zzzzzz_reproducible-builds-post-processing b/config/chroot_local-hooks/99-zzzzzz_reproducible-builds-post-processing new file mode 100644 index 0000000000000000000000000000000000000000..55e0a01cef8d3f1797b870c0567c71d8c1db9aa3 --- /dev/null +++ b/config/chroot_local-hooks/99-zzzzzz_reproducible-builds-post-processing @@ -0,0 +1,48 @@ +#! /bin/sh + +set -e + +echo "Post processing filesystem to make it reproducible" + +if [ -z "${SOURCE_DATE_EPOCH}" ]; then + echo "SOURCE_DATE_EPOCH was not set!" >&2 + exit 1 +fi + +# These files are pretty useless for us and mainly occupy space on the +# image. They are, for instance, not useful for checking the +# authenticity of the filesystem (an external verification tool and +# source of these checksums would be required), and checking for +# corruption is less relevant in Tails' context, where the system +# partition is read-only (the point being: if they do differ, chances +# are problems would manifest in much more obvious ways). +rm /var/lib/dpkg/info/*.md5sums + +# Clear caches and remove precompiled code. These will be generated +# on-the-fly when needed instead of being shipped on the image, so +# we'll require a bit more RAM and startup times, while the image will +# be smaller (and more reproducible!). +rm /etc/console-setup/cached_setup_keyboard.sh +rm /var/cache/ldconfig/aux-cache +rm /var/lib/systemd/catalog/database + +# Empty non-deterministically generated file. If it exists and is empty, systemd +# will automatically set up a new unique ID. But if does not exist, systemd +# will populate /etc with preset unit settings, which will for example re-enable +# units we have disabled (#11970). +: > /etc/machine-id + +# Remove logs. +rm -r /var/lib/dkms/*/*/*/*/log + +# Post-process /etc/shadow by setting the sp_lstchg field to the number of days +# since SOURCE_DATE_EPOCH instead of 1st Jan 1970. (#12339) +# XXX:Buster: drop this if https://bugs.debian.org/857803 is fixed. +cut -d: -f1 /etc/shadow | \ + xargs -L1 \ + chage --lastday \ + "$(($(date --utc --date "@${SOURCE_DATE_EPOCH}" "+%s") / 86400))" + +# A user reported all executable bits of /etc/hostname being set when +# trying to reproduce Tails 3.1. See #13623 for details. +chmod u=rw,go=r /etc/hostname diff --git a/config/chroot_local-includes/etc/NetworkManager/conf.d/dns.conf b/config/chroot_local-includes/etc/NetworkManager/conf.d/dns.conf new file mode 100644 index 0000000000000000000000000000000000000000..d435aba99e5b4978136e05393f5434b2403d1ebc --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/conf.d/dns.conf @@ -0,0 +1,2 @@ +[main] +dns=none diff --git a/config/chroot_local-includes/etc/NetworkManager/conf.d/spoof-mac.conf b/config/chroot_local-includes/etc/NetworkManager/conf.d/spoof-mac.conf new file mode 100644 index 0000000000000000000000000000000000000000..369abcea9d7f43b7bad7543767139e9450fdbe6c --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/conf.d/spoof-mac.conf @@ -0,0 +1,3 @@ +[connection] +ethernet.cloned-mac-address=preserve +wifi.cloned-mac-address=preserve diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-firewall.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-firewall.sh new file mode 100755 index 0000000000000000000000000000000000000000..61f8ffccbce956091df6b7d0a943867e81475c6e --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-firewall.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +# Run whenever an interface gets "up", not otherwise: +if [ "$2" != "up" ]; then + exit 0 +fi + +[ -x /usr/sbin/ferm ] || exit 2 +/usr/sbin/ferm /etc/ferm/ferm.conf diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-resolv-over-clearnet b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-resolv-over-clearnet new file mode 100755 index 0000000000000000000000000000000000000000..088dcf792fb35487620e7de1d7f52761121ca9fb --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/00-resolv-over-clearnet @@ -0,0 +1,23 @@ +#!/bin/sh + +# This file is needed by the Unsafe Browser, and Tor while in bridge +# mode. + +# Run only when the interface is not "lo": +if [ -z "$1" ] || [ "$1" = "lo" ]; then + exit 0 +fi + +RESOLV_CLEARNET_CONF=/etc/resolv-over-clearnet.conf +# We are truncating the file as opposed to deleting + recreating it +# for a reason: we mount-bind this file over /etc/resolv.conf for +# processes (via mount namespaces) that we want to give clearnet DNS +# resolving, and deleting + recreating it would mean that the +# bind-mount would remain outdated. +echo -n > "${RESOLV_CLEARNET_CONF}" +IP4_REGEX='[0-9]{1,3}(\.[0-9]{1,3}){3}' +for ns in ${IP4_NAMESERVERS}; do + if echo "${ns}" | grep --extended-regexp -q "^${IP4_REGEX}$"; then + echo "nameserver ${ns}" >> "${RESOLV_CLEARNET_CONF}" + fi +done diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/01-wait-for-notification-recipient.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/01-wait-for-notification-recipient.sh new file mode 100755 index 0000000000000000000000000000000000000000..ca9dea45a294f094559b7733a0d663f8510c3551 --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/01-wait-for-notification-recipient.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# When a non-loopback interface comes up, wait for the Live user's GNOME Shell +# to come up. Wait 120 times one second maximum. + +[ -n "$1" ] || exit 0 +[ "$1" != "lo" ] || exit 0 +[ "$2" = "up" ] || exit 0 + +MAX_WAIT=120 + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +for i in $(seq 1 ${MAX_WAIT}) ; do + if pgrep -u "${LIVE_USERNAME}" '^ibus-daemon' >/dev/null 2>&1 ; then + break + fi + sleep 1 +done diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh new file mode 100755 index 0000000000000000000000000000000000000000..e0a1714a50b57e4173fcdbaf851021e188741457 --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# We don't start Tor automatically so *this* is the time +# when it is supposed to start. + +# Run only when the interface is not "lo": +if [ -z "$1" ] || [ "$1" = "lo" ]; then + exit 0 +fi + +if [ "$2" = "up" ]; then + : # go on, that's what this script is for +elif [ "${2}" = "down" ]; then + systemctl --no-block stop tails-tor-has-bootstrapped.target + exit 0 +else + exit 0 +fi + +# Import tor_control_setconf(), TOR_LOG +. /usr/local/lib/tails-shell-library/tor.sh + +# Import tails_netconf() +. /usr/local/lib/tails-shell-library/tails-greeter.sh + +# It's safest that Tor is not running when messing with its logs. +systemctl stop tor@default.service + +# We depend on grepping stuff from the Tor log (especially for +# tordate/20-time.sh), so deleting it seems like a Good Thing(TM). +rm -f "${TOR_LOG}" + +# Let the rest of the system know that Tor is not working at the moment. +# This matters e.g. if we have already bootstrapped. +systemctl --no-block restart tails-tor-has-bootstrapped.target + +# The Tor syscall sandbox is not compatible with managed proxies. +# We could possibly detect whether the user has configured any such +# thing via Tor Launcher later (e.g. in 60-tor-ready.sh), +# but then we would have to restart Tor again to enable the sandbox. +# Let's avoid doing that, and enable the Sandbox only if no special Tor +# configuration is needed. Too bad users who simply need to configure +# a HTTP proxy or allowed firewall ports won't get the sandboxing, but +# much better than nothing. +if [ "$(tails_netconf)" = "direct" ]; then + tor_set_in_torrc Sandbox 1 +fi + +# We would like Tor to be started during init time, even before the +# network is up, and then send it a SIGHUP here to make it start +# bootstrapping swiftly, but it doesn't work because of a bug in +# Tor. Details: +# * https://trac.torproject.org/projects/tor/ticket/1247 +# * https://tails.boum.org/bugs/tor_vs_networkmanager/ +# To work around this we restart Tor, in various ways, no matter the +# case below. +TOR_SYSTEMD_OVERRIDE_DIR="/lib/systemd/system/tor@default.service.d" +TOR_RESOLV_CONF_OVERRIDE="${TOR_SYSTEMD_OVERRIDE_DIR}/50-resolv-conf-override.conf" +if [ "$(tails_netconf)" = "obstacle" ]; then + # Override /etc/resolv.conf for tor only, so it can use a clearnet + # DNS server to resolve hostnames used for pluggable transport and + # proxies. + if [ ! -e "${TOR_RESOLV_CONF_OVERRIDE}" ]; then + mkdir -p "${TOR_SYSTEMD_OVERRIDE_DIR}" + cat > "${TOR_RESOLV_CONF_OVERRIDE}" </dev/null + + # Tor is unreliable with picking a circuit after time change + systemctl restart tor@default.service +} + +tor_cert_valid_after() { + # Only print the last = freshest match + sed -n 's/^.*certificate lifetime runs from \(.*\) through.*$/\1/p' \ + ${TOR_LOG} | tail -n 1 +} + +tor_cert_lifetime_invalid() { + # To be sure that we only grep relevant information, we + # should delete the log when Tor is started, which we do + # in 10-tor.sh. + # The log severity will be "warn" if bootstrapping with + # authorities and "info" with bridges. + grep -q "\[\(warn\|info\)\] Certificate \(not yet valid\|already expired\)\." \ + ${TOR_LOG} +} + +# This check is blocking until Tor reaches either of two states: +# 1. Tor completes a handshake with an authority (or bridge). +# 2. Tor fails the handshake with all authorities (or bridges). +# Since 2 essentially is the negation of 1, one of them will happen, +# so it won't block forever. Hence we shouldn't need a timeout. +is_clock_way_off() { + log "Checking if system clock is way off" + until [ "$(tor_bootstrap_progress)" -gt 10 ]; do + if tor_cert_lifetime_invalid; then + return 0 + fi + sleep 1 + done + return 1 +} + +start_notification_helper() { + export_gnome_env + exec /bin/su -c /usr/local/lib/tails-htp-notify-user "$LIVE_USERNAME" & +} + + +### Main + +start_notification_helper + +# Delegate time setting to other daemons if Tor connections work +if tor_is_working; then + log "Tor has already opened a circuit" +else + # Since Tor 0.2.3.x Tor doesn't download a consensus for + # clocks that are more than 30 days in the past or 2 days in + # the future. For such clock skews we set the time to the + # authority's cert's valid-after date. + if is_clock_way_off; then + log "The clock is so badly off that Tor cannot download a consensus. Setting system time to the authority's cert's valid-after date and trying to fetch a consensus again..." + date --set="$(tor_cert_valid_after)" > /dev/null + systemctl reload tor@default.service + fi + wait_for_tor_consensus + maybe_set_time_from_tor_consensus +fi + +wait_for_working_tor + +touch $TORDATE_DONE_FILE + +log "Restarting htpdate" +systemctl restart htpdate.service +log "htpdate service restarted with return code $?" diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh new file mode 100755 index 0000000000000000000000000000000000000000..91e8514b1aaa62239ea34dbdadd39e9a8a8acc46 --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh @@ -0,0 +1,40 @@ +#! /bin/sh + +# Run only when the interface is not "lo": +if [ -z "$1" ] || [ "$1" = "lo" ]; then + exit 0 +fi + +# Run whenever an interface gets "up", not otherwise: +if [ "$2" != "up" ]; then + exit 0 +fi + +# Get LANG +. /etc/default/locale +export LANG + +# Initialize gettext support +. gettext.sh +TEXTDOMAIN="tails" +export TEXTDOMAIN + +while ! /usr/local/sbin/tor-has-bootstrapped; do + sleep 1 +done + +# We now know that whatever Tor settings we are using works, so if Tor +# Launcher is still running, we can just kill it and make sure it +# won't start next network reconnect. A reason for this happening is +# if Tor was restarted by tordate, e.g. if the clock was to incorrect. +TOR_LAUNCHER_PROCESS_REGEX="firefox-unconfined -?-app.*tor-launcher-standalone" +if pgrep -f "${TOR_LAUNCHER_PROCESS_REGEX}"; then + pkill -f "${TOR_LAUNCHER_PROCESS_REGEX}" + pref=/home/tor-launcher/.tor-launcher/profile.default/prefs.js + sed -i '/^user_pref("extensions\.torlauncher\.prompt_at_startup"/d' "${pref}" + echo 'user_pref("extensions.torlauncher.prompt_at_startup", false);' >> "${pref}" +fi + +/usr/local/sbin/tails-notify-user \ + "`gettext \"Tor is ready\"`" \ + "`gettext \"You can now access the Internet.\"`" diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/70-upgrade-additional-software.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/70-upgrade-additional-software.sh new file mode 100755 index 0000000000000000000000000000000000000000..1220b082a8cb0c4964c861401d799b4f128eada8 --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/70-upgrade-additional-software.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +# Run only when the interface is not "lo": +if [ -z "$1" ] || [ "$1" = "lo" ]; then + exit 0 +fi + +# Run whenever an interface gets "up", not otherwise: +if [ "$2" != "up" ]; then + exit 0 +fi + +/bin/systemctl --no-block start tails-additional-software-upgrade.path diff --git a/config/chroot_local-includes/etc/NetworkManager/system-connections/Wired connection b/config/chroot_local-includes/etc/NetworkManager/system-connections/Wired connection new file mode 100644 index 0000000000000000000000000000000000000000..74b07c12a6e45e11a4bc79d43e7cf123f20071bf --- /dev/null +++ b/config/chroot_local-includes/etc/NetworkManager/system-connections/Wired connection @@ -0,0 +1,14 @@ +[802-3-ethernet] +duplex=full + +[connection] +id=Wired connection +uuid=370b30e3-97ef-4516-b5e2-38ee0e942f72 +type=802-3-ethernet +timestamp=1395406011 + +[ipv6] +method=ignore + +[ipv4] +method=auto diff --git a/config/chroot_local-includes/etc/X11/Xsession.d/92tails-set-SSH_AUTH_SOCK b/config/chroot_local-includes/etc/X11/Xsession.d/92tails-set-SSH_AUTH_SOCK new file mode 100644 index 0000000000000000000000000000000000000000..2fc3199fbffabafce0860730b051a765a8bb252b --- /dev/null +++ b/config/chroot_local-includes/etc/X11/Xsession.d/92tails-set-SSH_AUTH_SOCK @@ -0,0 +1 @@ +export SSH_AUTH_SOCK="/run/user/$(id -u)/keyring/ssh" diff --git a/config/chroot_local-includes/etc/apparmor.d/abstractions/onionshare b/config/chroot_local-includes/etc/apparmor.d/abstractions/onionshare new file mode 100644 index 0000000000000000000000000000000000000000..b90e2436a662ec64edabec91e13819e2c530356b --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/abstractions/onionshare @@ -0,0 +1,29 @@ + #include + #include + #include + #include + + # Why are these not in abstractions/python? + /usr/lib{,32,64}/python{2,3}.[0-9]/__pycache__/ rw, + /usr/lib{,32,64}/python{2,3}.[0-9]/__pycache__/* rw, + /usr/lib{,32,64}/python{2,3}.[0-9]/**/__pycache__/ rw, + /usr/lib{,32,64}/python{2,3}.[0-9]/**/__pycache__/* rw, + /usr/lib{,32,64}/python{2,3}/**/__pycache__/ rw, + /usr/lib{,32,64}/python{2,3}/**/__pycache__/* rw, + + /bin/dash rix, + /proc/*/mounts r, + /proc/*/fd/ r, + /sbin/ldconfig rix, + /sbin/ldconfig.real rix, + /bin/uname rix, + /etc/mime.types r, + /usr/share/onionshare/ r, + /usr/share/onionshare/** r, + /tmp/ rw, + /tmp/** rw, + + # Allow read on almost anything in @{HOME}. Lenient, but + # private-files-strict is in effect. + owner @{HOME}/ r, + owner @{HOME}/[^.]** r, diff --git a/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare b/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare new file mode 100644 index 0000000000000000000000000000000000000000..6453771dba4da95a94b4a36f499ad62a299075c8 --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare @@ -0,0 +1,2 @@ +# Site-specific additions and overrides for usr.bin.onionshare. +# For more details, please see /etc/apparmor.d/local/README. diff --git a/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare-gui b/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare-gui new file mode 100644 index 0000000000000000000000000000000000000000..fa5ba3f0b3315b8c5d2c85b3d12f0961402c160b --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/local/usr.bin.onionshare-gui @@ -0,0 +1,2 @@ +# Site-specific additions and overrides for usr.bin.onionshare-gui. +# For more details, please see /etc/apparmor.d/local/README. diff --git a/config/chroot_local-includes/etc/apparmor.d/tunables/alias.d/tails b/config/chroot_local-includes/etc/apparmor.d/tunables/alias.d/tails new file mode 100644 index 0000000000000000000000000000000000000000..69c0d89d4431aa0108d2b0ed1b0786262a88307a --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/tunables/alias.d/tails @@ -0,0 +1,3 @@ +alias / -> /lib/live/mount/overlay/, +alias / -> /lib/live/mount/rootfs/*.squashfs/, + diff --git a/config/chroot_local-includes/etc/apparmor.d/tunables/home.d/tails b/config/chroot_local-includes/etc/apparmor.d/tunables/home.d/tails new file mode 100644 index 0000000000000000000000000000000000000000..2ef750a493ec6eeb6a6450a2a00aa7d3781da541 --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/tunables/home.d/tails @@ -0,0 +1 @@ +@{HOMEDIRS}+=/lib/live/mount/overlay/home/ diff --git a/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare b/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare new file mode 100644 index 0000000000000000000000000000000000000000..1c14ccc18487a177b231cec59f7ba716bd20a911 --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare @@ -0,0 +1,10 @@ +#include + +/usr/bin/onionshare { + #include + + /usr/bin/ r, + /usr/bin/onionshare r, + + #include +} diff --git a/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare-gui b/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare-gui new file mode 100644 index 0000000000000000000000000000000000000000..746dadc1b3e360af357bd900e13983ac6f4f6e48 --- /dev/null +++ b/config/chroot_local-includes/etc/apparmor.d/usr.bin.onionshare-gui @@ -0,0 +1,28 @@ +#include + +/usr/bin/onionshare-gui { + #include + #include + #include + + /usr/bin/ r, + /usr/bin/onionshare-gui r, + /proc/*/cmdline r, + + # The freedesktop.org abstraction doesn't allow `k` + /usr/share/icons/*/index.theme k, + + # Why do these still emit audit journal entries? + owner @{HOME}/.config/ibus/bus/ rw, + owner @{HOME}/.config/ibus/bus/* rw, + deny @{HOME}/.ICEauthority r, + + deny /etc/machine-id r, + deny /var/lib/dbus/machine-id.* rw, + + # Accessibility support + owner /{,var/}run/user/*/at-spi2-*/ rw, + owner /{,var/}run/user/*/at-spi2-*/** rw, + + #include +} diff --git a/config/chroot_local-includes/etc/apt/apt.conf.d/12nolang b/config/chroot_local-includes/etc/apt/apt.conf.d/12nolang new file mode 100644 index 0000000000000000000000000000000000000000..cfddd65a1b586ff6ac5e6bc60b121866f923dfa9 --- /dev/null +++ b/config/chroot_local-includes/etc/apt/apt.conf.d/12nolang @@ -0,0 +1 @@ +Acquire::Languages { "en"; }; diff --git a/config/chroot_local-includes/etc/apt/apt.conf.d/14keep-debs b/config/chroot_local-includes/etc/apt/apt.conf.d/14keep-debs new file mode 100644 index 0000000000000000000000000000000000000000..6f50c2d3bd4034c2c7a55e3a5b338ba8ab9176de --- /dev/null +++ b/config/chroot_local-includes/etc/apt/apt.conf.d/14keep-debs @@ -0,0 +1 @@ +Binary::apt::APT::Keep-Downloaded-Packages "true"; diff --git a/config/chroot_local-includes/etc/apt/apt.conf.d/80tails-additional-software.disabled b/config/chroot_local-includes/etc/apt/apt.conf.d/80tails-additional-software.disabled new file mode 100644 index 0000000000000000000000000000000000000000..5a18b873a6974763de4713a3c7071a316be8bbd4 --- /dev/null +++ b/config/chroot_local-includes/etc/apt/apt.conf.d/80tails-additional-software.disabled @@ -0,0 +1,5 @@ +# This configuration should not run during Tails build. It is enabled in the +# end of the build by /config/chroot_local-hooks/99-zz-install-ASP-DPKG-hooks +DPkg::Pre-Install-Pkgs { "/usr/local/sbin/tails-additional-software apt-pre"; }; +DPkg::Post-Invoke { "/usr/local/sbin/tails-additional-software apt-post"; }; +DPkg::Tools::Options::/usr/local/sbin/tails-additional-software::Version "3"; diff --git a/config/chroot_local-includes/etc/asound.conf b/config/chroot_local-includes/etc/asound.conf new file mode 100644 index 0000000000000000000000000000000000000000..d8eb4cf315944de969c39ef7d8de3b20159638cd --- /dev/null +++ b/config/chroot_local-includes/etc/asound.conf @@ -0,0 +1,16 @@ +# Use PulseAudio by default +pcm.!default { + type pulse + fallback "sysdefault" + hint { + show on + description "Default ALSA Output (currently PulseAudio Sound Server)" + } +} + +ctl.!default { + type pulse + fallback "sysdefault" +} + +# vim:set ft=alsaconf: diff --git a/config/chroot_local-includes/etc/bash.bashrc.d/replace-su-with-sudo.sh b/config/chroot_local-includes/etc/bash.bashrc.d/replace-su-with-sudo.sh new file mode 100755 index 0000000000000000000000000000000000000000..3fe81fb7c6327a957534a167a9c74f64c7acad77 --- /dev/null +++ b/config/chroot_local-includes/etc/bash.bashrc.d/replace-su-with-sudo.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Replace su by a message to use sudo. +# +# In Tails, the administration password doesn't work with 'su'. New +# users in particular may be puzzled by the authentication failures +# while trying to 'su' using administration password. +# +# This script introduces 'su' function for non-root users. The 'su' +# function executes '/usr/local/bin/replace-su-with-sudo', which asks +# them to use 'sudo' instead of 'su'. +# +# https://redmine.tails.boum.org/code/issues/15583 + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +# Only add the 'su' function for the desktop user. +[ "$USER" == "$LIVE_USERNAME" ] || return + +su (){ + /usr/local/bin/replace-su-with-sudo +} diff --git a/config/chroot_local-includes/etc/dbus-1/session.d/im.pidgin.purple.PurpleService.conf b/config/chroot_local-includes/etc/dbus-1/session.d/im.pidgin.purple.PurpleService.conf new file mode 100644 index 0000000000000000000000000000000000000000..732e11d3e303104d49a268bc591fcd01e278c398 --- /dev/null +++ b/config/chroot_local-includes/etc/dbus-1/session.d/im.pidgin.purple.PurpleService.conf @@ -0,0 +1,9 @@ + + + + + + + diff --git a/config/chroot_local-includes/etc/dconf/db/local.d/00_Tails_defaults b/config/chroot_local-includes/etc/dconf/db/local.d/00_Tails_defaults new file mode 100644 index 0000000000000000000000000000000000000000..e90fac7dda13e2e8cf2bcadb19dab47462995b49 --- /dev/null +++ b/config/chroot_local-includes/etc/dconf/db/local.d/00_Tails_defaults @@ -0,0 +1,75 @@ +[apps/seahorse/listing] +item-filter='' +sidebar-visible=true + +[desktop/gnome/crypto/pgp] +keyservers = ['hkp://jirk5u4osbsr34t5.onion'] + +[org/gnome/desktop/a11y] +always-show-universal-access-status=true + +[org/gnome/desktop/background] +show-desktop-icons = true +picture-uri='file:///usr/share/tails/desktop_wallpaper.png' + +[org/gnome/desktop/interface] +clock-show-date=true +menus-have-icons=true + +[org/gnome/desktop/lockdown] +disable-lock-screen = true +disable-log-out = true +disable-user-switching = true + +[org/gnome/desktop/media-handling] +automount = false +automount-open = false +autorun-x-content-start-app = @as [] +autorun-x-content-ignore = @as [] + +[org/gnome/desktop/screensaver] +lock-enabled = true +picture-uri = 'file:///usr/share/tails/screensaver_background.png' +user-switch-enabled = false + +[org/gnome/desktop/sound] +event-sounds=false + +[org/gnome/desktop/wm/preferences] +button-layout = ':minimize,maximize,close' + +[org/gnome/gedit/preferences/editor] +create-backup-copy = false + +[org/gnome/nautilus/desktop] +volumes-visible = false + +[org/gnome/nautilus/icon-view] +default-zoom-level = 'small' + +[org/gnome/desktop/peripherals/touchpad] +natural-scroll = true +tap-to-click = true +two-finger-scrolling-enabled = true + +[org/gnome/settings-daemon/plugins/media-keys] +custom-keybindings=['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/'] +screensaver='' + +[org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0] +binding='l' +command='tails-screen-locker' +name='Lock Screen' + +[org/gnome/settings-daemon/plugins/power] +power-button-action = 'nothing' +lid-close-ac-action = 'blank' +lid-close-battery-action = 'blank' + +[org/gnome/shell] +enabled-extensions = ['apps-menu@gnome-shell-extensions.gcampax.github.com', 'places-menu@gnome-shell-extensions.gcampax.github.com', 'window-list@gnome-shell-extensions.gcampax.github.com', 'TopIcons@phocean.net', 'status-menu-helper@tails.boum.org', 'torstatus@tails.boum.org'] +favorite-apps=['tor-browser.desktop', 'thunderbird.desktop', 'pidgin.desktop', 'keepassx.desktop', 'gnome-terminal.desktop'] + +[org/gnome/shell/extensions/topicons] +tray-pos='right' +tray-order=4 diff --git a/config/chroot_local-includes/etc/dconf/profile/user b/config/chroot_local-includes/etc/dconf/profile/user new file mode 100644 index 0000000000000000000000000000000000000000..aca0641f52a51cb922d107396deb358187410231 --- /dev/null +++ b/config/chroot_local-includes/etc/dconf/profile/user @@ -0,0 +1,2 @@ +user-db:user +system-db:local diff --git a/config/chroot_local-includes/etc/default/htpdate.pools b/config/chroot_local-includes/etc/default/htpdate.pools new file mode 100644 index 0000000000000000000000000000000000000000..45d46fb13f0685b80a480cc9836219b5aa063b5e --- /dev/null +++ b/config/chroot_local-includes/etc/default/htpdate.pools @@ -0,0 +1,3 @@ +HTP_POOL_1="boum.org,espiv.net,db.debian.org,epic.org,mail.riseup.net,leap.se,squat.net,tachanka.org,www.1984.is,www.eff.org,www.immerda.ch,www.privacyinternational.org,www.torproject.org" +HTP_POOL_2="cve.mitre.org,en.wikipedia.org,lkml.org,thepiratebay.org,www.apache.org,getfedora.org,www.democracynow.org,www.duckduckgo.com,www.gnu.org,www.kernel.org,www.mozilla.org,www.stackexchange.com,www.startpage.com,www.xkcd.com" +HTP_POOL_3="encrypted.google.com,github.com,login.live.com,login.yahoo.com,secure.flickr.com,tumblr.com,twitter.com,www.adobe.com,www.gandi.net,www.myspace.com,www.paypal.com,www.rackspace.com,www.sony.com" diff --git a/config/chroot_local-includes/etc/default/htpdate.user-agent b/config/chroot_local-includes/etc/default/htpdate.user-agent new file mode 100644 index 0000000000000000000000000000000000000000..e5aa63614e252e2b720d0ca70219cf5d90980e55 --- /dev/null +++ b/config/chroot_local-includes/etc/default/htpdate.user-agent @@ -0,0 +1 @@ +HTTP_USER_AGENT="Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0" diff --git a/config/chroot_local-includes/etc/dhcp/dhclient-enter-hooks.d/disable_make_resolv_conf b/config/chroot_local-includes/etc/dhcp/dhclient-enter-hooks.d/disable_make_resolv_conf new file mode 100755 index 0000000000000000000000000000000000000000..24bec42d8cae5fa3aea287b6a8ddfccce6f2b0c2 --- /dev/null +++ b/config/chroot_local-includes/etc/dhcp/dhclient-enter-hooks.d/disable_make_resolv_conf @@ -0,0 +1 @@ +make_resolv_conf() { : ; } diff --git a/config/chroot_local-includes/etc/dpkg/origins/Tails b/config/chroot_local-includes/etc/dpkg/origins/Tails new file mode 100644 index 0000000000000000000000000000000000000000..cc26612883da5c0176b1d800b5d8b8fb587032d1 --- /dev/null +++ b/config/chroot_local-includes/etc/dpkg/origins/Tails @@ -0,0 +1,4 @@ +Vendor: Tails +Vendor-URL: https://tails.boum.org/ +Bugs: mailto:tails@boum.org +Parent: Debian diff --git a/config/chroot_local-includes/etc/dpkg/origins/default b/config/chroot_local-includes/etc/dpkg/origins/default new file mode 120000 index 0000000000000000000000000000000000000000..fe4b4b9256d6c031a8fa654542f9d2510220369f --- /dev/null +++ b/config/chroot_local-includes/etc/dpkg/origins/default @@ -0,0 +1 @@ +Tails \ No newline at end of file diff --git a/config/chroot_local-includes/etc/environment b/config/chroot_local-includes/etc/environment new file mode 100644 index 0000000000000000000000000000000000000000..afa3fabaf61f206e515239f9133aea3e475dd876 --- /dev/null +++ b/config/chroot_local-includes/etc/environment @@ -0,0 +1,10 @@ +NODE_PATH=/usr/local/lib/nodejs + +SOCKS_SERVER=127.0.0.1:9050 +SOCKS5_SERVER=127.0.0.1:9050 + +# Have Qt applications use the Adwaita theme +QT_STYLE_OVERRIDE=adwaita + +# Add our Python version independent search path +PYTHONPATH=/usr/local/lib/python3/dist-packages diff --git a/config/chroot_local-includes/etc/ferm/ferm.conf b/config/chroot_local-includes/etc/ferm/ferm.conf new file mode 100644 index 0000000000000000000000000000000000000000..e8edef060fc5aba9a86743f25e7dc2900cb907cb --- /dev/null +++ b/config/chroot_local-includes/etc/ferm/ferm.conf @@ -0,0 +1,179 @@ +# -*- mode: conf[space] -*- +# +# Configuration file for ferm(1). +# + +# When ferm starts initially during early boot, the "amnesia" user does not +# exist yet, so we have to use its UID (#7018). +def $amnesia_uid = 1000; + +# IPv4 +domain ip { + table filter { + chain INPUT { + policy DROP; + + # Established incoming connections are accepted. + mod state state (ESTABLISHED) ACCEPT; + + # Traffic on the loopback interface is accepted. + interface lo ACCEPT; + } + + chain OUTPUT { + policy DROP; + + # Established outgoing connections are accepted. + mod state state (ESTABLISHED) ACCEPT; + + # White-list access to local resources + outerface lo { + # Related outgoing ICMP packets are accepted. + mod state state (RELATED) proto icmp ACCEPT; + + # White-list access to Tor's SOCKSPort's + daddr 127.0.0.1 proto tcp syn dport 9050 { + mod owner uid-owner _apt ACCEPT; + mod owner uid-owner proxy ACCEPT; + mod owner uid-owner nobody ACCEPT; + } + daddr 127.0.0.1 proto tcp syn mod multiport destination-ports (9050 9062 9150) { + mod owner uid-owner $amnesia_uid ACCEPT; + } + daddr 127.0.0.1 proto tcp syn dport 9062 { + mod owner uid-owner htp ACCEPT; + mod owner uid-owner tails-iuk-get-target-file ACCEPT; + mod owner uid-owner tails-upgrade-frontend ACCEPT; + } + + # White-list access to Tor's ControlPort + daddr 127.0.0.1 proto tcp dport 9052 { + # Needed for running the Tor control port filter + mod owner uid-owner root ACCEPT; + } + + # White-list access to the Tor control port filter + daddr 127.0.0.1 proto tcp dport 9051 { + mod owner uid-owner $amnesia_uid ACCEPT; + mod owner uid-owner tor-launcher ACCEPT; + } + + # White-list access to Tor's TransPort + daddr 127.0.0.1 proto tcp dport 9040 { + mod owner uid-owner $amnesia_uid ACCEPT; + } + + # White-list access to system DNS and Tor's DNSPort + daddr 127.0.0.1 proto udp dport (53 5353) { + mod owner uid-owner $amnesia_uid ACCEPT; + mod owner uid-owner _apt DROP; + } + + # White-list access to the accessibility daemon + daddr 127.0.0.1 proto tcp syn dport 4101 { + mod owner uid-owner $amnesia_uid ACCEPT; + mod owner uid-owner Debian-gdm ACCEPT; + } + + # White-list access to CUPS + daddr 127.0.0.1 proto tcp syn dport 631 { + mod owner uid-owner $amnesia_uid ACCEPT; + } + + # White-list access to OnionShare + daddr 127.0.0.1 proto tcp syn dport 17600:17650 { + mod owner uid-owner $amnesia_uid ACCEPT; + } + } + + # clearnet is allowed to connect to any TCP port via the + # external interfaces (but lo is blocked so it cannot interfere + # with Tor etc) including DNS on the LAN. UDP DNS queries are + # also allowed. + outerface ! lo mod owner uid-owner clearnet { + proto tcp ACCEPT; + proto udp dport domain ACCEPT; + } + + # Tor is allowed to do anything it wants to. + mod owner uid-owner debian-tor { + proto tcp syn mod state state (NEW) ACCEPT; + proto udp dport domain ACCEPT; + } + + # Local network connections should not go through Tor but DNS shall be + # rejected. (Note that we exclude the VirtualAddrNetwork used for + # .onion:s here.) + daddr (10.0.0.0/8 172.16.0.0/12 192.168.0.0/16) @subchain "lan" { + proto tcp dport domain REJECT; + proto udp dport domain REJECT; + proto tcp dport netbios-ns REJECT; + proto udp dport netbios-ns REJECT; + ACCEPT; + } + + # Everything else is logged and dropped. + LOG log-prefix "Dropped outbound packet: " log-level debug log-uid; + REJECT reject-with icmp-port-unreachable; + } + + chain FORWARD { + policy DROP; + } + } + + table nat { + chain PREROUTING { + policy ACCEPT; + } + + chain POSTROUTING { + policy ACCEPT; + } + + chain OUTPUT { + policy ACCEPT; + + # .onion mapped addresses redirection to Tor. + daddr 127.192.0.0/10 proto tcp REDIRECT to-ports 9040; + + # Redirect system DNS to Tor's DNSport + daddr 127.0.0.1 proto udp dport 53 REDIRECT to-ports 5353; + } + } +} + +# IPv6: +domain ip6 { + table filter { + chain INPUT { + policy DROP; + + # White-list access to the accessibility daemon + interface lo saddr ::1 daddr ::1 proto tcp { + dport 4101 ACCEPT; + sport 4101 mod state state (ESTABLISHED) ACCEPT; + } + + } + + chain FORWARD { + policy DROP; + } + + chain OUTPUT { + policy DROP; + + # White-list access to the accessibility daemon + outerface lo saddr ::1 daddr ::1 proto tcp { + dport 4101 mod owner uid-owner $amnesia_uid ACCEPT; + dport 4101 mod owner uid-owner Debian-gdm ACCEPT; + sport 4101 mod state state (ESTABLISHED) ACCEPT; + } + + # Everything else is logged and dropped. + LOG log-prefix "Dropped outbound packet: " log-level debug log-uid; + REJECT reject-with icmp6-port-unreachable; + } + } +} diff --git a/config/chroot_local-includes/etc/gitconfig b/config/chroot_local-includes/etc/gitconfig new file mode 100644 index 0000000000000000000000000000000000000000..aa3eeafbbe3bccaa736267c7ebc35f31ca808f44 --- /dev/null +++ b/config/chroot_local-includes/etc/gitconfig @@ -0,0 +1,4 @@ +[color] + ui = auto +[transfer] + fsckObjects = true diff --git a/config/chroot_local-includes/etc/hostname b/config/chroot_local-includes/etc/hostname new file mode 100644 index 0000000000000000000000000000000000000000..a13877bbae9af183ea57054922f566582863b781 --- /dev/null +++ b/config/chroot_local-includes/etc/hostname @@ -0,0 +1 @@ +amnesia diff --git a/config/chroot_local-includes/etc/initramfs-tools/modules b/config/chroot_local-includes/etc/initramfs-tools/modules new file mode 100644 index 0000000000000000000000000000000000000000..fe6c605354e7ab8b74346ed5b95eaf7ad13c1754 --- /dev/null +++ b/config/chroot_local-includes/etc/initramfs-tools/modules @@ -0,0 +1 @@ +nls_ascii diff --git a/config/chroot_local-includes/etc/live/config b/config/chroot_local-includes/etc/live/config new file mode 120000 index 0000000000000000000000000000000000000000..881bd52d8e877845cb7d66cbeb22a038fa5f7f4b --- /dev/null +++ b/config/chroot_local-includes/etc/live/config @@ -0,0 +1 @@ +config.d \ No newline at end of file diff --git a/config/chroot_local-includes/etc/live/config.conf.d b/config/chroot_local-includes/etc/live/config.conf.d new file mode 120000 index 0000000000000000000000000000000000000000..881bd52d8e877845cb7d66cbeb22a038fa5f7f4b --- /dev/null +++ b/config/chroot_local-includes/etc/live/config.conf.d @@ -0,0 +1 @@ +config.d \ No newline at end of file diff --git a/config/chroot_local-includes/etc/live/config.d/hostname.conf b/config/chroot_local-includes/etc/live/config.d/hostname.conf new file mode 100644 index 0000000000000000000000000000000000000000..266833c76211c6caac4e5a192145a0d1235ae2af --- /dev/null +++ b/config/chroot_local-includes/etc/live/config.d/hostname.conf @@ -0,0 +1 @@ +LIVE_HOSTNAME=amnesia diff --git a/config/chroot_local-includes/etc/live/config.d/noroot.conf b/config/chroot_local-includes/etc/live/config.d/noroot.conf new file mode 100644 index 0000000000000000000000000000000000000000..2d9df3b939422caa34b1e741269ffa8fceed94ce --- /dev/null +++ b/config/chroot_local-includes/etc/live/config.d/noroot.conf @@ -0,0 +1 @@ +LIVE_NOCONFIGS="${LIVE_NOCONFIGS},sudo,policykit" diff --git a/config/chroot_local-includes/etc/live/config.d/user-default-groups.conf b/config/chroot_local-includes/etc/live/config.d/user-default-groups.conf new file mode 100644 index 0000000000000000000000000000000000000000..6c99b77898a32891a28860d2dce1d5bc6d4debc0 --- /dev/null +++ b/config/chroot_local-includes/etc/live/config.d/user-default-groups.conf @@ -0,0 +1 @@ +LIVE_USER_DEFAULT_GROUPS="cdrom dialout floppy video plugdev netdev powerdev scanner lp lpadmin vboxsf" diff --git a/config/chroot_local-includes/etc/live/config.d/username.conf b/config/chroot_local-includes/etc/live/config.d/username.conf new file mode 100644 index 0000000000000000000000000000000000000000..8f6faf68374649a5603ffba968f7d1a78b728694 --- /dev/null +++ b/config/chroot_local-includes/etc/live/config.d/username.conf @@ -0,0 +1 @@ +LIVE_USERNAME=amnesia diff --git a/config/chroot_local-includes/etc/mailname b/config/chroot_local-includes/etc/mailname new file mode 100644 index 0000000000000000000000000000000000000000..2fbb50c4a8dc7dae6bd07d08c3f7d02ccb2818b0 --- /dev/null +++ b/config/chroot_local-includes/etc/mailname @@ -0,0 +1 @@ +localhost diff --git a/config/chroot_local-includes/etc/memlockd.cfg b/config/chroot_local-includes/etc/memlockd.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a2907fe2d6ef90d25fa46c672690a0d83a19c8bd --- /dev/null +++ b/config/chroot_local-includes/etc/memlockd.cfg @@ -0,0 +1,20 @@ ++/bin/cat ++/bin/echo ++/bin/grep ++/bin/kill ++/bin/loginctl ++/bin/ls ++/bin/mkdir ++/bin/mktemp ++/bin/mount ++/bin/mv ++/bin/plymouth ++/bin/rm ++/bin/sh ++/bin/sleep ++/bin/systemctl +/lib/systemd/system-shutdown/tails ++/lib/systemd/systemd-shutdown ++/usr/bin/eject ++/usr/bin/pkill ++/usr/local/sbin/udev-watchdog diff --git a/config/chroot_local-includes/etc/modprobe.d/loop.conf b/config/chroot_local-includes/etc/modprobe.d/loop.conf new file mode 100644 index 0000000000000000000000000000000000000000..40eeac77b34940e5ce370c6182444dc252a52f12 --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/loop.conf @@ -0,0 +1 @@ +options loop max_loop=32 diff --git a/config/chroot_local-includes/etc/modprobe.d/no-bluetooth.conf b/config/chroot_local-includes/etc/modprobe.d/no-bluetooth.conf new file mode 100644 index 0000000000000000000000000000000000000000..d71fc1c8328cf88acbf9cfbf5514f5e5a6e94c09 --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/no-bluetooth.conf @@ -0,0 +1,3 @@ +install bluetooth /bin/true +install bnep /bin/true +install btusb /bin/true diff --git a/config/chroot_local-includes/etc/modprobe.d/no-conntrack-helper.conf b/config/chroot_local-includes/etc/modprobe.d/no-conntrack-helper.conf new file mode 100644 index 0000000000000000000000000000000000000000..9f4e2dafcd0ac8f4437666e6660da167b0c27df4 --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/no-conntrack-helper.conf @@ -0,0 +1 @@ +options nf_conntrack nf_conntrack_helper=0 diff --git a/config/chroot_local-includes/etc/modprobe.d/no-mei.conf b/config/chroot_local-includes/etc/modprobe.d/no-mei.conf new file mode 100644 index 0000000000000000000000000000000000000000..7a5147972bd5d6fad2da66c9b4aa22013ae5469d --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/no-mei.conf @@ -0,0 +1,2 @@ +install mei-me /bin/true +install mei /bin/true diff --git a/config/chroot_local-includes/etc/modprobe.d/no-n-hdlc.conf b/config/chroot_local-includes/etc/modprobe.d/no-n-hdlc.conf new file mode 100644 index 0000000000000000000000000000000000000000..272bbfed5f1fda0b1cf437f885a9502e2320e84d --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/no-n-hdlc.conf @@ -0,0 +1,2 @@ +# Protect against CVE-2017-2636 +install n-hdlc /bin/true diff --git a/config/chroot_local-includes/etc/modprobe.d/no-pc-speaker.conf b/config/chroot_local-includes/etc/modprobe.d/no-pc-speaker.conf new file mode 100644 index 0000000000000000000000000000000000000000..b46792e5a70a900bf70ec9857378661d5d39d17e --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/no-pc-speaker.conf @@ -0,0 +1 @@ +blacklist pcspkr diff --git a/config/chroot_local-includes/etc/modprobe.d/uncommon-network-protocols.conf b/config/chroot_local-includes/etc/modprobe.d/uncommon-network-protocols.conf new file mode 100644 index 0000000000000000000000000000000000000000..92966bddc89474883fe70f241fba1ad2aedd84a1 --- /dev/null +++ b/config/chroot_local-includes/etc/modprobe.d/uncommon-network-protocols.conf @@ -0,0 +1,4 @@ +install dccp /bin/true +install sctp /bin/true +install rds /bin/true +install tipc /bin/true diff --git a/config/chroot_local-includes/etc/onion-grater.d/onioncircuits.yml b/config/chroot_local-includes/etc/onion-grater.d/onioncircuits.yml new file mode 100644 index 0000000000000000000000000000000000000000..5dfa9351ef209a2583c94ae33cbe83a60a700d61 --- /dev/null +++ b/config/chroot_local-includes/etc/onion-grater.d/onioncircuits.yml @@ -0,0 +1,22 @@ +--- +- apparmor-profiles: + - '/usr/bin/onioncircuits' + users: + - 'amnesia' + commands: + GETINFO: + - 'version' + - 'circuit-status' + - 'stream-status' + - 'ns/id/[a-fA-F0-9]+' + - 'ip-to-country/\d+\.\d+\.\d+\.\d+' + confs: + usemicrodescriptors: + __owningcontrollerprocess: + events: + SIGNAL: + suppress: true + CONF_CHANGED: + suppress: true + STREAM: + CIRC: diff --git a/config/chroot_local-includes/etc/onion-grater.d/onionshare.yml b/config/chroot_local-includes/etc/onion-grater.d/onionshare.yml new file mode 100644 index 0000000000000000000000000000000000000000..5f864be5392b13353cc4df67b0a7e69cddccaead --- /dev/null +++ b/config/chroot_local-includes/etc/onion-grater.d/onionshare.yml @@ -0,0 +1,22 @@ +--- +- apparmor-profiles: + - '/usr/bin/onionshare' + - '/usr/bin/onionshare-gui' + users: + - 'amnesia' + commands: + GETINFO: + - 'version' + - 'onions/current' + ADD_ONION: + - 'NEW:BEST Port=80,176([0-4][0-9]|50)' + DEL_ONION: + - '.+' + confs: + __owningcontrollerprocess: + events: + SIGNAL: + suppress: true + CONF_CHANGED: + suppress: true + HS_DESC: diff --git a/config/chroot_local-includes/etc/onion-grater.d/tor-browser.yml b/config/chroot_local-includes/etc/onion-grater.d/tor-browser.yml new file mode 100644 index 0000000000000000000000000000000000000000..8ea933058915bff68431ca788d5f335d7867f820 --- /dev/null +++ b/config/chroot_local-includes/etc/onion-grater.d/tor-browser.yml @@ -0,0 +1,18 @@ +--- +- apparmor-profiles: + - 'torbrowser_firefox' + users: + - 'amnesia' + commands: + SIGNAL: + - 'NEWNYM' + GETINFO: + - 'circuit-status' + - 'net/listeners/socks' + - 'ns/id/[a-fA-F0-9]+' + - 'ip-to-country/\d+\.\d+\.\d+\.\d+' + confs: + bridge: + events: + STREAM: + restrict-stream-events: true diff --git a/config/chroot_local-includes/etc/onion-grater.d/tor-launcher.yml b/config/chroot_local-includes/etc/onion-grater.d/tor-launcher.yml new file mode 100644 index 0000000000000000000000000000000000000000..7416fadde68f23dd9fbf5227700add81ddcd24d6 --- /dev/null +++ b/config/chroot_local-includes/etc/onion-grater.d/tor-launcher.yml @@ -0,0 +1,26 @@ +--- +- apparmor-profiles: + - '/usr/local/lib/tor-browser/firefox-unconfined' + users: + - 'tor-launcher' + commands: + SAVECONF: + - '' + GETINFO: + - 'status/bootstrap-phase' + confs: + UseBridges: ['', '.*'] + Bridge: ['', '.*'] + Socks4Proxy: ['', '.*'] + Socks5Proxy: ['', '.*'] + HTTPSProxy: ['', '.*'] + Socks5ProxyUsername: ['', '.*'] + Socks5ProxyPassword: ['', '.*'] + HTTPSProxyAuthenticator: ['', '.*'] + ReachableAddresses: ['', '.*'] + DisableNetwork: ['0', '1'] + events: + STATUS_CLIENT: + NOTICE: + WARN: + ERR: diff --git a/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.cups.pkla b/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.cups.pkla new file mode 100644 index 0000000000000000000000000000000000000000..84152228652c2aa3b88569cfa62e4ce312b30990 --- /dev/null +++ b/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.cups.pkla @@ -0,0 +1,54 @@ +[Get/Set server settings] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.server-settings +ResultActive=yes + +[Get list of available devices] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.devices-get +ResultActive=yes + +[Set a printer as default printer] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.printer-set-default +ResultActive=yes + +[Enable/Disable a printer] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.printer-enable +ResultActive=yes + +[Add/Remove/Edit a local printer] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.printer-local-edit +ResultActive=yes + +[Add/Remove/Edit a remote printer] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.printer-remote-edit +ResultActive=yes + +[Add/Remove/Edit a class] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.class-edit +ResultActive=yes + +[Restart/Cancel/Edit a job] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.job-edit +ResultActive=yes + +[Restart/Cancel/Edit a job owned by another user] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.job-not-owned-edit +ResultActive=yes + +[Change printer settings] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.all-edit +ResultActive=yes + +[Add/Remove/Edit a printer] +Identity=unix-user:amnesia +Action=org.opensuse.cupspkhelper.mechanism.printeraddremove +ResultActive=yes diff --git a/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.pkla b/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.pkla new file mode 100644 index 0000000000000000000000000000000000000000..0cdd41802c601c3d9f65457ed3888fb18bd5d31e --- /dev/null +++ b/config/chroot_local-includes/etc/polkit-1/localauthority/10-vendor.d/org.boum.tails.pkla @@ -0,0 +1,26 @@ +[Modify internal storage devices] +Identity=unix-user:tails-persistence-setup +Action=org.freedesktop.udisks2.modify-device-system +ResultAny=yes +ResultActive=yes +ResultInactive=yes + +[Mount storage devices] +Identity=unix-user:tails-persistence-setup +Action=org.freedesktop.udisks2.filesystem-mount +ResultAny=yes + +[Mount internal storage devices] +Identity=unix-user:tails-persistence-setup +Action=org.freedesktop.udisks2.filesystem-mount-system +ResultAny=yes + +[Unlock encrypted storage devices] +Identity=unix-user:tails-persistence-setup +Action=org.freedesktop.udisks2.encrypted-unlock-system +ResultAny=yes + +[Open a device] +Identity=unix-user:amnesia +Action=org.freedesktop.udisks2.open-device +ResultActive=yes diff --git a/config/chroot_local-includes/etc/resolv.conf b/config/chroot_local-includes/etc/resolv.conf new file mode 100644 index 0000000000000000000000000000000000000000..bbc8559cd54f10539c63a07c81138c23f24665e0 --- /dev/null +++ b/config/chroot_local-includes/etc/resolv.conf @@ -0,0 +1 @@ +nameserver 127.0.0.1 diff --git a/config/chroot_local-includes/etc/skel/.bash_logout b/config/chroot_local-includes/etc/skel/.bash_logout new file mode 100644 index 0000000000000000000000000000000000000000..de4f5f75d7ccd3a5b62bd2ce683ed678a5cb72c2 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.bash_logout @@ -0,0 +1,7 @@ +# ~/.bash_logout: executed by bash(1) when login shell exits. + +# when leaving the console clear the screen to increase privacy + +if [ "$SHLVL" = 1 ]; then + [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q +fi diff --git a/config/chroot_local-includes/etc/skel/.bashrc b/config/chroot_local-includes/etc/skel/.bashrc new file mode 100644 index 0000000000000000000000000000000000000000..e0f7d2c03eda78c6a9238093584ce571dc18c8a7 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.bashrc @@ -0,0 +1,99 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +[ -z "$PS1" ] && return + +# don't put duplicate lines in the history. See bash(1) for more options +# don't overwrite GNU Midnight Commander's setting of `ignorespace'. +export HISTCONTROL=$HISTCONTROL${HISTCONTROL+,}ignoredups +# ... or force ignoredups and ignorespace +export HISTCONTROL=ignoreboth + +# append to the history file, don't overwrite it +shopt -s histappend + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# make less more friendly for non-text input files, see lesspipe(1) +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, unless we know we "want" color) +case "$TERM" in + xterm-color) color_prompt=yes;; +esac + +# uncomment for a colored prompt, if the terminal has the capability; turned +# off by default to not distract the user: the focus in a terminal window +# should be on the output of commands, not on the prompt +force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. + +#if [ -f ~/.bash_aliases ]; then +# . ~/.bash_aliases +#fi + +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + eval "`dircolors -b`" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# some more ls aliases +alias ll='ls -l' +alias la='ls -A' +alias l='ls -CF' + +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if [ -f /etc/bash_completion ]; then + . /etc/bash_completion +fi diff --git a/config/chroot_local-includes/etc/skel/.config/Trolltech.conf b/config/chroot_local-includes/etc/skel/.config/Trolltech.conf new file mode 100644 index 0000000000000000000000000000000000000000..07637ef502fcf5c7f8330587e6cebc8472ff5a7e --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.config/Trolltech.conf @@ -0,0 +1,2 @@ +[Qt] +style=adwaita diff --git a/config/chroot_local-includes/etc/skel/.config/keepassx/keepassx2.ini b/config/chroot_local-includes/etc/skel/.config/keepassx/keepassx2.ini new file mode 100644 index 0000000000000000000000000000000000000000..64814ec590e332b4592bf013fc7ef6c846b74d2f --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.config/keepassx/keepassx2.ini @@ -0,0 +1,6 @@ +[General] +AutoSaveAfterEveryChange=true +ShowToolbar=true +LastOpenedDatabases=/home/amnesia/Persistent/keepassx.kdbx +LastDatabases=/home/amnesia/Persistent/keepassx.kdbx +LastDir=/home/amnesia/Persistent/ \ No newline at end of file diff --git a/config/chroot_local-includes/etc/skel/.electrum/config b/config/chroot_local-includes/etc/skel/.electrum/config new file mode 100644 index 0000000000000000000000000000000000000000..9b65c41fa5f6ab15ce112b453fd782b625230335 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.electrum/config @@ -0,0 +1,6 @@ +{ + "auto_connect": true, + "coin_chooser": "Privacy", + "proxy": "socks5:localhost:9050", + "server": "" +} diff --git a/config/chroot_local-includes/etc/skel/.gnome2/accels/.placeholder b/config/chroot_local-includes/etc/skel/.gnome2/accels/.placeholder new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/config/chroot_local-includes/etc/skel/.gnome2/keyrings/default b/config/chroot_local-includes/etc/skel/.gnome2/keyrings/default new file mode 100644 index 0000000000000000000000000000000000000000..31340c77289456a4bc4b688f949d619639c515ee --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.gnome2/keyrings/default @@ -0,0 +1 @@ +tails diff --git a/config/chroot_local-includes/etc/skel/.gnome2/keyrings/tails.keyring b/config/chroot_local-includes/etc/skel/.gnome2/keyrings/tails.keyring new file mode 100644 index 0000000000000000000000000000000000000000..fcba514f4a966b3bcb9d9d89cd943947aced11b5 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.gnome2/keyrings/tails.keyring @@ -0,0 +1,6 @@ +[keyring] +display-name=tails +ctime=0 +mtime=0 +lock-on-idle=false +lock-after=false diff --git a/config/chroot_local-includes/etc/skel/.gnome2_private/.placeholder b/config/chroot_local-includes/etc/skel/.gnome2_private/.placeholder new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/config/chroot_local-includes/etc/skel/.gnupg/dirmngr.conf b/config/chroot_local-includes/etc/skel/.gnupg/dirmngr.conf new file mode 100644 index 0000000000000000000000000000000000000000..44352fbf3dda55522be36290cb6b5135fc2c98b9 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.gnupg/dirmngr.conf @@ -0,0 +1,2 @@ +use-tor +keyserver hkp://jirk5u4osbsr34t5.onion diff --git a/config/chroot_local-includes/etc/skel/.gnupg/gpg-agent.conf b/config/chroot_local-includes/etc/skel/.gnupg/gpg-agent.conf new file mode 100644 index 0000000000000000000000000000000000000000..2ecba948ebfc19f01346c4b9104d6cd5863fec41 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.gnupg/gpg-agent.conf @@ -0,0 +1 @@ +no-grab diff --git a/config/chroot_local-includes/etc/skel/.gnupg/gpg.conf b/config/chroot_local-includes/etc/skel/.gnupg/gpg.conf new file mode 100644 index 0000000000000000000000000000000000000000..c3ab7e5c90f16917f237c938413b3e180d5e8473 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.gnupg/gpg.conf @@ -0,0 +1,68 @@ +# +# This is an implementation of the Riseup OpenPGP Best Practices +# https://help.riseup.net/en/security/message-security/openpgp/best-practices +# + + +#----------------------------- +# default key +#----------------------------- + +# The default key to sign with. If this option is not used, the default key is +# the first key found in the secret keyring + +#default-key 0xD8692123C4065DEA5E0F3AB5249B39D24F25E3B6 + + +#----------------------------- +# behavior +#----------------------------- + +# Disable inclusion of the version string in ASCII armored output +no-emit-version + +# Disable comment string in clear text signatures and ASCII armored messages +no-comments + +# Display long key IDs +keyid-format 0xlong + +# List all keys (or the specified ones) along with their fingerprints +with-fingerprint + +# Display the calculated validity of user IDs during key listings +list-options show-uid-validity +verify-options show-uid-validity + +# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to +# the agent before it asks for a passphrase. +use-agent + + +#----------------------------- +# keyserver +#----------------------------- + +# When searching for a key with --search-keys, include keys that are marked on +# the keyserver as revoked +keyserver-options include-revoked + + +#----------------------------- +# algorithm and ciphers +#----------------------------- + +# list of personal digest preferences. When multiple digests are supported by +# all recipients, choose the strongest one +personal-cipher-preferences AES256 AES192 AES CAST5 + +# list of personal digest preferences. When multiple ciphers are supported by +# all recipients, choose the strongest one +personal-digest-preferences SHA512 SHA384 SHA256 SHA224 + +# message digest algorithm used when signing a key +cert-digest-algo SHA512 + +# This preference list is used for new keys and becomes the default for +# "setpref" in the edit menu +default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed diff --git a/config/chroot_local-includes/etc/skel/.local/share/applications/mimeapps.list b/config/chroot_local-includes/etc/skel/.local/share/applications/mimeapps.list new file mode 100644 index 0000000000000000000000000000000000000000..301d35e7259c17cb19ef0384d16658eef8238037 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.local/share/applications/mimeapps.list @@ -0,0 +1,19 @@ +# XXX: Stretch -- the seahorse associations in here fix: +# - https://bugs.freedesktop.org/show_bug.cgi?id=93656 +# - Tails#10889 +# - Tails#10571 +# - Tails#10943 + +[Default Applications] +application/pgp-encrypted=seahorse-pgp-encrypted.desktop +application/pgp-keys=seahorse-pgp-keys.desktop +application/pgp-signature=seahorse-pgp-signature.desktop +application/x-iwork-keynote-sffkey=seahorse-pgp-keys.desktop +x-scheme-handler/mailto=thunderbird.desktop + +[Added Associations] +application/pgp-encrypted=seahorse-pgp-encrypted.desktop +application/pgp-keys=seahorse-pgp-keys.desktop +application/pgp-signature=seahorse-pgp-signature.desktop +application/x-iwork-keynote-sffkey=seahorse-pgp-keys.desktop +x-scheme-handler/mailto=thunderbird.desktop diff --git a/config/chroot_local-includes/etc/skel/.monkeysphere/monkeysphere.conf b/config/chroot_local-includes/etc/skel/.monkeysphere/monkeysphere.conf new file mode 100644 index 0000000000000000000000000000000000000000..130adddef9b116852df6c6ed4f5d231bb4aa351b --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.monkeysphere/monkeysphere.conf @@ -0,0 +1,2 @@ +KEYSERVER=hkp://2eghzlv2wwcq7u7y.onion + diff --git a/config/chroot_local-includes/etc/skel/.mozilla/firefox/bookmarks/places.sqlite.in b/config/chroot_local-includes/etc/skel/.mozilla/firefox/bookmarks/places.sqlite.in new file mode 100644 index 0000000000000000000000000000000000000000..afee2fbab7501f4447410d287d31b443835c4fc1 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.mozilla/firefox/bookmarks/places.sqlite.in @@ -0,0 +1,77 @@ +PRAGMA foreign_keys=OFF; +PRAGMA user_version=35; +BEGIN TRANSACTION; +CREATE TABLE moz_places ( id INTEGER PRIMARY KEY, url LONGVARCHAR, title LONGVARCHAR, rev_host LONGVARCHAR, visit_count INTEGER DEFAULT 0, hidden INTEGER DEFAULT 0 NOT NULL, typed INTEGER DEFAULT 0 NOT NULL, favicon_id INTEGER, frecency INTEGER DEFAULT -1 NOT NULL, last_visit_date INTEGER , guid TEXT, foreign_count INTEGER DEFAULT 0 NOT NULL, url_hash INTEGER DEFAULT 0 NOT NULL ); +INSERT INTO "moz_places" VALUES(1,'https://tails.boum.org/',NULL,'gro.muob.sliat.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(2,'file:///usr/share/doc/tails/website/index.en.html',NULL,'.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(3,'https://webmail.no-log.org/',NULL,'gro.gol-on.liambew.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(4,'https://mail.riseup.net/',NULL,'ten.puesir.liam.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(5,'https://webmail.boum.org/',NULL,'gro.muob.liambew.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(6,'https://check.torproject.org/',NULL,'gro.tcejorprot.kcehc.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(7,'https://www.torproject.org/',NULL,'gro.tcejorprot.www.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(8,'https://tor.stackexchange.com/',NULL,'moc.egnahcxekcats.rot.',0,0,0,NULL,140,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(9,'place:sort=8&maxResults=10',NULL,'.',0,0,0,NULL,0,NULL,NULL,1,0); +INSERT INTO "moz_places" VALUES(10,'place:type=6&sort=14&maxResults=10',NULL,'.',0,0,0,NULL,0,NULL,NULL,1,0); +CREATE TABLE moz_historyvisits ( id INTEGER PRIMARY KEY, from_visit INTEGER, place_id INTEGER, visit_date INTEGER, visit_type INTEGER, session INTEGER); +CREATE TABLE moz_inputhistory ( place_id INTEGER NOT NULL, input LONGVARCHAR NOT NULL, use_count INTEGER, PRIMARY KEY (place_id, input)); +CREATE TABLE moz_hosts ( id INTEGER PRIMARY KEY, host TEXT NOT NULL UNIQUE, frecency INTEGER, typed INTEGER NOT NULL DEFAULT 0, prefix TEXT); +INSERT INTO "moz_hosts" VALUES(1,'tails.boum.org',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(2,'webmail.no-log.org',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(3,'mail.riseup.net',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(4,'webmail.boum.org',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(5,'check.torproject.org',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(6,'torproject.org',140,0,NULL); +INSERT INTO "moz_hosts" VALUES(7,'tor.stackexchange.com',140,0,NULL); +CREATE TABLE moz_bookmarks ( id INTEGER PRIMARY KEY, type INTEGER, fk INTEGER DEFAULT NULL, parent INTEGER, position INTEGER, title LONGVARCHAR, keyword_id INTEGER, folder_type TEXT, dateAdded INTEGER, lastModified INTEGER, guid TEXT); +INSERT INTO "moz_bookmarks" VALUES(1,2,NULL,0,0,'',NULL,NULL,0,0,'root________'); +INSERT INTO "moz_bookmarks" VALUES(2,2,NULL,1,0,'Bookmarks Menu',NULL,NULL,0,0,'menu________'); +INSERT INTO "moz_bookmarks" VALUES(3,2,NULL,1,1,'Bookmarks Toolbar',NULL,NULL,0,0,'toolbar_____'); +INSERT INTO "moz_bookmarks" VALUES(4,2,NULL,1,2,'Tags',NULL,NULL,0,0,'tags________'); +INSERT INTO "moz_bookmarks" VALUES(5,2,NULL,1,3,'Other Bookmarks',NULL,NULL,0,0,'unfiled_____'); +INSERT INTO "moz_bookmarks" VALUES(6,2,NULL,1,4,'mobile',NULL,NULL,0,0,'mobile______'); +INSERT INTO "moz_bookmarks" VALUES(7,1,1,2,4,'Tails',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(8,1,2,2,5,'Tails documentation (offline)',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(9,2,NULL,2,2,'Webmail',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(10,1,3,9,0,'no-log.org',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(11,1,4,9,1,'riseup.net',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(12,1,5,9,2,'boum.org',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(13,2,NULL,2,3,'Tor',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(14,1,6,13,0,'Tor Check',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(15,1,7,13,1,'Tor Project',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(16,1,8,13,2,'Tor Stack Exchange',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(17,1,9,3,0,'Most Visited',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(18,1,10,2,0,'Recent Tags',NULL,NULL,0,0,NULL); +INSERT INTO "moz_bookmarks" VALUES(19,3,NULL,2,1,NULL,NULL,NULL,0,0,NULL); +CREATE TABLE moz_keywords ( id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT UNIQUE, place_id INTEGER, post_data TEXT); +CREATE TABLE moz_favicons ( id INTEGER PRIMARY KEY, url LONGVARCHAR UNIQUE, data BLOB, mime_type VARCHAR(32), expiration LONG); +CREATE TABLE moz_anno_attributes ( id INTEGER PRIMARY KEY, name VARCHAR(32) UNIQUE NOT NULL); +INSERT INTO "moz_anno_attributes" VALUES(1,'mobile/bookmarksRoot'); +INSERT INTO "moz_anno_attributes" VALUES(2,'Places/SmartBookmark'); +CREATE TABLE moz_annos ( id INTEGER PRIMARY KEY, place_id INTEGER NOT NULL, anno_attribute_id INTEGER, mime_type VARCHAR(32) DEFAULT NULL, content LONGVARCHAR, flags INTEGER DEFAULT 0, expiration INTEGER DEFAULT 0, type INTEGER DEFAULT 0, dateAdded INTEGER DEFAULT 0, lastModified INTEGER DEFAULT 0); +CREATE TABLE moz_items_annos ( id INTEGER PRIMARY KEY, item_id INTEGER NOT NULL, anno_attribute_id INTEGER, mime_type VARCHAR(32) DEFAULT NULL, content LONGVARCHAR, flags INTEGER DEFAULT 0, expiration INTEGER DEFAULT 0, type INTEGER DEFAULT 0, dateAdded INTEGER DEFAULT 0, lastModified INTEGER DEFAULT 0); +INSERT INTO "moz_items_annos" VALUES(1,6,1,NULL,'1',0,4,1,1071790224,1071790224); +INSERT INTO "moz_items_annos" VALUES(2,17,2,NULL,'MostVisited',0,4,3,0,0); +INSERT INTO "moz_items_annos" VALUES(3,18,2,NULL,'RecentTags',0,4,3,0,0); +ANALYZE sqlite_master; +INSERT INTO "sqlite_stat1" VALUES('moz_bookmarks','moz_bookmarks_guid_uniqueindex','6 1'); +INSERT INTO "sqlite_stat1" VALUES('moz_bookmarks','moz_bookmarks_itemlastmodifiedindex','6 6 3'); +INSERT INTO "sqlite_stat1" VALUES('moz_bookmarks','moz_bookmarks_parentindex','6 3 1'); +INSERT INTO "sqlite_stat1" VALUES('moz_bookmarks','moz_bookmarks_itemindex','6 6 6'); +CREATE INDEX moz_places_url_hashindex ON moz_places (url_hash); +CREATE INDEX moz_places_faviconindex ON moz_places (favicon_id); +CREATE INDEX moz_places_hostindex ON moz_places (rev_host); +CREATE INDEX moz_places_visitcount ON moz_places (visit_count); +CREATE INDEX moz_places_frecencyindex ON moz_places (frecency); +CREATE INDEX moz_places_lastvisitdateindex ON moz_places (last_visit_date); +CREATE UNIQUE INDEX moz_places_guid_uniqueindex ON moz_places (guid); +CREATE INDEX moz_historyvisits_placedateindex ON moz_historyvisits (place_id, visit_date); +CREATE INDEX moz_historyvisits_fromindex ON moz_historyvisits (from_visit); +CREATE INDEX moz_historyvisits_dateindex ON moz_historyvisits (visit_date); +CREATE INDEX moz_bookmarks_itemindex ON moz_bookmarks (fk, type); +CREATE INDEX moz_bookmarks_parentindex ON moz_bookmarks (parent, position); +CREATE INDEX moz_bookmarks_itemlastmodifiedindex ON moz_bookmarks (fk, lastModified); +CREATE UNIQUE INDEX moz_bookmarks_guid_uniqueindex ON moz_bookmarks (guid); +CREATE UNIQUE INDEX moz_keywords_placepostdata_uniqueindex ON moz_keywords (place_id, post_data); +CREATE UNIQUE INDEX moz_annos_placeattributeindex ON moz_annos (place_id, anno_attribute_id); +CREATE UNIQUE INDEX moz_items_annos_itemattributeindex ON moz_items_annos (item_id, anno_attribute_id); +COMMIT; diff --git a/config/chroot_local-includes/etc/skel/.poedit/config b/config/chroot_local-includes/etc/skel/.poedit/config new file mode 100644 index 0000000000000000000000000000000000000000..b6d634efb199821fd904672408566d1073bf4283 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.poedit/config @@ -0,0 +1,3 @@ +[donate] +dont_bug=1 +last_asked=1354364819 diff --git a/config/chroot_local-includes/etc/skel/.profile b/config/chroot_local-includes/etc/skel/.profile new file mode 100644 index 0000000000000000000000000000000000000000..5e324d75d5cb6b084fd022443f266eae8ce2d744 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.profile @@ -0,0 +1,22 @@ +# ~/.profile: executed by the command interpreter for login shells. +# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login +# exists. +# see /usr/share/doc/bash/examples/startup-files for examples. +# the files are located in the bash-doc package. + +# the default umask is set in /etc/profile; for setting the umask +# for ssh logins, install and configure the libpam-umask package. +umask 077 + +# if running bash +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/bin" ] ; then + PATH="$HOME/bin:$PATH" +fi diff --git a/config/chroot_local-includes/etc/skel/.purple/accounts.xml b/config/chroot_local-includes/etc/skel/.purple/accounts.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea40f8802dee18be577d5bf1ee2ba4f96b4302fe --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.purple/accounts.xml @@ -0,0 +1,59 @@ + + + + + prpl-irc + XXX_NICK_XXX@irc.oftc.net + + + + + + + + + + + + + XXX_NICK_XXX + UTF-8,ISO-8859-1 + XXX_NICK_XXX + 6697 + 1 + + + 0 + + + + + prpl-irc + XXX_NICK_XXX@127.0.0.1 + + + + + + + + + + + + + XXX_NICK_XXX + UTF-8,ISO-8859-1 + XXX_NICK_XXX + 6668 + 0 + + + 0 + + + none + + + + diff --git a/config/chroot_local-includes/etc/skel/.purple/blist.xml b/config/chroot_local-includes/etc/skel/.purple/blist.xml new file mode 100644 index 0000000000000000000000000000000000000000..767fdd402bb148548c4a038e01558f7077c3ff44 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.purple/blist.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/config/chroot_local-includes/etc/skel/.purple/prefs.xml b/config/chroot_local-includes/etc/skel/.purple/prefs.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bad646cb3057bb94e3d2aeaa6263cfbaa99bafc --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.purple/prefs.xml @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/chroot_local-includes/etc/skel/.tor/control_auth_cookie b/config/chroot_local-includes/etc/skel/.tor/control_auth_cookie new file mode 120000 index 0000000000000000000000000000000000000000..b84d7e584e5cc86ae8ce64243f256632eff689e1 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.tor/control_auth_cookie @@ -0,0 +1 @@ +/tmp/control_auth_cookie \ No newline at end of file diff --git a/config/chroot_local-includes/etc/skel/.xsessionrc b/config/chroot_local-includes/etc/skel/.xsessionrc new file mode 100644 index 0000000000000000000000000000000000000000..a23170fffd326bac39ca2d3bc235f7a5f2f2159c --- /dev/null +++ b/config/chroot_local-includes/etc/skel/.xsessionrc @@ -0,0 +1,2 @@ +. /etc/amnesia/environment +export TAILS_WIKI_SUPPORTED_LANGUAGES diff --git a/config/chroot_local-includes/etc/skel/Desktop/Report_an_error.desktop.in b/config/chroot_local-includes/etc/skel/Desktop/Report_an_error.desktop.in new file mode 100755 index 0000000000000000000000000000000000000000..fad85f9d45eeacf818a7424d02380f05b94d6e47 --- /dev/null +++ b/config/chroot_local-includes/etc/skel/Desktop/Report_an_error.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +_Name=Report an error +Type=Application +Terminal=false +Exec=/usr/local/bin/tails-documentation support +Icon=/usr/share/pixmaps/whisperback.svg +StartupNotify=true diff --git a/config/chroot_local-includes/etc/skel/Desktop/tails-documentation.desktop.in b/config/chroot_local-includes/etc/skel/Desktop/tails-documentation.desktop.in new file mode 100755 index 0000000000000000000000000000000000000000..8aa0331bb486e700b592a30b6bcd14d92e867bac --- /dev/null +++ b/config/chroot_local-includes/etc/skel/Desktop/tails-documentation.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +_Name=Tails documentation +Type=Application +Terminal=false +Exec=/usr/local/bin/tails-documentation doc +Icon=/usr/share/icons/gnome/48x48/categories/system-help.png +StartupNotify=true diff --git a/config/chroot_local-includes/etc/ssh/ssh_config b/config/chroot_local-includes/etc/ssh/ssh_config new file mode 100644 index 0000000000000000000000000000000000000000..18c95611d6c86e00810e720a5b8678ce061edb6b --- /dev/null +++ b/config/chroot_local-includes/etc/ssh/ssh_config @@ -0,0 +1,18 @@ +Host 192.168.* 10.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.* +ProxyCommand none + +Host * + +ProxyCommand /bin/nc -X 5 -x 127.0.0.1:9050 %h %p + +Compression yes +CompressionLevel 9 + +ForwardX11 no +ForwardX11Trusted no + +# Prevent fingerprinting when username was not specified +User root + +# Avoid storing full remote IP / host name connection history in plaintext +HashKnownHosts yes diff --git a/config/chroot_local-includes/etc/ssl/certs/Lets-Encrypt-Authority-X3.pem b/config/chroot_local-includes/etc/ssl/certs/Lets-Encrypt-Authority-X3.pem new file mode 100644 index 0000000000000000000000000000000000000000..0002462ce85dcda4d1038319b5989a3f859a6213 --- /dev/null +++ b/config/chroot_local-includes/etc/ssl/certs/Lets-Encrypt-Authority-X3.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/config/chroot_local-includes/etc/sudoers.d/always-ask-password b/config/chroot_local-includes/etc/sudoers.d/always-ask-password new file mode 100644 index 0000000000000000000000000000000000000000..f238814a836f8438f114da3b738549de4ce6e001 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/always-ask-password @@ -0,0 +1 @@ +Defaults timestamp_timeout=0 diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_boot_profile b/config/chroot_local-includes/etc/sudoers.d/zzz_boot_profile new file mode 100644 index 0000000000000000000000000000000000000000..4a08035be92a403902d61ecb40cee3309ef1b8a2 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_boot_profile @@ -0,0 +1 @@ +amnesia ALL = NOPASSWD: /usr/local/lib/kill-boot-profile "" diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_gdm b/config/chroot_local-includes/etc/sudoers.d/zzz_gdm new file mode 100644 index 0000000000000000000000000000000000000000..24026cdfef3b7163674ee0c19ec8319229c14d7e --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_gdm @@ -0,0 +1,2 @@ +# Allow our gdm-x-session wrapper to kill the GDM service +Debian-gdm ALL = NOPASSWD: /bin/systemctl kill --signal=9 gdm diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_halt b/config/chroot_local-includes/etc/sudoers.d/zzz_halt new file mode 100644 index 0000000000000000000000000000000000000000..f5897bf334983f57f4f5f27b60a474582c1333a4 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_halt @@ -0,0 +1,2 @@ +amnesia ALL = NOPASSWD: /sbin/poweroff "" +amnesia ALL = NOPASSWD: /sbin/reboot "" diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_persistence-setup b/config/chroot_local-includes/etc/sudoers.d/zzz_persistence-setup new file mode 100644 index 0000000000000000000000000000000000000000..456d03b31e48775717a17b6b63ce6b4de447c3f7 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_persistence-setup @@ -0,0 +1,4 @@ +Cmnd_Alias PERSISTENCE_SETUP = /usr/bin/tails-persistence-setup "", /usr/bin/tails-persistence-setup --verbose, /usr/bin/tails-persistence-setup --step delete, /usr/bin/tails-persistence-setup --step delete --verbose, /usr/bin/tails-persistence-setup --force-enable-preset AdditionalSoftware + +amnesia ALL = (tails-persistence-setup) NOPASSWD: PERSISTENCE_SETUP +tails-persistence-setup ALL = (root) NOPASSWD: /usr/bin/tails-fix-persistent-volume-permissions "" diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_tails-additional-software b/config/chroot_local-includes/etc/sudoers.d/zzz_tails-additional-software new file mode 100644 index 0000000000000000000000000000000000000000..11baa4827d6afe5b0da5e52de3db519da192aeb0 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_tails-additional-software @@ -0,0 +1,5 @@ +# XXX:Buster this sudo rule should be replaced by a polkit rule once we have +# policykit >= 0.106. The rule is already in +# [[blueprint/additional_software_packages/org.boum.tails.additional-software.rules]] +# and should be installed in /usr/share/polkit-1/rules.d/ +amnesia ALL = NOPASSWD: /bin/systemctl start tails-additional-software-install.service diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_tails-debugging-info b/config/chroot_local-includes/etc/sudoers.d/zzz_tails-debugging-info new file mode 100644 index 0000000000000000000000000000000000000000..c5f9e6b47aa9a8d03ac91d158045d943128d69de --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_tails-debugging-info @@ -0,0 +1 @@ +amnesia ALL = NOPASSWD: /usr/local/sbin/tails-debugging-info "" diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_unsafe-browser b/config/chroot_local-includes/etc/sudoers.d/zzz_unsafe-browser new file mode 100644 index 0000000000000000000000000000000000000000..0fec53095f3f685e5a032d1d67ef9f23e94ff523 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_unsafe-browser @@ -0,0 +1 @@ +amnesia ALL = NOPASSWD: /usr/local/sbin/unsafe-browser "" diff --git a/config/chroot_local-includes/etc/sudoers.d/zzz_upgrade b/config/chroot_local-includes/etc/sudoers.d/zzz_upgrade new file mode 100644 index 0000000000000000000000000000000000000000..4cc0618092e9abe1bbc507fdfc60b586ce782b70 --- /dev/null +++ b/config/chroot_local-includes/etc/sudoers.d/zzz_upgrade @@ -0,0 +1,15 @@ +Cmnd_Alias INSTALL_IUK = /bin/chmod, /bin/dd, /bin/mkdir, /bin/mktemp, /bin/mount, /bin/rm, /bin/tar, /lib/live/mount/medium/utils/linux/syslinux, /usr/bin/nocache /bin/cp * +Cmnd_Alias IUK_GET_TARGET_FILE = /usr/bin/tails-iuk-get-target-file +Cmnd_Alias UPGRADE_FRONTEND = /usr/bin/tails-upgrade-frontend "" + +Defaults!IUK_GET_TARGET_FILE env_keep+="HARNESS_ACTIVE DISABLE_PROXY" +Defaults!UPGRADE_FRONTEND env_keep+="DISABLE_PROXY SSL_NO_VERIFY" + +amnesia ALL = (tails-upgrade-frontend) NOPASSWD: UPGRADE_FRONTEND +tails-upgrade-frontend ALL = NOPASSWD: /usr/bin/tails-shutdown-network "" +tails-upgrade-frontend ALL = (tails-install-iuk) NOPASSWD: /usr/bin/tails-install-iuk +tails-upgrade-frontend ALL = (tails-iuk-get-target-file) NOPASSWD: IUK_GET_TARGET_FILE +tails-upgrade-frontend ALL = (tails-iuk-get-target-file) NOPASSWD: /usr/bin/tails-iuk-mktemp-get-target-file "" +tails-upgrade-frontend ALL = NOPASSWD: /sbin/reboot "" + +tails-install-iuk ALL = NOPASSWD: INSTALL_IUK diff --git a/config/chroot_local-includes/etc/sysctl.d/disable_ipv6.conf b/config/chroot_local-includes/etc/sysctl.d/disable_ipv6.conf new file mode 100644 index 0000000000000000000000000000000000000000..e1d78834f6f1cfa3d390ce7f5e713a9c65c0b3df --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/disable_ipv6.conf @@ -0,0 +1,5 @@ +net.ipv6.conf.default.disable_ipv6 = 1 +net.ipv6.conf.all.disable_ipv6 = 1 + +# Some programs expect the loopback interface to have IPv6 enabled +net.ipv6.conf.lo.disable_ipv6 = 0 diff --git a/config/chroot_local-includes/etc/sysctl.d/fs_protected.conf b/config/chroot_local-includes/etc/sysctl.d/fs_protected.conf new file mode 100644 index 0000000000000000000000000000000000000000..d7baaed6b8390fadae8b2ad749193bcda606bd67 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/fs_protected.conf @@ -0,0 +1,2 @@ +fs.protected_fifos = 2 +fs.protected_regular = 2 diff --git a/config/chroot_local-includes/etc/sysctl.d/kexec.conf b/config/chroot_local-includes/etc/sysctl.d/kexec.conf new file mode 100644 index 0000000000000000000000000000000000000000..edfb7252d58ea2e12a6404aec01f7dab3c969341 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/kexec.conf @@ -0,0 +1 @@ +kernel.kexec_load_disabled = 1 diff --git a/config/chroot_local-includes/etc/sysctl.d/kptr_restrict.conf b/config/chroot_local-includes/etc/sysctl.d/kptr_restrict.conf new file mode 100644 index 0000000000000000000000000000000000000000..a1e18e8b8a17de174d96aed9757aa07e74bbf079 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/kptr_restrict.conf @@ -0,0 +1 @@ +kernel.kptr_restrict=2 diff --git a/config/chroot_local-includes/etc/sysctl.d/mmap_aslr.conf b/config/chroot_local-includes/etc/sysctl.d/mmap_aslr.conf new file mode 100644 index 0000000000000000000000000000000000000000..826430f5b78df52b3802f96a7543e1e776c07759 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/mmap_aslr.conf @@ -0,0 +1,2 @@ +vm.mmap_rnd_bits=32 +vm.mmap_rnd_compat_bits=16 diff --git a/config/chroot_local-includes/etc/sysctl.d/pmtud.conf b/config/chroot_local-includes/etc/sysctl.d/pmtud.conf new file mode 100644 index 0000000000000000000000000000000000000000..3e938cd9df11895d9954c9f693072e13e49368e8 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/pmtud.conf @@ -0,0 +1 @@ +net.ipv4.tcp_mtu_probing=1 diff --git a/config/chroot_local-includes/etc/sysctl.d/ptrace_scope.conf b/config/chroot_local-includes/etc/sysctl.d/ptrace_scope.conf new file mode 100644 index 0000000000000000000000000000000000000000..4b882fed89a5878be99bcf24ea9607e32dc2c8c1 --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/ptrace_scope.conf @@ -0,0 +1 @@ +kernel.yama.ptrace_scope=2 diff --git a/config/chroot_local-includes/etc/sysctl.d/tcp_timestamps.conf b/config/chroot_local-includes/etc/sysctl.d/tcp_timestamps.conf new file mode 100644 index 0000000000000000000000000000000000000000..f47b8d31049915b94e5ce894f50350b1b192d61a --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/tcp_timestamps.conf @@ -0,0 +1 @@ +net.ipv4.tcp_timestamps=0 diff --git a/config/chroot_local-includes/etc/sysctl.d/unprivileged_bpf.conf b/config/chroot_local-includes/etc/sysctl.d/unprivileged_bpf.conf new file mode 100644 index 0000000000000000000000000000000000000000..529fc86f2f43e063f8064c2c22065c7845d7430c --- /dev/null +++ b/config/chroot_local-includes/etc/sysctl.d/unprivileged_bpf.conf @@ -0,0 +1 @@ +kernel.unprivileged_bpf_disabled=1 diff --git a/config/chroot_local-includes/etc/thunderbird/pref/thunderbird.js b/config/chroot_local-includes/etc/thunderbird/pref/thunderbird.js new file mode 100644 index 0000000000000000000000000000000000000000..9cf13344df9ec85796f5a9b007296b5bc9a5cd99 --- /dev/null +++ b/config/chroot_local-includes/etc/thunderbird/pref/thunderbird.js @@ -0,0 +1,82 @@ +// This is the Debian specific preferences file for Mozilla Firefox +// You can make any change in here, it is the purpose of this file. +// You can, with this file and all files present in the +// /etc/thunderbird/pref directory, override any preference that is +// present in /usr/lib/thunderbird/defaults/pref directory. +// While your changes will be kept on upgrade if you modify files in +// /etc/thunderbird/pref, please note that they won't be kept if you +// do them in /usr/lib/thunderbird/defaults/pref. + +pref("extensions.update.enabled", false); + +// Use LANG environment variable to choose locale from system +// The old environment setting 'pref("intl.locale.matchOS", true);' is +// currently not working anymore. The new introduced setting +// 'intl.locale.requested' is now used for this. Setting an empty string is +// pulling the system locale into Thunderbird. +pref("intl.locale.requested", ""); + +// Disable default mail checking (gnome). +pref("mail.shell.checkDefaultMail", false); + +// if you are not using gnome +pref("network.protocol-handler.app.http", "x-www-browser"); +pref("network.protocol-handler.app.https", "x-www-browser"); + +// Disable mail indexing +pref("mailnews.database.global.indexer.enabled", false); + +// Disable chat +pref("mail.chat.enabled", false); + +// Hide the "Know your rights" message +pref("mail.rights.version", 1); + +// Disable system addons +pref("extensions.autoDisableScopes", 3); +pref("extensions.enabledScopes", 4); + +// Only show the tab bar if there's more than one tab to display +pref("mail.tabs.autoHide", true); + +// Try to disable "Would you like to help Thunderbird Mail/News by automatically reporting memory usage, performance, and responsiveness to Mozilla" +pref("toolkit.telemetry.prompted", 2); +pref("toolkit.telemetry.rejected", true); +pref("toolkit.telemetry.enabled", false); + +// Only allow SSL channels when fetching from the ISP. +pref("mailnews.auto_config.fetchFromISP.ssl_only", true); +// Only allow Thunderbird's automatic configuration wizard to use and +// configure secure (SSL/TLS) protocols. +pref("mailnews.auto_config.ssl_only_mail_servers", true); +// Old name for mailnews.auto_config.ssl_only_mail_servers, to make +// this configuration still work in case we have to revert to a previous +// version of the #6156 patchset. +pref("mailnews.auto_config.account_constraints.ssl_only", true); +// Drop auto-fetched configurations using Oauth2 -- they do not work +// together with Torbirdy since it disables needed functionality (like +// JavaScript and cookies) in the embedded browser. +pref("mailnews.auto_config.account_constraints.allow_oauth2", false); +// The timeout (in seconds) for each guess +pref("mailnews.auto_config.guess.timeout", 30); + +// We disable Memory Hole for encrypted email until support is more +// mature and widely spread (#15201). +pref("extensions.enigmail.protectedHeaders", 0); +// This setting is a good guess - but not used at the moment +pref("extensions.torbirdy.custom.extensions.enigmail.protectedHeaders", 0); + +// Those settings are useless at the moment, just needed to display +// the correct checkmark in torbirdy (#13649#note-31). +pref("extensions.enigmail.protectHeaders", false); +pref("extensions.torbirdy.custom.extensions.enigmail.protectHeaders", false); + +// Disable Autocrypt by default for new accounts (#16222). +// This does not change anything for accounts that were created before. +pref("mail.server.default.enableAutocrypt", false); + +// Don't decrypt subordinate message parts that otherwise might reveal +// decrypted content to the attacker, i.e. the optional part of the fixes +// for EFAIL. +// Reference: https://www.thunderbird.net/en-US/thunderbird/52.9.1/releasenotes/ +pref("mailnews.p7m_subparts_external", true); diff --git a/config/chroot_local-includes/etc/thunderbird/profile/chrome/userChrome.css b/config/chroot_local-includes/etc/thunderbird/profile/chrome/userChrome.css new file mode 100644 index 0000000000000000000000000000000000000000..cc2471bf05595a430a929a1f61ef0f67e828bfd4 --- /dev/null +++ b/config/chroot_local-includes/etc/thunderbird/profile/chrome/userChrome.css @@ -0,0 +1,15 @@ +/* Required, do not remove */ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +#torbirdy-jondo-selection, +#torbirdy-whonix-selection, +#torbirdy-tor-selection, +#torbirdy-tor-selection + menuseparator, + +#torbirdy-anon-settings, +#torbirdy-anonservice, + +/* Hide "Chat account" on Thunderbird's start-up page */ +#CreateAccountChat + +{ display: none; } diff --git a/config/chroot_local-includes/etc/tor-browser/profile/chrome/userChrome.css b/config/chroot_local-includes/etc/tor-browser/profile/chrome/userChrome.css new file mode 100644 index 0000000000000000000000000000000000000000..cc2c33f3b1dd81de52694aff283eb5dced14624f --- /dev/null +++ b/config/chroot_local-includes/etc/tor-browser/profile/chrome/userChrome.css @@ -0,0 +1,27 @@ +/* Required, do not remove */ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* Hide Firefox Sync options. Sync hasn't been audited by the + Tor Browser developers yet (Tor bug #10368), and it doesn't seem to + work any way (Tor bug #13279). Weak passwords would be a pretty + serious issue too. */ +#BrowserPreferences radio[pane="paneSync"], +#sync-button, +#sync-menu-button, +#sync-setup, +#sync-setup-appmenu, +#sync-status-button, +#sync-syncnowitem-appmenu, +#wrapper-sync-button, + +/* Hide the Tools -> Apps link to the Firefox Marketplace. It doesn't + seem to work in the Tor Browser, and may have privacy issues. */ +#menu_openApps, + +/* Hide the "Share this page" button in the Tool bar, which encourages + the use of social (= tracking) networks. Note that this one likely + will be removed upstream in the final Tor Browser 5.0 release. */ +#social-share-button, + +/* Hide HTTPS Everywhere button in the toolbar */ +#https-everywhere-button { display: none; } diff --git a/config/chroot_local-includes/etc/tor-browser/profile/prefs.js b/config/chroot_local-includes/etc/tor-browser/profile/prefs.js new file mode 100644 index 0000000000000000000000000000000000000000..ab11aea7de8cbd54f06dd8ca8f7262f3c3d574bc --- /dev/null +++ b/config/chroot_local-includes/etc/tor-browser/profile/prefs.js @@ -0,0 +1,5 @@ +// Prefs that *need* to be here because they are not honored +// if we set them via /usr/share/tails/tor-browser-prefs.js +user_pref("extensions.torbutton.launch_warning", false); +user_pref("intl.accept_languages", "en-US, en"); +user_pref("javascript.use_us_english_locale", true); diff --git a/config/chroot_local-includes/etc/tor/tor-tsocks.conf b/config/chroot_local-includes/etc/tor/tor-tsocks.conf new file mode 100644 index 0000000000000000000000000000000000000000..064de3b6cd742af8face17e20dfa138e703f5ec4 --- /dev/null +++ b/config/chroot_local-includes/etc/tor/tor-tsocks.conf @@ -0,0 +1,19 @@ +# This is the configuration for libtsocks (transparent socks) for use +# with tor, which is providing a socks server on port 9050 by default. +# +# See tsocks.conf(5) and torify(1) manpages. + +server = 127.0.0.1 +server_port = 9050 + +# We specify local as 127.0.0.0 - 127.191.255.255 because the +# Tor MAPADDRESS virtual IP range is the rest of net 127. +local = 127.0.0.0/255.128.0.0 +local = 127.128.0.0/255.192.0.0 + + +# My local networks +local = 10.0.0.0/255.0.0.0 +local = 172.16.0.0/255.240.0.0 +local = 192.168.0.0/255.255.0.0 + diff --git a/config/chroot_local-includes/etc/tor/torrc b/config/chroot_local-includes/etc/tor/torrc new file mode 100644 index 0000000000000000000000000000000000000000..9e17ea99649171c6137d1151e94e7c693436144a --- /dev/null +++ b/config/chroot_local-includes/etc/tor/torrc @@ -0,0 +1,179 @@ +## Configuration file for a typical Tor user +## Last updated 22 December 2007 for Tor 0.2.0.14-alpha. +## (May or may not work for much older or much newer versions of Tor.) +## +## Lines that begin with "## " try to explain what's going on. Lines +## that begin with just "#" are disabled commands: you can enable them +## by removing the "#" symbol. +## +## See the man page, or https://www.torproject.org/tor-manual-dev.html, +## for more options you can use in this file. +## +## Tor will look for this file in various places based on your platform: +## http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#torrc + + +## Default SocksPort +SocksPort 127.0.0.1:9050 IsolateDestAddr IsolateDestPort +## SocksPort for Tails-specific applications +SocksPort 127.0.0.1:9062 IsolateDestAddr IsolateDestPort +## SocksPort for the default web browser +SocksPort 127.0.0.1:9150 IsolateSOCKSAuth KeepAliveIsolateSOCKSAuth + +## Entry policies to allow/deny SOCKS requests based on IP address. +## First entry that matches wins. If no SocksPolicy is set, we accept +## all (and only) requests from SocksListenAddress. +#SocksPolicy accept 192.168.0.0/16 +#SocksPolicy reject * + +## Logs go to stdout at level "notice" unless redirected by something +## else, like one of the below lines. You can have as many Log lines as +## you want. +## +## We advise using "notice" in most cases, since anything more verbose +## may provide sensitive information to an attacker who obtains the logs. +## +## Send all messages of level 'notice' or higher to /var/log/tor/notices.log +#Log notice file /var/log/tor/notices.log +## Send every possible message to /var/log/tor/debug.log +#Log debug file /var/log/tor/debug.log +## Use the system log instead of Tor's logfiles +#Log notice syslog +## To send all messages to stderr: +#Log debug stderr + +## Uncomment this to start the process in the background... or use +## --runasdaemon 1 on the command line. This is ignored on Windows; +## see the FAQ entry if you want Tor to run as an NT service. +#RunAsDaemon 1 + +## The directory for keeping all the keys/etc. By default, we store +## things in $HOME/.tor on Unix, and in Application Data\tor on Windows. +#DataDirectory /var/lib/tor + +## The port on which Tor will listen for local connections from Tor +## controller applications, as documented in control-spec.txt. +ControlPort 9052 +ControlListenAddress 127.0.0.1 + +############### This section is just for location-hidden services ### + +## Once you have configured a hidden service, you can look at the +## contents of the file ".../hidden_service/hostname" for the address +## to tell people. +## +## HiddenServicePort x y:z says to redirect requests on port x to the +## address y:z. + +#HiddenServiceDir /var/lib/tor/hidden_service/ +#HiddenServicePort 80 127.0.0.1:80 + +#HiddenServiceDir /var/lib/tor/other_hidden_service/ +#HiddenServicePort 80 127.0.0.1:80 +#HiddenServicePort 22 127.0.0.1:22 + +################ This section is just for relays ##################### +# +## See https://www.torproject.org/docs/tor-doc-relay for details. + +## A unique handle for your server. +#Nickname ididnteditheconfig + +## The IP or FQDN for your server. Leave commented out and Tor will guess. +#Address noname.example.com + +## Define these to limit the bandwidth usage of relayed (server) +## traffic. Your own traffic is still unthrottled. +## Note that RelayBandwidthRate must be at least 20 KB. +#RelayBandwidthRate 100 KBytes # Throttle traffic to 100KB/s (800Kbps) +#RelayBandwidthBurst 200 KBytes # But allow bursts up to 200KB/s (1600Kbps) + +## Contact info to be published in the directory, so we can contact you +## if your server is misconfigured or something else goes wrong. +#ContactInfo Random Person +## You might also include your PGP or GPG fingerprint if you have one: +#ContactInfo 1234D/FFFFFFFF Random Person + +## Required: what port to advertise for Tor connections. +#ORPort 9001 +## If you need to listen on a port other than the one advertised +## in ORPort (e.g. to advertise 443 but bind to 9090), uncomment the +## line below too. You'll need to do ipchains or other port forwarding +## yourself to make this work. +#ORListenAddress 0.0.0.0:9090 + +## Uncomment this to mirror directory information for others. Please do +## if you have enough bandwidth. +#DirPort 9030 # what port to advertise for directory connections +## If you need to listen on a port other than the one advertised +## in DirPort (e.g. to advertise 80 but bind to 9091), uncomment the line +## below too. You'll need to do ipchains or other port forwarding yourself +## to make this work. +#DirListenAddress 0.0.0.0:9091 + +## Uncomment this if you run more than one Tor server, and add the +## nickname of each Tor server you control, even if they're on different +## networks. You declare it here so Tor clients can avoid using more than +## one of your servers in a single circuit. See +## http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#MultipleServers +#MyFamily nickname1,nickname2,... + +## A comma-separated list of exit policies. They're considered first +## to last, and the first match wins. If you want to _replace_ +## the default exit policy, end this with either a reject *:* or an +## accept *:*. Otherwise, you're _augmenting_ (prepending to) the +## default exit policy. Leave commented to just use the default, which is +## available in the man page or at https://www.torproject.org/documentation.html +## +## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses +## for issues you might encounter if you use the default exit policy. +## +## If certain IPs and ports are blocked externally, e.g. by your firewall, +## you should update your exit policy to reflect this -- otherwise Tor +## users will be told that those destinations are down. +## +#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more +#ExitPolicy accept *:119 # accept nntp as well as default exit policy +#ExitPolicy reject *:* # no exits allowed +# +################ This section is just for bridge relays ############## +# +## Bridge relays (or "bridges" ) are Tor relays that aren't listed in the +## main directory. Since there is no complete public list of them, even if an +## ISP is filtering connections to all the known Tor relays, they probably +## won't be able to block all the bridges. Unlike running an exit relay, +## running a bridge relay just passes data to and from the Tor network -- +## so it shouldn't expose the operator to abuse complaints. + +#ORPort 443 +#BridgeRelay 1 +#RelayBandwidthRate 50KBytes +#ExitPolicy reject *:* + + +################ Local settings ######################################## + +## Torified DNS +DNSPort 5353 +AutomapHostsOnResolve 1 +AutomapHostsSuffixes .exit,.onion + +## Transparent proxy +TransPort 9040 +TransListenAddress 127.0.0.1 + +## Misc +AvoidDiskWrites 1 + +## We don't care if applications do their own DNS lookups since our Tor +## enforcement will handle it safely. +WarnUnsafeSocks 0 + +## Disable default warnings on StartTLS for email. Let's not train our +## users to click through security warnings. +WarnPlaintextPorts 23,109 + +## Tor 0.3.x logs to syslog by default, which we redirect to the Journal; +## but we have some code that reads Tor's logs and only supports plaintext +## log files at the moment, so let's keep logging to a file. +Log notice file /var/log/tor/log diff --git a/config/chroot_local-includes/etc/ttdnsd.conf b/config/chroot_local-includes/etc/ttdnsd.conf new file mode 100644 index 0000000000000000000000000000000000000000..8c78190700d56579dba3be6b5040367bc196dfa8 --- /dev/null +++ b/config/chroot_local-includes/etc/ttdnsd.conf @@ -0,0 +1,2 @@ +# OpenDNS +208.67.222.222 diff --git a/config/chroot_local-includes/etc/udev/rules.d/00-mac-spoof.rules b/config/chroot_local-includes/etc/udev/rules.d/00-mac-spoof.rules new file mode 100644 index 0000000000000000000000000000000000000000..f1c6666f5a9f0b96454051473884e177d25e2dbd --- /dev/null +++ b/config/chroot_local-includes/etc/udev/rules.d/00-mac-spoof.rules @@ -0,0 +1,3 @@ +# Note: ATTR{type}=="1" means ethernet (ARPHDR_ETHER, see Linux' +# sources, beginning of include/linux/if_arp.h) +SUBSYSTEM=="net", ACTION=="add", ATTR{type}=="1", RUN+="/usr/local/lib/tails-spoof-mac $name" diff --git a/config/chroot_local-includes/etc/udev/rules.d/70-protect-boot-medium-for-udisks.rules b/config/chroot_local-includes/etc/udev/rules.d/70-protect-boot-medium-for-udisks.rules new file mode 100644 index 0000000000000000000000000000000000000000..b4cdfbd36894e756a1bd5fc64464a608642fc041 --- /dev/null +++ b/config/chroot_local-includes/etc/udev/rules.d/70-protect-boot-medium-for-udisks.rules @@ -0,0 +1,18 @@ +SUBSYSTEM!="block", GOTO="bilibop_end" +ACTION!="add|change", GOTO="bilibop_end" +KERNEL!="sd?*|mmcblk?*|mspblk?*", GOTO="bilibop_end" + +SUBSYSTEMS=="usb|firewire|memstick|mmc", \ + PROGRAM=="/lib/bilibop/test $tempnode", \ + ENV{UDISKS_SYSTEM}:="1", \ + GROUP:="disk", \ + GOTO="bilibop_disk" + +GOTO="bilibop_end" +LABEL="bilibop_disk" + +KERNEL=="sd?|mmcblk?|mspblk?", \ + ENV{ID_DRIVE_DETACHABLE}:="0", \ + SYMLINK+="TailsBootDev" + +LABEL="bilibop_end" diff --git a/config/chroot_local-includes/etc/udev/rules.d/80-net-setup-link.rules b/config/chroot_local-includes/etc/udev/rules.d/80-net-setup-link.rules new file mode 120000 index 0000000000000000000000000000000000000000..dc1dc0cde0f7dff7b7f7c9347fff75936d705cb8 --- /dev/null +++ b/config/chroot_local-includes/etc/udev/rules.d/80-net-setup-link.rules @@ -0,0 +1 @@ +/dev/null \ No newline at end of file diff --git a/config/chroot_local-includes/etc/udev/rules.d/99-hide-TailsData.rules b/config/chroot_local-includes/etc/udev/rules.d/99-hide-TailsData.rules new file mode 100644 index 0000000000000000000000000000000000000000..67493f5b1dda7f5d80a92951bfa31472f3e39946 --- /dev/null +++ b/config/chroot_local-includes/etc/udev/rules.d/99-hide-TailsData.rules @@ -0,0 +1 @@ +ENV{ID_FS_LABEL}=="TailsData", ENV{UDISKS_IGNORE}="1" diff --git a/config/chroot_local-includes/etc/udev/rules.d/99-make-removable-devices-user-writable.rules b/config/chroot_local-includes/etc/udev/rules.d/99-make-removable-devices-user-writable.rules new file mode 100644 index 0000000000000000000000000000000000000000..482f550d02cad24d281b8f5bc49ca7e405b5b029 --- /dev/null +++ b/config/chroot_local-includes/etc/udev/rules.d/99-make-removable-devices-user-writable.rules @@ -0,0 +1,3 @@ +# This is essentially borrowed from /lib/udev/rules.d/91-permissions.rules +# in order to workaround #8273. +SUBSYSTEM=="block", ACTION=="add", SUBSYSTEMS=="usb|mmc", GROUP="floppy" diff --git a/config/chroot_local-includes/etc/udisks2/tcrypt.conf b/config/chroot_local-includes/etc/udisks2/tcrypt.conf new file mode 100644 index 0000000000000000000000000000000000000000..a350fdcd893b6e26e6c31915888d05133bec3696 --- /dev/null +++ b/config/chroot_local-includes/etc/udisks2/tcrypt.conf @@ -0,0 +1,2 @@ +# This flag file needs to exist in order to activate VeraCrypt detection +# heuristics in udisks. Its content does not matter. diff --git a/config/chroot_local-includes/etc/vim/vimrc.local b/config/chroot_local-includes/etc/vim/vimrc.local new file mode 100644 index 0000000000000000000000000000000000000000..9aa99b46d4b7f288903d450d20bc3d7d10ed361a --- /dev/null +++ b/config/chroot_local-includes/etc/vim/vimrc.local @@ -0,0 +1,8 @@ +syntax on +set showcmd " Show (partial) command in status line. +set showmatch " Show matching brackets. +set ignorecase " Do case insensitive matching +set smartcase " Do smart case matching +set incsearch " Incremental search +set autowrite " Automatically save before commands like :next and :make +set hidden " Hide buffers when they are abandoned diff --git a/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem b/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem new file mode 100644 index 0000000000000000000000000000000000000000..7e7bb65a9ac7c22df7a5feeffbb427a18697d9a3 --- /dev/null +++ b/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEvjCCAqYCCQC0kD+1GKCKDzANBgkqhkiG9w0BAQUFADAhMR8wHQYDVQQDExY0 +bXZxM3BudmlkM2F3amxuLm9uaW9uMB4XDTA5MDkxMjE3MjUzM1oXDTE5MDkxMDE3 +MjUzM1owITEfMB0GA1UEAxMWNG12cTNwbnZpZDNhd2psbi5vbmlvbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAOsO/hK2WNClY4lq82nTrJ8CGCfUYUzL +TiBz7P0XIAcGB34DkFO96aCyFz4TsjpPalIhna8BabuIPRZo6Gt0gpE6lpqLbYiG +qyvXK63ENlL92LzennKdeYSBlAUi9Bt38T3jDZ8dAWxFhkjKKPrtqjpN9d6gA7aU +IDWzczXUl0rmE5UC5bh8NmcaHDogiNR5r/Wj24FqncS6Ilfjhn1mXacINX9mqzOV +IX/WHWQ6NGFWd+uV3D0U/7TkVDQDJ+Ni/RZGXgcVJ5JoSgJAPAefUTKuC9X7FGVt +i1iu/Cy0DYLVjTHO30oazKTcJuMdOVZ70fRnDyXI8m4hHqyUB16lyw4lHN10OgY/ +haOm6C6VW1OoBAcgxvOdNo/h/jkhSKzgC5iWbtDPB2+qrBvgDVqgYPFDVaBCXewd +qnd02ysMe0axu4nSjRSODG3CRJjuQ0Zhaz4cPsHeOBeLOlDTFuHN/YyPDaWOD7xH +FyDE0hn7kMQWh955Hh5CVZZrx6GI2AbppCgLiWFo2M9e16YAssiZ86yOg2j3PYhW +RDcNuInfj1U/YHv/DnunS0o2eNKxmNLbcaQMu8+4AdGPBhUX7dNtR1iK3o3OB25Z +6ZU2FloEYJGaTiRV3ZMPuABlyxOJxLCSuSfaUk5Xl0+K51sW8FoQU4XhKyej561y +/fSgAJST37/RAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACf9gKIdXBnNuLiaBmt2 +t78Ton2geH8IT5eT6sr7NaWRRfaHkKgTNzqE4/KItNM5LDMCN96JulIns9mSnfyE +gYB4KYgfVtHdm5RJ6vlnO1q/UveYXvwTvBcOQBr62ztG41L4xGPZZb7NVOihXr1f +2iGyc/mEy9QiB3b26Tx5+3N4lyJWEadNyqDNbP4RhHSdDMcDhbTPu9tzbhjMVehL +FLEhHGCIxKoFqyc/OWZRrvrKZtjhvRxkCiQ3sCc7qdVMnK8qaa6JUyrPrZomeF2p +csOTEyVc24iWz9XuQgZjmx9b5BKreUPoZuQ8mQqU7CdVasIKREe/+pk8VyBUgAvV ++vdxJ77WI7XUarILH0ZuSbSgl5iV4Krkqk4o65GoVW9VCjw9aiEeb6X5ijZxe1/j +h2PWFb1603eHDuuCrZYywzl3DLjZ6xzQF5kQGcpR+ORs/wcaxxcDveiBk7oEfRkr +pxGo8batLy5NtCbp5eB2Nvd0oWA1ALsdIwNCSZyuYOUO5lr4cjl98KF9KBhHGbhN +AHn4jKgDHsJwfMRBUaiYtcPQLfhsyM5C4t2xXBJ2ycZuoOCEDxx0yONatRAnbHAX +UdPjN/ijn12c6uvrjAOVK54o0uZ+h1DiGvwU5i31yCHFQX11TZY4FHohuCKl4oTj +39ZLEAZs4/tAyWm1eAZK4GrF +-----END CERTIFICATE----- diff --git a/config/chroot_local-includes/etc/whisperback/config.py b/config/chroot_local-includes/etc/whisperback/config.py new file mode 100644 index 0000000000000000000000000000000000000000..32ee87db60c222ee32a8ad5a679fbff161f5d410 --- /dev/null +++ b/config/chroot_local-includes/etc/whisperback/config.py @@ -0,0 +1,188 @@ +# -*- coding: UTF-8 -*- +# +# Tails configuration file for WhisperBack +# ========================================== +# +# This is a Python script that will be read at startup. Any Python +# syntax is valid. + +# IMPORTS + +# Custom imports +import os +import subprocess +import random +import re +import locale +import gettext + +# DOCUMENTATION + + +def __get_localised_doc_link(): + """Return the link to the localised documentation + + @returns the link to the localised documentation if available, or fallback + to the English version + """ + + # Try to get the list of supported languages codes supported by the + # documentation according to the $TAILS_WIKI_SUPPORTED_LANGUAGES + # environnement variable. If unset, fallback to `en` + try: + wiki_supported_languages = os.environ["TAILS_WIKI_SUPPORTED_LANGUAGES"].split(' ') + except KeyError: + wiki_supported_languages = ['en'] + + # locale.getlocale returns a tuple (language code, encoding) + # the language is the two first character of the RFC 1766 "language code" + system_language_code = locale.getdefaultlocale()[0] + if system_language_code: + system_language = system_language_code[0:2] + else: + system_language = None + + # Get the language code of the localised documentation if available, or + # fallback to `en` + if system_language in wiki_supported_languages: + localised_doc_language = system_language + else: + localised_doc_language = 'en' + + return ("file:///usr/share/doc/tails/website/doc/first_steps/bug_reporting." + + localised_doc_language + + ".html") + + +def _(string): + try: + encoded = gettext.translation("tails", "/usr/share/locale").lgettext(string) + string = encoded.decode('utf-8') + except IOError: + pass + finally: + return string + + +# The right panel help (HTML string) +html_help = _( +"""

Help us fix your bug!

+

Read our bug reporting instructions.

+

Do not include more personal information than +needed!

+

About giving us an email address

+

+Giving us an email address allows us to contact you to clarify the problem. This +is needed for the vast majority of the reports we receive as most reports +without any contact information are useless. On the other hand it also provides +an opportunity for eavesdroppers, like your email or Internet provider, to +confirm that you are using Tails. +

+""") % __get_localised_doc_link() + +# ENCRYPTION +# +# This section defines encryption parameters + +# The path to the OpenPGP keyring to use. If None, use OpenPGP default +# keyring. +gnupg_keyring = "/usr/share/keyrings/whisperback-keyring.gpg" + +# RECIPIENT +# +# This section defines the recepient parameters + +# The address of the recipient +to_address = "tails-bugs@boum.org" + +# The fingerprint of the recipient's GPG key +to_fingerprint = "1F56EDD30741048035DAC1C5EC57B56EF0C43132" + +# SENDER +# +# This section defines the sender parameters + +# The address of the sender +from_address = "devnull@tails.boum.org" + +# SMTP +# +# This section defines the SMTP server parameters +# +# The SMTP server to use to send the mail +smtp_host = "4mvq3pnvid3awjln.onion" +# The port to connect to on that SMTP server +smtp_port = 25 +# The path to a file containing the certificate to trust +# This can be either a CA certificate used to sign the SMTP server +# certificate or the certificate of the SMTP server itself +smtp_tlscafile = "/etc/whisperback/4mvq3pnvid3awjln.onion.pem" + +# SOCKS +# +# This section defines the SOCKS proxy parameters +# +# The SOCKS proxy to use to send the mail +socks_host = "127.0.0.1" +# The port to connect to on that SOCKS proxy +socks_port = 9062 + +# MESSAGE +# +# This section defines the message parameters + +# The subject of the email to be sent +# Please take into account that this will not be encrypted +mail_subject = "Bug report: %x" % random.randrange(16**32) + + +def mail_prepended_info(): + """Returns the version of the running Tails system + A callback function to get information to prepend to the mail + (this information will be encrypted). This is useful to add + software version. + + It should not take any parameter, and should return a string to be + preprended to the email + + @return The output of tails-version, if any, or an English string + explaining the error + """ + + try: + tails_version_process = subprocess.Popen("tails-version", + stdout=subprocess.PIPE) + tails_version_process.wait() + tails_version = tails_version_process.stdout.read().decode('utf-8') + except OSError: + tails_version = "tails-version command not found" + except subprocess.CalledProcessError: + tails_version = "tails-version returned an error" + + return "Tails-Version: %s\n" % tails_version + + +def mail_appended_info(): + """Returns debugging information on the running Tails system + A callback function to get information to append to the email + (this information will be encrypted). This is useful to add + configuration files useful for debugging. + + It should not take any parameter, and should return a string serialized + json to be deserialized to append infos to the email + + @return a string containing serialized json with debugging information + """ + debugging_info = "" + + try: + process = subprocess.Popen(["sudo", "/usr/local/sbin/tails-debugging-info"], + stdout=subprocess.PIPE) + for line in process.stdout: + debugging_info += re.sub(r'^--\s*', '', line.decode('utf-8')) + process.wait() + except OSError: + debugging_info += "sudo command not found\n" + except subprocess.CalledProcessError: + debugging_info += "debugging command returned an error\n" + return debugging_info diff --git a/config/chroot_local-includes/etc/whisperback/debugging-info.json b/config/chroot_local-includes/etc/whisperback/debugging-info.json new file mode 100644 index 0000000000000000000000000000000000000000..44f2d70fb9d05a21f95c01cb50077006187adcf7 --- /dev/null +++ b/config/chroot_local-includes/etc/whisperback/debugging-info.json @@ -0,0 +1,26 @@ +[ +["file", {"user": "root", "path": "/proc/cmdline"}], +["command", {"args": ["/usr/sbin/dmidecode", "-s", "system-manufacturer"]}], +["command", {"args": ["/usr/sbin/dmidecode", "-s", "system-product-name"]}], +["command", {"args": ["/usr/sbin/dmidecode", "-s", "system-version"]}], +["command", {"args": ["/usr/bin/lspci", "-nn"]}], +["command", {"args": ["/bin/df", "--human-readable", "--print-type"]}], +["command", {"args": ["/bin/mount", "--show-labels"]}], +["command", {"args": ["/sbin/dmsetup", "ls", "--tree", "--options=blkdevname,uuid,active,open,rw,notrunc"]}], +["command", {"args": ["/sbin/losetup", "--list", "--output=NAME,BACK-FILE,AUTOCLEAR,RO,PARTSCAN,SIZELIMIT,OFFSET"]}], +["command", {"args": ["/bin/lsmod"]}], +["file", {"user": "root", "path": "/proc/asound/cards"}], +["file", {"user": "root", "path": "/proc/asound/devices"}], +["file", {"user": "root", "path": "/proc/asound/modules"}], +["file", {"user": "root", "path": "/etc/X11/xorg.conf"}], +["file", {"user": "Debian-gdm", "path": "/var/log/gdm3/tails-greeter.errors"}], +["file", {"user": "root", "path": "/var/log/live/boot.log"}], +["file", {"user": "root", "path": "/var/log/live/config.log"}], +["file", {"user": "root", "path": "/var/lib/live/config/tails.physical_security"}], +["file", {"user": "root", "path": "/var/lib/gdm3/tails.persistence"}], +["file", {"user": "tails-persistence-setup", "path": "/live/persistence/TailsData_unlocked/persistence.conf"}], +["file", {"user": "tails-persistence-setup", "path": "/live/persistence/TailsData_unlocked/live-additional-software.conf"}], +["directory", {"user": "root", "path": "/live/persistence/TailsData_unlocked/apt-sources.list.d"}], +["file", {"user": "root", "path": "/var/log/live-persist"}], +["command", {"args": ["/bin/journalctl", "--catalog", "--no-pager"]}] +] diff --git a/config/chroot_local-includes/etc/xdg/autostart/systemd-desktop-target.desktop b/config/chroot_local-includes/etc/xdg/autostart/systemd-desktop-target.desktop new file mode 100644 index 0000000000000000000000000000000000000000..fd3882340d1d8997eb1cdf22f0af9ff01760f989 --- /dev/null +++ b/config/chroot_local-includes/etc/xdg/autostart/systemd-desktop-target.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=systemd Desktop target +GenericName=Start the Desktop target in the systemd user session +Version=1.0 +Exec=/usr/local/lib/start-systemd-desktop-target +Terminal=false +Type=Application +Categories= diff --git a/config/chroot_local-includes/etc/xdg/autostart/systemd-gnome-early-initialization-target.desktop b/config/chroot_local-includes/etc/xdg/autostart/systemd-gnome-early-initialization-target.desktop new file mode 100644 index 0000000000000000000000000000000000000000..3bd42bfe603dd14259d1d18911e8e67ed89743ba --- /dev/null +++ b/config/chroot_local-includes/etc/xdg/autostart/systemd-gnome-early-initialization-target.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=systemd GNOME EarlyInitialization target +GenericName=Start the GNOME EarlyInitialization target in the systemd user session +Version=1.0 +Exec=/bin/systemctl --user start gnome-early-initialization.target +Terminal=false +Type=Application +Categories= +X-GNOME-Autostart-Phase=EarlyInitialization diff --git a/config/chroot_local-includes/etc/xul-ext/torbirdy.js b/config/chroot_local-includes/etc/xul-ext/torbirdy.js new file mode 100644 index 0000000000000000000000000000000000000000..1f5b467ba68bc9dc000baec8c184d2f533ede25c --- /dev/null +++ b/config/chroot_local-includes/etc/xul-ext/torbirdy.js @@ -0,0 +1,6 @@ +// Place your preferences for xul-ext-torbirdy in this file. +// You can override here the preferences specified in +// /usr/share/xul-ext/torbirdy/defaults/preferences/prefs.js + +pref("extensions.torbirdy.emailwizard", true); +pref("extensions.torbirdy.gpg_already_torified", true); diff --git a/config/chroot_local-includes/lib/live/config/0000-boot-profile b/config/chroot_local-includes/lib/live/config/0000-boot-profile new file mode 100755 index 0000000000000000000000000000000000000000..9daaa41dad251e02d058b5ceac18842ba1ee3391 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/0000-boot-profile @@ -0,0 +1,35 @@ +#!/bin/sh + +Boot_profile () +{ + # Only start profiler when "profile" appears on kernel command line + grep -qw "profile" /proc/cmdline || return 0 + + echo -n " boot-profile" + + Start_boot_profile +} + +Start_boot_profile () +{ + + # Schedule stop script + mkdir -p /etc/skel/.config/autostart + cat <"/etc/skel/.config/autostart/end-profile.desktop" +[Desktop Entry] +Version=1.0 +Name=EndProfile +GenericName=EndProfile +Exec=/usr/local/lib/end-profile +Terminal=false +Type=Application +EOF + + echo 32768 >/proc/sys/fs/inotify/max_user_watches + /usr/local/lib/boot-profile /var/log/boot-profile + + # Creating state file + touch /var/lib/live/config/boot-profile +} + +Boot_profile diff --git a/config/chroot_local-includes/lib/live/config/0001-sane-clock b/config/chroot_local-includes/lib/live/config/0001-sane-clock new file mode 100755 index 0000000000000000000000000000000000000000..b9d96cbed45493b234664093e587153dfbd0fd9e --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/0001-sane-clock @@ -0,0 +1,12 @@ +#!/bin/sh + +echo "- making sure the system clock is sane" + +# If the system clock is before the source date, then we know it's +# incorrect and set it too the source date. However, to account for +# potential issues due to timezone differences etc we ignore clocks +# that are up to 1 day before the source date. +SOURCE_DATE="$(sed -n -e '1s/^.* - \([0-9]\+\)$/\1/p;q' /etc/amnesia/version)" +if [ "$(date +%s)" -lt "$(date -d "${SOURCE_DATE} - 1 day" +%s)" ]; then + date --set "${SOURCE_DATE}" +fi diff --git a/config/chroot_local-includes/lib/live/config/1000-remount-procfs b/config/chroot_local-includes/lib/live/config/1000-remount-procfs new file mode 100755 index 0000000000000000000000000000000000000000..82a7a73d77e46cf4a403fa28b10bb67d74e9769f --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/1000-remount-procfs @@ -0,0 +1,8 @@ +#!/bin/sh + +Remount_Proc_Fs () +{ + mount -o remount /proc +} + +Remount_Proc_Fs diff --git a/config/chroot_local-includes/lib/live/config/1500-reconfigure-APT b/config/chroot_local-includes/lib/live/config/1500-reconfigure-APT new file mode 100755 index 0000000000000000000000000000000000000000..60c68876a18485e0f98d12c1a47768370419bfa8 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/1500-reconfigure-APT @@ -0,0 +1,115 @@ +#!/bin/sh + +echo "- configuring APT sources" + +sed -i 's,^\(\#\?\s*deb\(-src\)\?\s\+\)http://,\1tor+http://,' \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.list + +sed -E -i 's,\s+non-free$,,' \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.list + +sed -E -i '/^deb(-src)?\s+\S+\s+\S+-proposed-updates\s+/d' \ + /etc/apt/sources.list /etc/apt/sources.list.d/*.list + +echo ' + +### Time-based snapshots + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://time-based[.]snapshots[.]deb[.]tails[.]boum[.]org + /debian + /[0-9]{10} # serial + /? + (\s+) +}{$1tor+http://vwakviie2ienjx6t.onion/debian/$2}xms; + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://time-based[.]snapshots[.]deb[.]tails[.]boum[.]org + /debian-security + /[0-9]{10} # serial + /? + (\s+) +}{$1tor+http://sgvtcaew4bxjd7ln.onion/$2}xms; + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://time-based[.]snapshots[.]deb[.]tails[.]boum[.]org + /torproject + /[0-9]{10} # serial + /? + (\s+) +}{$1tor+http://sdscoq7snqtznauu.onion/torproject.org/$2}xms; + +### Tagged snapshots + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://tagged[.]snapshots[.]deb[.]tails[.]boum[.]org + /[0-9a-z.-]+ # tag + /debian + /? + (\s+) +}{$1tor+http://vwakviie2ienjx6t.onion/debian/$2}xms; + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://tagged[.]snapshots[.]deb[.]tails[.]boum[.]org + /[0-9a-z.-]+ # tag + /debian-security + /? + (\s+) +}{$1tor+http://sgvtcaew4bxjd7ln.onion/$2}xms; + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://tagged[.]snapshots[.]deb[.]tails[.]boum[.]org + /[0-9a-z.-]+ # tag + /torproject + /? + (\s+) +}{$1tor+http://sdscoq7snqtznauu.onion/torproject.org/$2}xms; + +### Custom APT repository + +s{ + ^ + (deb(?:-src)?\s+) + tor[+]https?://deb[.]tails[.]boum[.]org + /? + (\s+) +}{$1tor+http://jenw7xbd6tf7vfhp.onion/$2}xms; + +' | perl -pi - /etc/apt/sources.list /etc/apt/sources.list.d/*.list + +echo "- configuring APT preferences" + +echo ' +### Custom APT repository + +s{ + ^ + (Pin:\s+origin\s+) + deb[.]tails[.]boum[.]org + $ +}{$1jenw7xbd6tf7vfhp.onion}xms; + +### Fix origin for backports + +s{ + ^ + (Pin:\s+release\s+) + o=Debian + (,[an]=stretch-backports) + $ +}{$1o=Debian Backports$2}xms; +' | perl -pi - /etc/apt/preferences + +find /etc/apt/sources.list* -size 0 -delete diff --git a/config/chroot_local-includes/lib/live/config/1600-undivert-APT b/config/chroot_local-includes/lib/live/config/1600-undivert-APT new file mode 100755 index 0000000000000000000000000000000000000000..93f8b539d4f74082eac1e346319620b085412ac1 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/1600-undivert-APT @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "- undiverting APT" + +if [ -f /usr/bin/apt-get.real ]; then + rm -f usr/bin/apt-get + dpkg-divert --rename --remove /usr/bin/apt-get +fi diff --git a/config/chroot_local-includes/lib/live/config/2000-aesthetics b/config/chroot_local-includes/lib/live/config/2000-aesthetics new file mode 100755 index 0000000000000000000000000000000000000000..07847f0ddbcb0e7998c7f5298ed8c2108176b269 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/2000-aesthetics @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "" +echo "Configuring Tails" diff --git a/config/chroot_local-includes/lib/live/config/2000-import-gnupg-key b/config/chroot_local-includes/lib/live/config/2000-import-gnupg-key new file mode 100755 index 0000000000000000000000000000000000000000..b409e9015608bf87a55daeb5b6608e9806851f89 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/2000-import-gnupg-key @@ -0,0 +1,23 @@ +#!/bin/sh + +Import_GnuPG_key () +{ + echo "- importing Tails' GnuPG keys into the ${LIVE_USERNAME}'s keyring" + sudo -H -u "${LIVE_USERNAME}" gpg --batch --import /usr/share/doc/tails/website/*.key + + echo "- importing Tails' GnuPG signing key into tails-iuk's trusted keyring" + gpg --batch --homedir /usr/share/tails-iuk/trusted_gnupg_homedir \ + --import /usr/share/doc/tails/website/tails-signing.key + chmod -R go+rX /usr/share/tails-iuk + + echo "- importing Tails help desk's GnuPG key into WhisperBack's keyring" + gpg --batch --no-default-keyring \ + --keyring /usr/share/keyrings/whisperback-keyring.gpg \ + --import /usr/share/doc/tails/website/tails-bugs.key + chmod a+r /usr/share/keyrings/whisperback-keyring.gpg + + # Creating state file + touch /var/lib/live/config/import-gnupg-key +} + +Import_GnuPG_key diff --git a/config/chroot_local-includes/lib/live/config/2010-pidgin b/config/chroot_local-includes/lib/live/config/2010-pidgin new file mode 100755 index 0000000000000000000000000000000000000000..df5f2f94f117dadb7b683fd492b0c46e83072431 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/2010-pidgin @@ -0,0 +1,63 @@ +#!/bin/sh + +# List of at least 2000 possible nicknames +NICKS_LIST=/usr/share/tails/firstnames.txt + +# returns true with probability $1 +prob() +{ + # sh doesn't have bash's $RANDOM, so we implement it + RANDOM=$(expr $(od -Anv -N4 -tu4 /dev/urandom) % 32768) + # we compare with > instead of <= due to mismatch between bash and bc + # on what values true and false have. + return $(echo "scale = 10; ${RANDOM}/32767 > ${1}" | bc) +} + +leet_nick() +{ + # we leave the first letter due to restrictions on nicks in IRC + first=$(expr substr ${1} 1 1) + rest=${1#?} + rest=$(echo "${rest}" | tr 'e' '3' | tr 'i' '1' | tr 'o' '0') + echo "${first}${rest}" +} + +generate_nick() +{ + NICK=$(/usr/local/bin/lc.py -g 1 --min 4 --max 10 "${NICKS_LIST}") + + if prob 0.90; then + NICK=$(echo "${NICK}" | tr '[:upper:]' '[:lower:]') + fi + + if prob 0.05; then + if prob 0.50; then + NICK="${NICK}_" + else + NICK="${NICK}^" + fi + fi + + if prob 0.05; then + NICK=$(leet_nick "${NICK}") + fi + + echo ${NICK} +} + +Configure_pidgin () +{ + + echo "- configuring Pidgin" + + NICK=$(generate_nick) + + for file in accounts.xml blist.xml ; do + sudo -H -u "${LIVE_USERNAME}" sed -i'' "s,XXX_NICK_XXX,${NICK}," "/home/${LIVE_USERNAME}/.purple/${file}" + done + + # Creating state file + touch /var/lib/live/config/pidgin +} + +Configure_pidgin diff --git a/config/chroot_local-includes/lib/live/config/2030-systemd b/config/chroot_local-includes/lib/live/config/2030-systemd new file mode 100755 index 0000000000000000000000000000000000000000..6ee1820067d24e80feecdffa299f3ab98a779c8b --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/2030-systemd @@ -0,0 +1,10 @@ +#!/bin/sh +# +# Recreate files (eg. /var/lib/systemd/catalog/database, /etc/machine-id, etc.) +# at boot-time as we remove them to ensure a deterministic build. + +echo "- configuring systemd" + +systemd-machine-id-setup + +journalctl --update-catalog diff --git a/config/chroot_local-includes/lib/live/config/3000-tps-media-directory b/config/chroot_local-includes/lib/live/config/3000-tps-media-directory new file mode 100755 index 0000000000000000000000000000000000000000..8957a791be2e38c2a19809f5dd7a708a2a553154 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/3000-tps-media-directory @@ -0,0 +1,19 @@ +#!/bin/sh + +# We need laxer permissions than the default (tails-persistence-setup:root, +# 0700) here so that a newly created persistent volume is accessible +# to the amnesia user, that runs the tails-additional-software-config +# GUI app which needs to read +# /media/tails-persistence-setup/TailsData/live-additional-software.conf. + +Create_tps_media_directory () +{ + echo "- creating tails-persistence-setup's directory under /media" + install -o tails-persistence-setup -g amnesia \ + -m 0710 -d /media/tails-persistence-setup + + # Creating state file + touch /var/lib/live/config/tps-media-directory +} + +Create_tps_media_directory diff --git a/config/chroot_local-includes/lib/live/config/7000-debug b/config/chroot_local-includes/lib/live/config/7000-debug new file mode 100755 index 0000000000000000000000000000000000000000..8090dce65af1efd4944c50f9e4abb2944113b992 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/7000-debug @@ -0,0 +1,13 @@ +#!/bin/sh + +Set_root_password () +{ + echo "- setting root password" + echo "root:root" | chpasswd + touch /var/lib/live/config/rootpassword +} + +if grep -qw "debug=root" /proc/cmdline +then + Set_root_password +fi diff --git a/config/chroot_local-includes/lib/live/config/8000-rootpw b/config/chroot_local-includes/lib/live/config/8000-rootpw new file mode 100755 index 0000000000000000000000000000000000000000..7a48eedd7baaa4f3001c2e97c8037b5bb6ad7689 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/8000-rootpw @@ -0,0 +1,11 @@ +#!/bin/sh + +for X in $(cat /proc/cmdline); do + case ${X} in + rootpw=*) + PW=${X#rootpw=} + usermod -p $(echo ${PW} | mkpasswd -s) root + exit 0 + ;; + esac +done diff --git a/config/chroot_local-includes/lib/live/config/9000-hosts-file b/config/chroot_local-includes/lib/live/config/9000-hosts-file new file mode 100644 index 0000000000000000000000000000000000000000..461a85dce39dc79ecbcc94c2d40526bcb9c03555 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/9000-hosts-file @@ -0,0 +1,19 @@ +#!/bin/sh + +# Note: must run after /lib/live/config/0020-hostname since it +# otherwise will overwrite any hosts file generated at build time with +# a bloated one that also include the IPv6 host `::1 localhost`, which +# can lead to IPv6 traffic, which we block, which may lead to stuff +# breaking (for instance APT's tor+http transport). +# +# localhost.localdomain added to prevent loopback leaks to Tor circuits +# for applications that use the FQDN (fully qualified domain name) model +# + +echo "- setting up hosts file" + +. /etc/live/config.d/hostname.conf + +cat > /etc/hosts << EOF +127.0.0.1 localhost localhost.localdomain ${LIVE_HOSTNAME} +EOF diff --git a/config/chroot_local-includes/lib/live/config/9980-permissions b/config/chroot_local-includes/lib/live/config/9980-permissions new file mode 100755 index 0000000000000000000000000000000000000000..adc07a2fef1452d085dee668e4539a64e2a8dac2 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/9980-permissions @@ -0,0 +1,13 @@ +#!/bin/sh + +Fix_permissions () +{ + echo "- fixing permissions" + chown -R "${LIVE_USERNAME}":"${LIVE_USERNAME}" "/home/${LIVE_USERNAME}" + chmod go= "/home/${LIVE_USERNAME}" + + # Creating state file + touch /var/lib/live/config/permissions +} + +Fix_permissions diff --git a/config/chroot_local-includes/lib/live/config/9999-unset-user-account-comment b/config/chroot_local-includes/lib/live/config/9999-unset-user-account-comment new file mode 100755 index 0000000000000000000000000000000000000000..802e27e348c3fd570387df0acc42f8dab0f5c5a9 --- /dev/null +++ b/config/chroot_local-includes/lib/live/config/9999-unset-user-account-comment @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +usermod -c "" "${LIVE_USERNAME}" diff --git a/config/chroot_local-includes/lib/live/mount/persistence b/config/chroot_local-includes/lib/live/mount/persistence new file mode 120000 index 0000000000000000000000000000000000000000..fc4cc90aaa0707215ae4e08272c382a1f0d8475b --- /dev/null +++ b/config/chroot_local-includes/lib/live/mount/persistence @@ -0,0 +1 @@ +/live/persistence \ No newline at end of file diff --git a/config/chroot_local-includes/lib/systemd/system-shutdown/tails b/config/chroot_local-includes/lib/systemd/system-shutdown/tails new file mode 100755 index 0000000000000000000000000000000000000000..3800121b055a44005770dc192a13b0b87ed3e64f --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system-shutdown/tails @@ -0,0 +1,14 @@ +#!/bin/sh + +set -x + +# This script is only run by the instance of systemd-shutdown that's +# run outside of the initramfs, and not by the other instance of +# systemd-shutdown that's run (as /shutdown) after returning to the +# initramfs during shutdown: in the initramfs, this script is +# overwritten with /usr/local/lib/initramfs-pre-shutdown-hook. + +# Debugging +/bin/ls -l /run/initramfs + +echo 3 > /proc/sys/vm/drop_caches diff --git a/config/chroot_local-includes/lib/systemd/system-sleep/toggle-tails-shutdown-on-media-removal.sh b/config/chroot_local-includes/lib/systemd/system-sleep/toggle-tails-shutdown-on-media-removal.sh new file mode 100755 index 0000000000000000000000000000000000000000..859d21eb83de7c283a32ab90b6643212546ddbbb --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system-sleep/toggle-tails-shutdown-on-media-removal.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +case "$1" in + pre) + systemctl stop tails-shutdown-on-media-removal.service + ;; + post) + systemctl start tails-shutdown-on-media-removal.service + ;; +esac diff --git a/config/chroot_local-includes/lib/systemd/system.conf.d/lower-DefaultTimeoutStopSec.conf b/config/chroot_local-includes/lib/systemd/system.conf.d/lower-DefaultTimeoutStopSec.conf new file mode 100644 index 0000000000000000000000000000000000000000..90dce4f6602dfaaf6f5d0b3ed887cab4f4fec599 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system.conf.d/lower-DefaultTimeoutStopSec.conf @@ -0,0 +1,2 @@ +[Manager] +DefaultTimeoutStopSec=5s diff --git a/config/chroot_local-includes/lib/systemd/system/alsa-restore.service.d/dont-store-state-on-shutdown.conf b/config/chroot_local-includes/lib/systemd/system/alsa-restore.service.d/dont-store-state-on-shutdown.conf new file mode 100644 index 0000000000000000000000000000000000000000..f178f07fcd4797f33fd105baca3119d35d1b3989 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/alsa-restore.service.d/dont-store-state-on-shutdown.conf @@ -0,0 +1,2 @@ +[Service] +ExecStop= diff --git a/config/chroot_local-includes/lib/systemd/system/cups.service.d/after-AppArmor.conf b/config/chroot_local-includes/lib/systemd/system/cups.service.d/after-AppArmor.conf new file mode 100644 index 0000000000000000000000000000000000000000..544fb7da8dd73d7dc871f88290ac427a777a4678 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/cups.service.d/after-AppArmor.conf @@ -0,0 +1,2 @@ +[Unit] +After=apparmor.service diff --git a/config/chroot_local-includes/lib/systemd/system/gdm.service.d/failure.conf b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/failure.conf new file mode 100644 index 0000000000000000000000000000000000000000..f05a8d528b05d3f43af63effb4341551b0cf9e72 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/failure.conf @@ -0,0 +1,2 @@ +[Unit] +OnFailure=tails-gdm-failed-to-start.service diff --git a/config/chroot_local-includes/lib/systemd/system/gdm.service.d/permissions.conf b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/permissions.conf new file mode 100644 index 0000000000000000000000000000000000000000..ebde20ee883095c561d0cd234c90a39cb6f7e626 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/permissions.conf @@ -0,0 +1,5 @@ +[Service] + +# Tails Greeter writes to the tails.persistence file in there +ExecStartPre=/bin/chgrp Debian-gdm /var/lib/live/config/ +ExecStartPre=/bin/chmod g+w /var/lib/live/config/ diff --git a/config/chroot_local-includes/lib/systemd/system/gdm.service.d/restart.conf b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/restart.conf new file mode 100644 index 0000000000000000000000000000000000000000..1a68d481e546eee3377bcd53ac5fa85914b60e8c --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/gdm.service.d/restart.conf @@ -0,0 +1,6 @@ +[Service] + +# The GDM unit file has a Restart=always directive, which is good in the +# general case. However, it breaks our emergency shutdown on boot medium +# removal feature, so we disable it. +Restart=no diff --git a/config/chroot_local-includes/lib/systemd/system/htpdate.service b/config/chroot_local-includes/lib/systemd/system/htpdate.service new file mode 100644 index 0000000000000000000000000000000000000000..dda8aef88f3405ff30aa2e3131c3765463fd1c3c --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/htpdate.service @@ -0,0 +1,38 @@ +[Unit] +Description=Setting time using HTP +Documentation=https://tails.boum.org/contribute/design/Time_syncing/ +Before=time-sync.target +Wants=time-sync.target + +[Service] +Type=oneshot +Environment=DONE_FILE=/run/htpdate/done +Environment=SUCCESS_FILE=/run/htpdate/success +Environment=LOG=/var/log/htpdate.log +EnvironmentFile=/etc/default/htpdate.* +ExecStartPre=/bin/sh -c \ + '[ -n "${HTTP_USER_AGENT}" ] && \ + [ -n "${HTP_POOL_1}" ] && \ + [ -n "${HTP_POOL_2}" ] && \ + [ -n "${HTP_POOL_3}" ]' +ExecStartPre=/bin/rm -f "${DONE_FILE}" +ExecStartPre=/bin/rm -f "${SUCCESS_FILE}" +ExecStartPre=/usr/bin/install -o htp -g nogroup -m 0644 /dev/null "${LOG}" +ExecStart=/usr/local/sbin/htpdate \ + --debug \ + --log_file "${LOG}" \ + --user_agent "${HTTP_USER_AGENT}" \ + --allowed_per_pool_failure_ratio 0.34 \ + --user htp \ + --done_file "${DONE_FILE}" \ + --success_file "${SUCCESS_FILE}" \ + --pool1 "${HTP_POOL_1}" \ + --pool2 "${HTP_POOL_2}" \ + --pool3 "${HTP_POOL_3}" \ + --proxy 127.0.0.1:9062 +RemainAfterExit=yes +CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_SETUID CAP_SYS_TIME +PrivateDevices=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full diff --git a/config/chroot_local-includes/lib/systemd/system/initramfs-shutdown.service b/config/chroot_local-includes/lib/systemd/system/initramfs-shutdown.service new file mode 100644 index 0000000000000000000000000000000000000000..431c05cc79f30dfe6bbe091ae13ad75ced14b54b --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/initramfs-shutdown.service @@ -0,0 +1,12 @@ +[Unit] +Description=Prepare /run/initramfs for shutdown +Documentation=https://tails.boum.org/contribute/design/memory_erasure/ +ConditionPathExists=!/run/initramfs/bin/sh + +[Service] +RemainAfterExit=yes +Type=oneshot +ExecStart=/usr/local/lib/initramfs-restore + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/live-config.service.d/after-tmpfiles.conf b/config/chroot_local-includes/lib/systemd/system/live-config.service.d/after-tmpfiles.conf new file mode 100644 index 0000000000000000000000000000000000000000..5ec278cad061caf0ab39fcc9504fcbca713f303a --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/live-config.service.d/after-tmpfiles.conf @@ -0,0 +1,2 @@ +[Unit] +After=systemd-tmpfiles-setup.service diff --git a/config/chroot_local-includes/lib/systemd/system/memlockd.service.d/oom.conf b/config/chroot_local-includes/lib/systemd/system/memlockd.service.d/oom.conf new file mode 100644 index 0000000000000000000000000000000000000000..bac841be5747038bfef47c1ed223d60f18220a51 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/memlockd.service.d/oom.conf @@ -0,0 +1,2 @@ +[Service] +OOMScoreAdjust=-1000 diff --git a/config/chroot_local-includes/lib/systemd/system/onion-grater.service b/config/chroot_local-includes/lib/systemd/system/onion-grater.service new file mode 100644 index 0000000000000000000000000000000000000000..2032e7021c70ff0a8dcaa6951e119687f5fd8792 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/onion-grater.service @@ -0,0 +1,15 @@ +[Unit] +Description=Tor control port filter proxy +Documentation=https://tails.boum.org/contribute/design/ + +[Service] +Type=simple +ExecStart=/usr/local/lib/onion-grater +CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_SYS_PTRACE +PrivateDevices=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/run-initramfs.mount b/config/chroot_local-includes/lib/systemd/system/run-initramfs.mount new file mode 100644 index 0000000000000000000000000000000000000000..20ad14e9b71c560fe926646804dc3788237b746c --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/run-initramfs.mount @@ -0,0 +1,18 @@ +# This allows systemd-shutdown to execute /run/initramfs/shutdown. +# XXX:Bullseye: if https://github.com/systemd/systemd/pull/9429 is merged, +# we can remove this custom code. + +[Unit] +Description=Extracted initrd directory +ConditionPathIsSymbolicLink=!/run/initramfs +DefaultDependencies=no +Before=initramfs-shutdown.service local-fs.target + +[Mount] +What=tmpfs +Where=/run/initramfs +Type=tmpfs +Options=mode=755 + +[Install] +WantedBy=local-fs.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-additional-software-install.service b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-install.service new file mode 100644 index 0000000000000000000000000000000000000000..72a4603a053402e1bbfbcff9197a04bbb6a3de12 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-install.service @@ -0,0 +1,22 @@ +[Unit] +Description=Install Additional Software Packages +Documentation=https://tails.boum.org/contribute/design/persistence/ +ConditionFileNotEmpty=/live/persistence/TailsData_unlocked/live-additional-software.conf + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=-/usr/local/sbin/tails-additional-software install +ExecStartPost=/usr/bin/install -m 0644 -D /dev/null /run/live-additional-software/installed +TimeoutStartSec=infinity +PrivateDevices=yes +PrivateTmp=yes +# Capabilities needed by tails-additional-software +CapabilityBoundingSet=CAP_DAC_READ_SEARCH +# Capabilities needed by apt/dpkg +CapabilityBoundingSet=CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID +CapabilityBoundingSet=CAP_SETGID CAP_SETUID +ProtectSystem=no +# Capabilities needed by tails-notify-user +CapabilityBoundingSet=CAP_SYS_PTRACE CAP_AUDIT_WRITE CAP_SYS_RESOURCE +ProtectHome=no diff --git a/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.path b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.path new file mode 100644 index 0000000000000000000000000000000000000000..27fa138459b137275a64ac38ec316acd7e1142d5 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.path @@ -0,0 +1,9 @@ +[Unit] +Description=Trigger upgrade of Additional Software Packages +Documentation=https://tails.boum.org/contribute/design/persistence/ +After=tails-additional-software-install.service +After=tor-has-bootstrapped.service +ConditionFileNotEmpty=/live/persistence/TailsData_unlocked/live-additional-software.conf + +[Path] +PathExists=/run/live-additional-software/installed diff --git a/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.service b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.service new file mode 100644 index 0000000000000000000000000000000000000000..f9d235f6df9f56243eb58cc1e64951e9cad2cea5 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-additional-software-upgrade.service @@ -0,0 +1,24 @@ +[Unit] +Description=Upgrade Additional Software Packages +Documentation=https://tails.boum.org/contribute/design/persistence/ +After=tails-additional-software-install.service +After=tor-has-bootstrapped.service +ConditionFileNotEmpty=/live/persistence/TailsData_unlocked/live-additional-software.conf + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/sbin/tails-additional-software upgrade +ExecStartPost=/usr/bin/install -m 0644 -D /dev/null /run/live-additional-software/upgraded +TimeoutStartSec=infinity +PrivateDevices=yes +PrivateTmp=yes +# Capabilities needed by tails-additional-software +CapabilityBoundingSet=CAP_DAC_READ_SEARCH +# Capabilities needed by apt/dpkg +CapabilityBoundingSet=CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID +CapabilityBoundingSet=CAP_SETGID CAP_SETUID +ProtectSystem=no +# Capabilities needed by tails-notify-user +CapabilityBoundingSet=CAP_SYS_PTRACE CAP_AUDIT_WRITE CAP_SYS_RESOURCE +ProtectHome=no diff --git a/config/chroot_local-includes/lib/systemd/system/tails-autotest-broken-Xorg.service b/config/chroot_local-includes/lib/systemd/system/tails-autotest-broken-Xorg.service new file mode 100644 index 0000000000000000000000000000000000000000..705fd089df5fae3ff2358ee19720c9c1cd32adc7 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-autotest-broken-Xorg.service @@ -0,0 +1,13 @@ +[Unit] +Description=Break Xorg for Tails test suite +Documentation=https://tails.boum.org/contribute/release_process/test/automated_tests/ +ConditionKernelCommandLine=autotest_broken_Xorg +Before=gdm.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/sh -c 'echo "#!/bin/sh\nexit 1" > /usr/bin/Xorg' + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-autotest-remote-shell.service b/config/chroot_local-includes/lib/systemd/system/tails-autotest-remote-shell.service new file mode 100644 index 0000000000000000000000000000000000000000..aeb31ed0b3db65c0f5ca0ce676aa43c46074d317 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-autotest-remote-shell.service @@ -0,0 +1,13 @@ +[Unit] +Description=Remote shell used in Tails test suite +Documentation=https://tails.boum.org/contribute/release_process/test/automated_tests/ +ConditionKernelCommandLine=autotest_never_use_this_option +Before=gdm.service + +[Service] +Type=notify +ExecStart=/usr/local/lib/tails-autotest-remote-shell +OOMScoreAdjust=-1000 + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-gdm-failed-to-start.service b/config/chroot_local-includes/lib/systemd/system/tails-gdm-failed-to-start.service new file mode 100644 index 0000000000000000000000000000000000000000..ae598f88d472e4283c49dc492e1a255b8d504683 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-gdm-failed-to-start.service @@ -0,0 +1,38 @@ +[Unit] +Description=Guide the user when GDM fails to start +# GDM normally runs "plymouth --quit" when it fails to start the X server +# (see on_display_status_changed that calls plymouth_quit_without_transition). +# But when this happens we kill -9 GDM in our gdm-x-session wrapper, so it +# might not have time to quit plymouth yet. Therefore we ensure plymouth +# has quit before we start: we run after plymouth-quit.service (which is started +# by gdm.service's default OnFailure=), we have plymouth-quit-wait.service start, +# and we wait for it to complete. +After=plymouth-quit.service +Requires=plymouth-quit-wait.service +After=plymouth-quit-wait.service + +[Service] +Type=oneshot +# We use VT5 that is clean of boot messages and does not get a getty started +# when we switch there, thanks to our custom NAutoVTs=4 logind.conf setting +# +# There are queued udev events when we run plymouthd so on Stretch, so +# watch_for_coldplug_completion will set up a watcher and return before +# there's any place where plymouthd can create a seat to display its +# splash and messages on. So we tell plymouthd to ignore udev which makes +# it create a fallback seat. +# XXX:Buster: check if plymouth.ignore-udev is still necessary (this code path +# has changed in plymouth 0.9.3) +ExecStart=/bin/sh -c \ + '/sbin/plymouthd --mode=shutdown --tty=tty5 \ + --kernel-command-line="plymouth.ignore-udev $(cat /proc/cmdline)"' +ExecStart=/bin/chvt 5 +ExecStart=/bin/plymouth show-splash +ExecStart=/bin/sh -c \ + 'MAX_LENGTH=254 ; \ + PREFIX="Error starting GDM with your graphics card: " ; \ + SUFFIX=". Please take note of this error and visit https://tails.boum.org/gdm for troubleshooting." ; \ + MAX_VIDEO_CARD_LENGTH=$(($MAX_LENGTH - $(echo -n "$PREFIX$SUFFIX" | wc -c))) ; \ + VIDEO_CARD=$(lspci -d::0300 -nn | sed -E "s,.* VGA compatible controller \[0300\]:\s*,," | cut -c "1-$MAX_VIDEO_CARD_LENGTH") ; \ + /bin/plymouth display-message --text="$PREFIX$VIDEO_CARD$SUFFIX" \ + ' diff --git a/config/chroot_local-includes/lib/systemd/system/tails-set-wireless-devices-state.service b/config/chroot_local-includes/lib/systemd/system/tails-set-wireless-devices-state.service new file mode 100644 index 0000000000000000000000000000000000000000..6c41e28947f66c345fc5b01360569cf0de7c53bc --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-set-wireless-devices-state.service @@ -0,0 +1,16 @@ +[Unit] +Description=Set proper default state on wireless devices +Documentation=https://tails.boum.org/contribute/design/ + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/tails-set-wireless-devices-state +CapabilityBoundingSet=~CAP_SYS_ADMIN +PrivateDevices=yes +PrivateNetwork=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-shutdown-on-media-removal.service b/config/chroot_local-includes/lib/systemd/system/tails-shutdown-on-media-removal.service new file mode 100644 index 0000000000000000000000000000000000000000..d469a1d9127a3f9450c35912be45bb823aa16604 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-shutdown-on-media-removal.service @@ -0,0 +1,16 @@ +[Unit] +Description=Wipe memory on live media removal +Documentation=https://tails.boum.org/contribute/design/memory_erasure/ +After=memlockd.service initramfs-shutdown.service + +[Service] +Type=simple +ExecStart=/usr/local/lib/udev-watchdog-wrapper +CapabilityBoundingSet=~CAP_SYS_ADMIN +PrivateNetwork=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-synchronize-data-to-new-persistent-volume-on-shutdown.service b/config/chroot_local-includes/lib/systemd/system/tails-synchronize-data-to-new-persistent-volume-on-shutdown.service new file mode 100644 index 0000000000000000000000000000000000000000..e38097c61013d75cc3308f6ce4edd5fbc931639b --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-synchronize-data-to-new-persistent-volume-on-shutdown.service @@ -0,0 +1,19 @@ +[Unit] +Description=Synchronize data to newly created persistent volume on shutdown + +[Service] +RemainAfterExit=yes +Type=oneshot +ExecStop=/bin/sh -c ' \ + if mountpoint -q /media/tails-persistence-setup/TailsData \ + && test ! -d /media/tails-persistence-setup/TailsData/apt; then \ + echo "Copy APT data to newly created persistent volume"; \ + mkdir /media/tails-persistence-setup/TailsData/apt/ && \ + cp -a /var/cache/apt/archives \ + /media/tails-persistence-setup/TailsData/apt/cache && \ + cp -a /var/lib/apt/lists \ + /media/tails-persistence-setup/TailsData/apt/; \ + fi' + +[Install] +WantedBy=multi-user.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped-flag-file.service b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped-flag-file.service new file mode 100644 index 0000000000000000000000000000000000000000..1d932c53cf1956414920f5c477e71602723efea5 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped-flag-file.service @@ -0,0 +1,21 @@ +[Unit] +Description=Manage the flag file that indicates whether Tor has bootstrapped +Documentation=https://tails.boum.org/contribute/design/ +After=tails-wait-until-tor-has-bootstrapped.service +PartOf=tails-tor-has-bootstrapped.target + +[Service] +Type=oneshot +RemainAfterExit=yes +User=debian-tor +ExecStart=/bin/touch /run/tor-has-bootstrapped/done +ExecStop=/bin/rm -f /run/tor-has-bootstrapped/done +CapabilityBoundingSet= +PrivateDevices=yes +PrivateNetwork=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full + +[Install] +WantedBy=tails-tor-has-bootstrapped.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target new file mode 100644 index 0000000000000000000000000000000000000000..0aca04f33838696849991995107cea53d03216df --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target @@ -0,0 +1,10 @@ +[Unit] +Description=Tor has bootstrapped +Documentation=https://tails.boum.org/contribute/design/ +Requires=graphical.target +Conflicts=rescue.service rescue.target +After=graphical.target rescue.service rescue.target +AllowIsolate=yes + +[Install] +WantedBy=graphical.target diff --git a/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service b/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service new file mode 100644 index 0000000000000000000000000000000000000000..e8feacad7cac3c6d5b3bd9d1b0a660dd902114a3 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service @@ -0,0 +1,31 @@ +[Unit] +Description=Unblock network device drivers +Documentation=https://tails.boum.org/contribute/design/MAC_address/ + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/var/lib/gdm3/tails.physical_security + +# It's important we "export" the settings from tails.physical_security +# before unblocking the network; doing so will make the user-set MAC spoofing +# option apply (via the custom udev rule) when loading the modules for the +# previously blocked network devices. +ExecStartPre=/usr/bin/install -m 0640 -o root -g root \ + /var/lib/gdm3/tails.physical_security \ + /var/lib/live/config/tails.physical_security +ExecStartPre=/bin/sync +ExecStartPre=/bin/sh -c \ + 'if [ "${TAILS_NETCONF}" = "obstacle" ] ; then \ + . /usr/local/lib/tails-shell-library/tor.sh ; \ + tor_set_in_torrc "DisableNetwork" "1" ; \ + fi' + +# We sync to make sure the blacklist has disappeared from the +# filesystem +ExecStart=/bin/sh -c \ + 'if [ "${TAILS_NETCONF}" != "disabled" ] ; then \ + /bin/rm -f /etc/modprobe.d/all-net-blacklist.conf ; \ + /bin/touch /etc/modprobe.d ; \ + /bin/sync ; \ + fi' diff --git a/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service b/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service new file mode 100644 index 0000000000000000000000000000000000000000..64f2afde0c11511fcc08a713e13e9db5b6f63ff1 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service @@ -0,0 +1,22 @@ +[Unit] +Description=Wait for Tor to Have Bootstrapped +Documentation=https://tails.boum.org/contribute/design/ +After=tor@default.service +Before=tails-tor-has-bootstrapped.target + +[Service] +Type=oneshot +User=debian-tor +ExecStart=/bin/sh -c '. /usr/local/lib/tails-shell-library/tor.sh ; \ + while ! tor_is_working ; do \ + /bin/sleep 1 ; \ + done' +TimeoutStartSec=0 +CapabilityBoundingSet= +PrivateDevices=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full + +[Install] +WantedBy=tails-tor-has-bootstrapped.target diff --git a/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/fix-obfs4proxy.conf b/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/fix-obfs4proxy.conf new file mode 100644 index 0000000000000000000000000000000000000000..9cb80b8795aafeada799df91166339d2a33d7dec --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/fix-obfs4proxy.conf @@ -0,0 +1,4 @@ +[Service] + +# obfs4proxy can't start otherwise +NoNewPrivileges=no diff --git a/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/writable-etc-tor.conf b/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/writable-etc-tor.conf new file mode 100644 index 0000000000000000000000000000000000000000..096151a2142dbcf9b143725440e5c19a446332e0 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/tor@default.service.d/writable-etc-tor.conf @@ -0,0 +1,5 @@ +[Service] + +# Tor Launcher needs to make Tor modify its configuration +ProtectSystem=yes +ReadWriteDirectories=-/etc/tor diff --git a/config/chroot_local-includes/lib/systemd/system/var-tmp.mount b/config/chroot_local-includes/lib/systemd/system/var-tmp.mount new file mode 100644 index 0000000000000000000000000000000000000000..cef423d97c1b9f37b4813733d29fda6ece235de6 --- /dev/null +++ b/config/chroot_local-includes/lib/systemd/system/var-tmp.mount @@ -0,0 +1,15 @@ +[Unit] +Description=Temporary Directory +ConditionPathIsSymbolicLink=!/var/tmp +DefaultDependencies=no +Conflicts=umount.target +Before=local-fs.target umount.target + +[Mount] +What=tmpfs +Where=/var/tmp +Type=tmpfs +Options=mode=1777,strictatime + +[Install] +WantedBy=local-fs.target diff --git a/config/chroot_local-includes/live/overlay b/config/chroot_local-includes/live/overlay new file mode 120000 index 0000000000000000000000000000000000000000..1f1f1cf62f0f7fc0d93fa4eb61a88b9a1b149f3e --- /dev/null +++ b/config/chroot_local-includes/live/overlay @@ -0,0 +1 @@ +/lib/live/mount/overlay \ No newline at end of file diff --git a/config/chroot_local-includes/root/.synaptic/synaptic.conf b/config/chroot_local-includes/root/.synaptic/synaptic.conf new file mode 100644 index 0000000000000000000000000000000000000000..3a18e4aa4b37d782e6ec51ce1fcf632c93b90f60 --- /dev/null +++ b/config/chroot_local-includes/root/.synaptic/synaptic.conf @@ -0,0 +1,4 @@ +Synaptic "" { + showWelcomeDialog "0"; + Maximized "1"; +}; diff --git a/config/chroot_local-includes/usr/lib/gdm3/gdm-x-session.tails b/config/chroot_local-includes/usr/lib/gdm3/gdm-x-session.tails new file mode 100755 index 0000000000000000000000000000000000000000..9441ab738984277899c7f26f669983b8504cf81a --- /dev/null +++ b/config/chroot_local-includes/usr/lib/gdm3/gdm-x-session.tails @@ -0,0 +1,35 @@ +#!/bin/sh + +# No "set -e" because we need to capture the exit status of gdm-x-session.real +set -u + +FAILURES_COUNT_FILE=/var/lib/gdm3/gdm-x-session_failures +MAX_FAILURES=5 + +get_failures () { + local failures=0 + if [ -f "$FAILURES_COUNT_FILE" ] ; then + failures=$(cat "$FAILURES_COUNT_FILE") + fi + echo -n "$failures" +} + +increment_failures () { + failures=$(($(get_failures) + 1)) + echo -n "$failures" > "$FAILURES_COUNT_FILE" +} + +/usr/lib/gdm3/gdm-x-session.real "$@" + +RET=$? + +if [ $RET -ne 0 ] ; then + increment_failures + if [ $(get_failures) -ge "$MAX_FAILURES" ] ; then + # Trigger OnFailure=tails-gdm-failed-to-start.service + echo "gdm-x-session failed too many times, stopping GDM" + sudo -n /bin/systemctl kill --signal=9 gdm + fi +fi + +exit $RET diff --git a/config/chroot_local-includes/usr/lib/systemd/logind.conf.d/lower-NAutoVTs.conf b/config/chroot_local-includes/usr/lib/systemd/logind.conf.d/lower-NAutoVTs.conf new file mode 100644 index 0000000000000000000000000000000000000000..df32fcca78999ef850565020f00a1d1e7ccccb05 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/logind.conf.d/lower-NAutoVTs.conf @@ -0,0 +1,3 @@ +# Leaves a free virtual terminal to run tails-gdm-failed-to-start.service on +[Login] +NAutoVTs=4 diff --git a/config/chroot_local-includes/usr/lib/systemd/user/desktop.target b/config/chroot_local-includes/usr/lib/systemd/user/desktop.target new file mode 100644 index 0000000000000000000000000000000000000000..5f4ee0f2e0dede96e298d18822a2435064cb1659 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/desktop.target @@ -0,0 +1,5 @@ +[Unit] +Description=Desktop +Requires=default.target +After=default.target +AllowIsolate=yes diff --git a/config/chroot_local-includes/usr/lib/systemd/user/gnome-early-initialization.target b/config/chroot_local-includes/usr/lib/systemd/user/gnome-early-initialization.target new file mode 100644 index 0000000000000000000000000000000000000000..0a024d7ee6ade527ea520be2d9f535594dd7cd5a --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/gnome-early-initialization.target @@ -0,0 +1,5 @@ +[Unit] +Description=Bits of GNOME EarlyInitialization managed by systemd +Requires=default.target +After=default.target +AllowIsolate=yes diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-add-GNOME-bookmarks.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-add-GNOME-bookmarks.service new file mode 100644 index 0000000000000000000000000000000000000000..834af27fd27bf40d67739ea362ddfbb23c8f9cb1 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-add-GNOME-bookmarks.service @@ -0,0 +1,11 @@ +[Unit] +Description=Add GTK bookmarks to some directories +Documentation=https://tails.boum.org/contribute/design/application_isolation/ + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/add-GNOME-bookmarks +RemainAfterExit=yes + +[Install] +WantedBy=basic.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-additional-software-install.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-additional-software-install.service new file mode 100644 index 0000000000000000000000000000000000000000..fff9413ba385453bb7ded96ab4772109afb5ea9c --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-additional-software-install.service @@ -0,0 +1,18 @@ +# This user unit triggers installation of additional software packages after +# the desktop has started by starting the identically named system unit. + +[Unit] +Description=Trigger installation of Additional Software Packages +Documentation=https://tails.boum.org/contribute/design/persistence/ + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/sudo /bin/systemctl start tails-additional-software-install.service +# XXX:Buster: when policykit-1 >= 0.106 is available in Tails, we should +# use the following, and remove sudoers.d configuration: +#ExecStart=/bin/systemctl start tails-additional-software-install.service +TimeoutStartSec=0 + +[Install] +WantedBy=desktop.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-configure-keyboard.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-configure-keyboard.service new file mode 100644 index 0000000000000000000000000000000000000000..21dff6800384a79152cd40f919786ef00770d12b --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-configure-keyboard.service @@ -0,0 +1,11 @@ +[Unit] +Description=Configure the keyboard layout according to settings chosen in Tails Greeter +Documentation=https://tails.boum.org/contribute/design/ + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/tails-configure-keyboard +RemainAfterExit=yes + +[Install] +WantedBy=gnome-early-initialization.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-create-tor-browser-directories.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-create-tor-browser-directories.service new file mode 100644 index 0000000000000000000000000000000000000000..bb02fd6f72abfcd0722b68624add41526723a3af --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-create-tor-browser-directories.service @@ -0,0 +1,11 @@ +[Unit] +Description=Create the Tor Browser amnesiac and persistent directories +Documentation=https://tails.boum.org/contribute/design/application_isolation/ + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/create-tor-browser-directories +RemainAfterExit=yes + +[Install] +WantedBy=basic.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-security-check.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-security-check.service new file mode 100644 index 0000000000000000000000000000000000000000..01260af3ba4fc3f0e367e9e5b285b5a41dad4252 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-security-check.service @@ -0,0 +1,11 @@ +[Unit] +Description=Check Tails known, unfixed security issues +Documentation=https://tails.boum.org/contribute/design/ +After=tails-wait-until-tor-has-bootstrapped.service + +[Service] +ExecStart=/usr/local/bin/tails-security-check +RemainAfterExit=yes + +[Install] +WantedBy=desktop.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-upgrade-frontend.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-upgrade-frontend.service new file mode 100644 index 0000000000000000000000000000000000000000..2b4c9e902de8c5b961616c732af59b134bfc31b6 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-upgrade-frontend.service @@ -0,0 +1,11 @@ +[Unit] +Description=Check available Tails upgrades +Documentation=https://tails.boum.org/contribute/design/incremental_upgrades/ +After=tails-wait-until-tor-has-bootstrapped.service + +[Service] +ExecStart=/usr/local/bin/tails-upgrade-frontend-wrapper +RemainAfterExit=yes + +[Install] +WantedBy=desktop.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-virt-notify-user.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-virt-notify-user.service new file mode 100644 index 0000000000000000000000000000000000000000..591cee38c155d552e97875d840b03a051e8b4c1d --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-virt-notify-user.service @@ -0,0 +1,11 @@ +[Unit] +Description=Warn the user if Tails is running inside a virtual machine +Documentation=https://tails.boum.org/contribute/design/virtualization_support/ + +[Service] +Type=oneshot +ExecStart=/usr/local/lib/tails-virt-notify-user +RemainAfterExit=yes + +[Install] +WantedBy=desktop.target diff --git a/config/chroot_local-includes/usr/lib/systemd/user/tails-wait-until-tor-has-bootstrapped.service b/config/chroot_local-includes/usr/lib/systemd/user/tails-wait-until-tor-has-bootstrapped.service new file mode 100644 index 0000000000000000000000000000000000000000..191f8bdd47dfd496ae6a8a6adf79d36db78fb01e --- /dev/null +++ b/config/chroot_local-includes/usr/lib/systemd/user/tails-wait-until-tor-has-bootstrapped.service @@ -0,0 +1,19 @@ +# The systemd user and system instances don't share units. So, we have +# the *system* tails-wait-until-tor-has-bootstrapped.service create +# a file upon completion -- and the identically named *user* unit file wait for +# that file to appear. + +[Unit] +Description=Wait for Tor to Have Bootstrapped +Documentation=https://tails.boum.org/contribute/design/ + +[Service] +Type=oneshot +ExecStart=/bin/sh -c '[ "$(/usr/bin/id -u)" = 1000 ] || exit 0 ; \ + while ! [ -e /run/tor-has-bootstrapped/done ] ; do \ + /bin/sleep 1 ; \ + done' +TimeoutStartSec=0 + +[Install] +WantedBy=desktop.target diff --git a/config/chroot_local-includes/usr/lib/tmpfiles.d/htpdate.conf b/config/chroot_local-includes/usr/lib/tmpfiles.d/htpdate.conf new file mode 100644 index 0000000000000000000000000000000000000000..2604bc1e8d0f2448990ef446c7908a65a8fd6eb7 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/tmpfiles.d/htpdate.conf @@ -0,0 +1,2 @@ +# Type Path Mode UID GID Age Argument +d /run/htpdate 00755 root root - - diff --git a/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-additional-software.conf b/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-additional-software.conf new file mode 100644 index 0000000000000000000000000000000000000000..d2fd48b5d58e378ed0f8a2054a1945dace544653 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-additional-software.conf @@ -0,0 +1,2 @@ +# Type Path Mode UID GID Age Argument +d /run/live-additional-software 00775 root root - - diff --git a/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-upgrader.conf b/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-upgrader.conf new file mode 100644 index 0000000000000000000000000000000000000000..fd4cb3d5922283045b471edd6a2feb61f9a41385 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/tmpfiles.d/tails-upgrader.conf @@ -0,0 +1,3 @@ +# Type Path Mode UID GID Age Argument +d /run/tails-upgrader 00775 root tails-upgrade-frontend - - +d /usr/share/tails-iuk/trusted_gnupg_homedir 00700 root root - - diff --git a/config/chroot_local-includes/usr/lib/tmpfiles.d/tor-has-bootstrapped.conf b/config/chroot_local-includes/usr/lib/tmpfiles.d/tor-has-bootstrapped.conf new file mode 100644 index 0000000000000000000000000000000000000000..28b7456a716efef99a55445f261871f41b8f8dcf --- /dev/null +++ b/config/chroot_local-includes/usr/lib/tmpfiles.d/tor-has-bootstrapped.conf @@ -0,0 +1,2 @@ +# Type Path Mode UID GID Age Argument +d /run/tor-has-bootstrapped 00755 debian-tor debian-tor - - diff --git a/config/chroot_local-includes/usr/lib/tmpfiles.d/tordate.conf b/config/chroot_local-includes/usr/lib/tmpfiles.d/tordate.conf new file mode 100644 index 0000000000000000000000000000000000000000..6af8297420a9b50e08f204bda3d611ac66d73035 --- /dev/null +++ b/config/chroot_local-includes/usr/lib/tmpfiles.d/tordate.conf @@ -0,0 +1,2 @@ +# Type Path Mode UID GID Age Argument +d /run/tordate 00755 root root - - diff --git a/config/chroot_local-includes/usr/local/bin/electrum b/config/chroot_local-includes/usr/local/bin/electrum new file mode 100755 index 0000000000000000000000000000000000000000..9c6e371f546dab33393859cc73430182a3c94a56 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/electrum @@ -0,0 +1,82 @@ +#! /usr/bin/env python3 +""" +Tails electrum wrapper + +Test with "python3 electrum.py doctest". +The tests will start the tor-browser so you probably +want to use a tester that handles user interaction or +run the tests from the command line and answer prompts as needed. + +goodcrypto.com converted from bash to python and added basic tests. + +>>> # run script +>>> sh.Command(sys.argv[0])() + +""" + +import os +import sys +from gettext import gettext + +import sh + +os.environ['TEXTDOMAIN'] = 'tails' + +HOME_DIR = os.environ['HOME'] +CONF_DIR = os.path.join(HOME_DIR, '.electrum') + + +def main(*args): + if not electrum_config_is_persistent(): + if not verify_start(): + return + + os.execv('/usr/bin/electrum', ['/usr/bin/electrum'] + list(args)) + + +def electrum_config_is_persistent(): + """Return True iff electrum config is persistent. + + >>> electrum_config_is_persistent() + False + """ + + filesystem = sh.findmnt('--noheadings', + '--output', 'SOURCE', + '--target', CONF_DIR).stdout.decode().strip() + return filesystem in sh.glob('/dev/mapper/TailsData_unlocked[/electrum]') + + +def verify_start(): + """Ask user whether to start Electrum. + + >>> verify_start() in (True, False) + True + """ + + disabled_text = gettext('Persistence is disabled for Electrum') + warning_text = gettext( + "When you reboot Tails, all of Electrum's data will be lost, including your Bitcoin wallet. It is strongly recommended to only run Electrum when its persistence feature is activated.") + question_text = gettext('Do you want to start Electrum anyway?') + dialog_msg = ('{}\n\n{}\n\n{}\n'. + format(disabled_text, warning_text, question_text)) + launch_text = gettext('_Launch') + exit_text = gettext('_Exit') + + # results 0 == True; 1 == False; 5 == Timeout + results = sh.zenity('--question', '--title', '', '--default-cancel', + '--ok-label', launch_text, + '--cancel-label', exit_text, + '--text', dialog_msg, + _ok_code=[0,1,5]) + start = results.exit_code == 0 + + return start + + +if __name__ == '__main__': + if len(sys.argv) > 1 and sys.argv[1] == 'doctest': + import doctest + doctest.testmod() + else: + main(*sys.argv[1:]) diff --git a/config/chroot_local-includes/usr/local/bin/git b/config/chroot_local-includes/usr/local/bin/git new file mode 100755 index 0000000000000000000000000000000000000000..487236252dd95cda0cbc4924e7538616aeed72d6 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/git @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/torsocks /usr/bin/git "$@" diff --git a/config/chroot_local-includes/usr/local/bin/gnome-terminal-pkexec b/config/chroot_local-includes/usr/local/bin/gnome-terminal-pkexec new file mode 100755 index 0000000000000000000000000000000000000000..4982d5203a35b35b7a379e04cd43c09b7839a89a --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/gnome-terminal-pkexec @@ -0,0 +1,2 @@ +#!/bin/sh +pkexec /usr/bin/gnome-terminal "${@}" diff --git a/config/chroot_local-includes/usr/local/bin/keepassx b/config/chroot_local-includes/usr/local/bin/keepassx new file mode 100755 index 0000000000000000000000000000000000000000..806259ca8e0e3312bc4f4e952e90c3f2d9c8c5db --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/keepassx @@ -0,0 +1,70 @@ +#!/bin/sh + +set -e +set -u + +. gettext.sh +TEXTDOMAIN="tails" +export TEXTDOMAIN + +PERSISTENT_DATA_DIR="${HOME}/Persistent" +OLD_DB="${PERSISTENT_DATA_DIR}/keepassx.kdb" +MIGRATED_DB="${PERSISTENT_DATA_DIR}/New database.kdbx" +NEW_DB="${PERSISTENT_DATA_DIR}/keepassx.kdbx" + +prompt_for_database_renaming() { + local filename="${1}" + local dialog_msg="`eval_gettext \"Do you want to rename your KeePassX database? + +You have a KeePassX database in your Persistent folder: + +\\\${filename} + +Renaming it to keepassx.kdbx would allow KeePassX to open it automatically in the future.\"` +" + local rename="`gettext \"Rename\"`" + local open="`gettext \"Keep current name\"`" + zenity --question --title "" --text "${dialog_msg}" --default-cancel \ + --ok-label "${rename}" --cancel-label "${open}" +} + +# There's a migrated DB named 'New database' => rename it before opening it: +if mountpoint -q "$PERSISTENT_DATA_DIR" && \ + [ -e "$MIGRATED_DB" ] && ! [ -e "$NEW_DB" ]; then + mv "$MIGRATED_DB" "$NEW_DB" + exec /usr/bin/keepassx "$NEW_DB" + +# New database file is not named keepassx.kdbx, prompt for renaming it. +elif mountpoint -q "$PERSISTENT_DATA_DIR" && \ + ! [ -e "${NEW_DB}" ] && \ + [ "$(find "$PERSISTENT_DATA_DIR" -maxdepth 1 -name '*.kdbx' 2>/dev/null | wc -l)" = "1" ]; then + user_db="$(find "$PERSISTENT_DATA_DIR" -maxdepth 1 -name '*.kdbx' 2>/dev/null)" + if ! [ -e "${PERSISTENT_DATA_DIR}/.no_keepassx_db_renaming" ] \ + && prompt_for_database_renaming "${user_db}"; then + mv "${user_db}" "${NEW_DB}" + exec /usr/bin/keepassx "${NEW_DB}" + else + touch "${PERSISTENT_DATA_DIR}/.no_keepassx_db_renaming" + exec /usr/bin/keepassx + fi + +# There's an old DB but no new one => import the old DB: +elif mountpoint -q "$PERSISTENT_DATA_DIR" \ + && ! [ -e "$NEW_DB" ] \ + && [ -e "$OLD_DB" ]; then + + # Ensure $PERSISTENT_DATA_DIR is pre-selected for saving + # the migrated database + cd "$PERSISTENT_DATA_DIR" + + # Trigger the migration from the old KeePassX database to the new format + # used in KeePassX 2.0.x. + /usr/bin/keepassx "$OLD_DB" + + # Avoid the user being prompted to open the old DB on next run. + mv "$OLD_DB" "${OLD_DB}.bak" + +# Default case: +else + exec /usr/bin/keepassx "$@" +fi diff --git a/config/chroot_local-includes/usr/local/bin/lc.py b/config/chroot_local-includes/usr/local/bin/lc.py new file mode 100755 index 0000000000000000000000000000000000000000..5a817927996edc2d348690d950f08da29beebc7c --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/lc.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 + +# The MIT License +# +# Copyright (c) 2011 Christopher Pound +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# lc.py -- language confluxer (http://www.ruf.rice.edu/~pound/lc.py) +# +# - Written by Christopher Pound (pound@rice.edu), July 1993. +# - Loren Miller suggested I make sure lc starts by picking a +# letter pair that was at the beginning of a data word, Oct 95. +# - Cleaned it up a little bit, March 95; more, September 01 +# - Python version, Jul 09 +# +# The datafile should be a bunch of words from some language +# with minimal punctuation or garbage (# starts a comment). + +from optparse import OptionParser +import random +import re +import sys + +class Pseudolanguage: + + def __init__(self, **dict): + """Set up a new pseudolanguage""" + dict.setdefault('name', '') + self.name = dict['name'] + self.parsed = False + self.data = {} + self.inits = {} + self.pairs = {} + + def incorporate(self, files): + """Load list of files for this pseudolanguage into self.data""" + self.parsed = False + for f in files: + words = [] + with open(f) as text: + for line in text: + line = line.strip() + line = re.sub(r"#.*", "", line) + words.extend(re.split(r"\s+", line)) + self.data[f] = words + + def delete(self, files): + """Delete a list of languages from self.data""" + self.parsed = False + for f in files: + del self.data[f] + + def parse(self): + """Parse pseudolanguage's data into self.inits and self.pairs""" + if not self.parsed: + self.inits.clear() + self.pairs.clear() + for f in self.data: + for word in self.data[f]: + word += ' ' + if len(word) > 3: + if word[0:2] in self.inits: + self.inits[word[0:2]].append(word[2:3]) + else: + self.inits[word[0:2]] = [word[2:3]] + pos = 0 + while pos < len(word)-2: + if word[pos:pos+2] in self.pairs: + self.pairs[word[pos:pos+2]].append(word[pos+2]) + else: + self.pairs[word[pos:pos+2]] = [word[pos+2]] + pos = pos + 1 + self.parsed = True + + def dump(self): + """Print the current parsed data; use pickle for inflatable dumps""" + self.parse() + print('name = """', self.name, '"""') + print("dump = { 'inits': ", self.inits, ",") + print("'pairs': ", self.pairs, " }") + + def generate(self, number, min, max): + """Generate list of words of min and max lengths""" + self.parse() + wordlist = [] + while len(wordlist) < number: + word = random.choice(list(self.inits.keys())) + while word.find(' ') == -1: + word += random.choice(self.pairs[word[-2:]]) + word = word.strip() + if len(word) >= min and len(word) <= max: + wordlist.append(word) + return wordlist + +if __name__ == '__main__': + + usage = "usage: %prog [options] datafile1 [datafile2 ...]" + parser = OptionParser(usage=usage, version="%prog 1.0") + parser.add_option("-d", "--dump", action="store_true", + dest="dump", default=False, + help="Dump internal representation of the pseudolanguage") + parser.add_option("-g", "--generate", type="int", dest="num", + help="Generate specified number of words") + parser.add_option("--min", type="int", dest="min", default=3, + help="Set the minimum length of each word") + parser.add_option("--max", type="int", dest="max", default=9, + help="Set the maximum length of each word") + parser.add_option("--name", dest="name", default=' ', + help="Set the name of the pseudolanguage") + (options, args) = parser.parse_args() + + aLanguage = Pseudolanguage(name=options.name) + aLanguage.incorporate(args) + if options.dump: + aLanguage.dump() + else: + results = aLanguage.generate(options.num, options.min, options.max) + for word in results: + print(word) diff --git a/config/chroot_local-includes/usr/local/bin/pidgin b/config/chroot_local-includes/usr/local/bin/pidgin new file mode 100755 index 0000000000000000000000000000000000000000..580632a130756e7e22dfcedbbde2ca9ffe7a975f --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/pidgin @@ -0,0 +1,5 @@ +#!/bin/sh + +# Start Pidgin with the GNOME integration disabled, so that the +# "Global proxy configuration" is used, which we set to use Tor +exec env GNOME_DESKTOP_SESSION_ID="" /usr/bin/pidgin "${@}" diff --git a/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo b/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo new file mode 100755 index 0000000000000000000000000000000000000000..33e7142cccbe0af1d7d91dec0412b96f2e90ecee --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# In Tails, the administration password doesn't work with 'su'. New +# users in particular may be puzzled by the authentication failures +# while trying to 'su' using administration password. +# +# This script is called by '/etc/bash.bashrc.d/replace-su-with-sudo.sh'. +# It checks if the current user's password is set or not using +# 'is_password_set()' function from 'adminpassword.py' library. If the +# password is set, the user is asked to use 'sudo' instead of 'su'. +# Otherwise, the user is asked to first set the administration password. +# +# https://redmine.tails.boum.org/code/issues/15583 + +import gettext +import sys +from tailslib.adminpassword import is_password_set + +def main() -> None: + if is_password_set(): + print(_('su is disabled. Please use sudo instead.')) + sys.exit(0) + else: + print(open("/usr/share/tails-greeter/no-password-lecture.txt").read()) + sys.exit(1) + +if __name__ == "__main__": + # Initialize translations + translation = gettext.translation("tails", fallback=True) + _ = translation.gettext + + main() diff --git a/config/chroot_local-includes/usr/local/bin/tails-about b/config/chroot_local-includes/usr/local/bin/tails-about new file mode 100755 index 0000000000000000000000000000000000000000..173b0f47b89c0613c944e7e49e4a6c0f02469684 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-about @@ -0,0 +1,57 @@ +#!/usr/bin/python3 +# -*- encoding: UTF-8 +"""This scripts show a dialog with basic information about the +running Tails installation. +""" + +import gettext +import subprocess + +from gi import require_version +require_version('Gtk', '3.0') +from gi.repository import GLib, Gtk, GdkPixbuf + + +class AboutTails(Gtk.AboutDialog): + """A simple class showing the dialog""" + def __init__(self): + gettext.install("tails") + self.get_tails_version() + Gtk.AboutDialog.__init__(self) + + self.set_program_name(_("Tails")) + + headerbar = Gtk.HeaderBar() + headerbar.set_title(_("About Tails")) + headerbar.set_show_close_button(True) + self.set_titlebar(headerbar) + + try: + self.set_logo(GdkPixbuf.Pixbuf.new_from_file_at_size( + '/usr/share/tails/tails-logo-flat-inverted.svg', 400, 200)) + except GLib.GError: + pass + + self.set_comments(_("The Amnesic Incognito Live System") + "\n\n" + + _("Build information:\n%s") % self.tails_version) + self.set_copyright("Tails developers") + self.set_version(self.tails_main_version) + self.set_website("https://tails.boum.org/") + + self.connect("delete-event", Gtk.main_quit) + self.connect("response", Gtk.main_quit) + self.show_all() + Gtk.main() + + def get_tails_version(self): + """Find out the tails_version and the tails_main_version""" + try: + self.tails_version = subprocess.Popen( + ["tails-version"], stdout=subprocess.PIPE).communicate()[0] + self.tails_version = self.tails_version.decode('utf-8') + self.tails_main_version = self.tails_version.split("-")[0] + except OSError: + self.tails_version = _("not available") + self.tails_main_version = "" + +AboutTails() diff --git a/config/chroot_local-includes/usr/local/bin/tails-additional-software-config b/config/chroot_local-includes/usr/local/bin/tails-additional-software-config new file mode 100755 index 0000000000000000000000000000000000000000..41e003167379b4cb43669f7144df4db67cd46809 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-additional-software-config @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 + +"""User interface to configure Tails Additional Software.""" + +import gettext +import os +import subprocess +import sys + +import apt.cache +import gi + +from gi.repository import Gio # NOQA: E402 +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk # NOQA: E402 + +from tailslib.persistence import ( # NOQA: E402 + has_unlocked_persistence, + has_persistence, + is_tails_media_writable, + launch_persistence_setup) + +from tailslib.additionalsoftware import ( # NOQA: E402 + get_additional_packages, + get_packages_list_path, + filter_package_details) + +_ = gettext.gettext + +UI_FILE = "/usr/share/tails/additional-software/configuration-window.ui" + + +class ASPConfigApplicationWindow(Gtk.ApplicationWindow): + def __init__(self, application, get_config_func, remove_asp_func): + Gtk.ApplicationWindow.__init__(self, application=application) + + self.get_config_func = get_config_func + self.remove_asp_func = remove_asp_func + + self.connect("show", self.cb_window_show) + + builder = Gtk.Builder.new_from_file(UI_FILE) + builder.set_translation_domain("tails") + builder.connect_signals(self) + + self.listbox = builder.get_object("listbox") + self.no_package_page = builder.get_object("no_package_page") + self.package_list_page = builder.get_object("package_list_page") + self.stack = builder.get_object("stack") + self.install_label = builder.get_object("install_label") + self.persistence_button = builder.get_object("persistence_button") + + self.listbox.set_header_func(self._listbox_update_header_func, None) + + self.set_default_size(width=500, height=-1) + self.set_icon_name("package-x-generic") + self.set_titlebar(builder.get_object("headerbar")) + self.add(builder.get_object("main_box")) + + @staticmethod + def _listbox_update_header_func(row, before, user_data): + if not before: + row.set_header(None) + return + + current = row.get_header() + if not current: + current = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL) + current.show() + row.set_header(current) + + def __show_exception_dialog(self, explanation, exception): + dialog = Gtk.MessageDialog( + self, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.OK, + explanation) + dialog.format_secondary_text(str(exception)) + dialog.run() + dialog.destroy() + + def cb_activate_link(self, label, uri): + if uri.endswith(".desktop"): + appinfo = Gio.DesktopAppInfo.new(uri) + appinfo.launch() + return True + + def cb_listboxrow_remove_button_clicked(self, button, package_name): + dialog = Gtk.MessageDialog( + self, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.QUESTION, + Gtk.ButtonsType.NONE, + # Translators: Don't translate {package}, it's a placeholder and will be replaced. + _("Remove {package} from your additional software? " + "This will stop installing the package " + "automatically.").format(package=package_name)) + dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT) + dialog.add_button(Gtk.STOCK_REMOVE, Gtk.ResponseType.ACCEPT) + if dialog.run() == Gtk.ResponseType.ACCEPT: + try: + self.remove_asp_func(package_name) + except subprocess.CalledProcessError as e: + self.__show_exception_dialog( + # Translators: Don't translate {pkg}, it's a placeholder and will be replaced. + _("Failed to remove {pkg}").format(pkg=package_name), + e) + dialog.destroy() + + def cb_persistence_button_clicked(self, button, data=None): + launch_persistence_setup("--force-enable-preset", "AdditionalSoftware") + self.update_packages_list() + return True + + def cb_window_show(self, window): + self.update_packages_list() + + def update_packages_list(self): + try: + packages = self.get_config_func() + except Exception as e: + self.__show_exception_dialog( + _("Failed to read additional software configuration"), + e) + self.hide() + return + self.persistence_button.set_visible(False) + if packages: + self.listbox.foreach(lambda widget, data: widget.destroy(), None) + for package_name, package_description in packages: + listboxrow = Gtk.ListBoxRow.new() + + hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) + hbox.set_border_width(3) + + vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) + name_label = Gtk.Label.new("{}".format(package_name)) + name_label.set_use_markup(True) + name_label.set_xalign(0) + vbox.pack_start(name_label, expand=True, fill=True, padding=0) + description_label = Gtk.Label.new(package_description) + description_label.set_xalign(0) + vbox.pack_start( + description_label, expand=True, fill=True, padding=0) + hbox.pack_start(vbox, expand=True, fill=True, padding=12) + + remove_button = Gtk.Button.new_from_icon_name( + "window-close-symbolic", + Gtk.IconSize.SMALL_TOOLBAR) + remove_button.set_relief(Gtk.ReliefStyle.NONE) + remove_button.set_tooltip_text( + # Translators: Don't translate {package}, it's a placeholder and will be replaced. + _("Stop installing {package} " + "automatically").format(package=package_name)) + remove_button.get_accessible().set_name(_("Remove")) + remove_button.connect( + "clicked", self.cb_listboxrow_remove_button_clicked, + package_name) + hbox.pack_end( + remove_button, expand=False, fill=False, padding=0) + + listboxrow.add(hbox) + self.listbox.add(listboxrow) + # Add empty listboxrow to finish the list with a separator + listboxrow = Gtk.ListBoxRow.new() + listboxrow.set_selectable(False) + self.listbox.add(listboxrow) + + self.listbox.show_all() + self.stack.set_visible_child(self.package_list_page) + self.install_label.set_markup( + _('To add more, install some software using ' + 'Synaptic Package Manager ' + 'or APT on the ' + 'command line.')) + else: + self.stack.set_visible_child(self.no_package_page) + self.install_label.set_markup( + _('To do so, install some software using ' + 'Synaptic Package Manager ' + 'or APT on the ' + 'command line.')) + if has_unlocked_persistence(search_new_persistence=True): + # The label from the UI file is good unmodified + pass + elif has_persistence(): + self.install_label.set_markup( + _('To do so, unlock your persistent storage ' + 'when starting Tails and ' + 'install some software using ' + 'Synaptic Package ' + 'Manager or ' + 'APT on the ' + 'command line.')) + elif is_tails_media_writable(): + self.persistence_button.set_visible(True) + self.install_label.set_markup( + _('To do so, create a persistent storage and install some ' + 'software using ' + 'Synaptic Package ' + 'Manager or ' + 'APT on the ' + 'command line.')) + else: # It's impossible to have a persistent storage + self.install_label.set_markup( + _('To do so, install Tails on a USB stick using ' + 'Tails Installer ' + 'and create a persistent storage.')) + + +class ASPConfigApplication(Gtk.Application): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + application_id="org.boum.tails.additional-software-config", + **kwargs) + + def do_activate(self): + self.window.present() + + def do_startup(self): + Gtk.Application.do_startup(self) + gettext.install("tails") + self.window = ASPConfigApplicationWindow( + application=self, + get_config_func=self.get_asp_configuration, + remove_asp_func=self.remove_additional_software) + + packages_list_file = Gio.File.new_for_path( + get_packages_list_path(search_new_persistence=True, + return_nonexistent=True)) + self.packages_list_monitor = packages_list_file.monitor( + Gio.FileMonitorFlags.NONE, None) + self.packages_list_monitor.connect( + "changed", self.cb_packages_list_changed) + + def cb_packages_list_changed(self, file_monitor, file, other_file, + event_type): + if os.access(file.get_path(), os.R_OK): + self.window.update_packages_list() + + def get_asp_configuration(self): + additional_packages = get_additional_packages( + search_new_persistence=True) + apt_cache = apt.cache.Cache() + + packages_with_description = [] + for package in sorted(additional_packages): + package_name = filter_package_details(package) + try: + apt_package = apt_cache[package_name] + except KeyError: + summary = _("[package not available]") + else: + if apt_package.installed: + summary = apt_package.installed.summary + else: + summary = apt_package.candidate.summary + packages_with_description.append((package, summary)) + + return packages_with_description + + def remove_additional_software(self, package_name): + subprocess.run(["pkexec", + "/usr/local/sbin/tails-additional-software-remove", + package_name], + check=True) + + +asp_application = ASPConfigApplication() +exit_status = asp_application.run(sys.argv) +sys.exit(exit_status) diff --git a/config/chroot_local-includes/usr/local/bin/tails-delete-persistent-volume b/config/chroot_local-includes/usr/local/bin/tails-delete-persistent-volume new file mode 100755 index 0000000000000000000000000000000000000000..1da2f5992d699146c0e20fb9f57800fdbdc84a8e --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-delete-persistent-volume @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +RUN_AS_USER=tails-persistence-setup + +cd / +xhost +SI:localuser:"$RUN_AS_USER" +sudo -u "$RUN_AS_USER" /usr/bin/tails-persistence-setup --step delete $@ +xhost -SI:localuser:"$RUN_AS_USER" diff --git a/config/chroot_local-includes/usr/local/bin/tails-documentation b/config/chroot_local-includes/usr/local/bin/tails-documentation new file mode 100755 index 0000000000000000000000000000000000000000..c65c6100af131f5e3b52a9346421aa0b471a7862 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-documentation @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import os +import os.path +import sys + +# Main + +try: + page = sys.argv[1] +except IndexError: + page = 'doc' + +try: + anchor = sys.argv[2] +except IndexError: + anchor = None + +tails_homepage = 'https://tails.boum.org' +wiki_path = '/usr/share/doc/tails/website' +lang_code = os.getenv('LANG', 'en')[0:2] + +# If possible, let's hand-off to our website, which should be the most +# up-to-date option. +if os.system('/usr/local/sbin/tor-has-bootstrapped') == 0: + if os.path.isfile(os.path.join( + wiki_path, page + '.' + lang_code + ".html")): + uri = tails_homepage + '/' + page + '/index.' + lang_code + '.html' + else: + uri = tails_homepage + '/' + page +else: + trials = [ + os.path.join(wiki_path, page + code + ".html") + for code in ['.' + lang_code, '.en', ''] + ] + try: + uri = 'file://' + next( + trial for trial in trials if os.path.isfile(trial) + ) + except StopIteration: + sys.exit('error: could not find the requested documentation page') + +if anchor is not None: + uri = uri + '#' + anchor + +os.environ['TOR_BROWSER_SKIP_OFFLINE_WARNING'] = 'yes' +os.execv('/usr/local/bin/tor-browser', + ['/usr/local/bin/tor-browser', '--new-tab', uri]) diff --git a/config/chroot_local-includes/usr/local/bin/tails-get-bootinfo b/config/chroot_local-includes/usr/local/bin/tails-get-bootinfo new file mode 100755 index 0000000000000000000000000000000000000000..a104b85a92b5b4198ee33a0ed8586c9d74b9b702 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-get-bootinfo @@ -0,0 +1,57 @@ +#! /usr/bin/env python3 +""" +Get Tails boot info. + +Test with "python3 tails-get-bootinfo.py doctest". + +goodcrypto.com converted from bash to python and added basic tests. + +>>> import sh +>>> sh.Command(sys.argv[0])('kernel') +/lib/live/mount/medium/live/vmlinuz +>>> sh.Command(sys.argv[0])('initrd') +/lib/live/mount/medium/live/initrd.img +>>> sh.Command(sys.argv[0])(_ok_code=(1)) +Usage: tails-get-bootinfo kernel|initrd + +""" + +import sys + +LIVE_IMAGE_MOUNTPOINT = '/lib/live/mount/medium' + + +def main(*args): + kernel = None + initrd = None + + with open('/proc/cmdline') as f: + kernel_params = f.read().split() + for param in kernel_params: + if param.startswith('BOOT_IMAGE='): + kernel = param[len('BOOT_IMAGE='):] + elif param.startswith('initrd='): + initrd = param[len('initrd='):] + + if not kernel or not initrd: + print('Failed to parse /proc/cmdline', file=sys.stderr) + sys.exit(1) + + if 'kernel' in args: + print(LIVE_IMAGE_MOUNTPOINT + kernel, end="") + elif 'initrd' in args: + print(LIVE_IMAGE_MOUNTPOINT + initrd, end="") + else: + print('Usage: tails-get-bootinfo kernel|initrd', file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == 'doctest': + import doctest + doctest.testmod() + elif len(sys.argv) == 2: + main(*sys.argv[1:]) + else: + print('Usage: tails-get-bootinfo kernel|initrd', file=sys.stderr) + sys.exit(1) diff --git a/config/chroot_local-includes/usr/local/bin/tails-persistence-setup b/config/chroot_local-includes/usr/local/bin/tails-persistence-setup new file mode 100755 index 0000000000000000000000000000000000000000..22777cada09cc44c5bc8c878b1a60d005ca2163b --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-persistence-setup @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +RUN_AS_USER=tails-persistence-setup + +cd / +xhost +SI:localuser:"$RUN_AS_USER" +sudo -u "$RUN_AS_USER" /usr/bin/tails-persistence-setup $@ +xhost -SI:localuser:"$RUN_AS_USER" diff --git a/config/chroot_local-includes/usr/local/bin/tails-screen-locker b/config/chroot_local-includes/usr/local/bin/tails-screen-locker new file mode 100755 index 0000000000000000000000000000000000000000..42f7aadaa003d014cc451ee42591d660f25cb900 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-screen-locker @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +import logging +import socket +import sys +import gettext +import subprocess +from pydbus import SessionBus, SystemBus +import os +from pam import pam +import time +import pwd + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GLib +gi.require_version('Gdk', '3.0') +from gi.repository import Gdk + +from tailslib.adminpassword import is_password_set + +_ = gettext.gettext +gettext.textdomain("tails") + +logging.basicConfig(level=logging.DEBUG) + +mainloop = GLib.MainLoop() + + +def lock_screen(): + # org.gnome.ScreenSaver.Lock() sometimes does not return, so we set a timeout of 5 seconds + try: + SessionBus().get("org.gnome.ScreenSaver").Lock(timeout=5) + except Exception as e: + logging.exception(e) + finally: + sys.exit() + + +class PasswordDialog(object): + + def on_cancel_clicked(self, button, data=None): + sys.exit(1) + + def on_entry_changed(self, entry, data=None): + if not self.entry1.get_text() or not self.entry2.get_text(): + self.ok_button.set_sensitive(False) + elif self.entry1.get_text() == self.entry2.get_text(): + # Passwords match + self.ok_button.set_sensitive(True) + self.entry2.set_icon_from_icon_name(1, None) + else: + # Passwords don't match + self.ok_button.set_sensitive(False) + self.entry2.set_icon_from_stock(1, "gtk-dialog-warning") + + def on_ok_clicked(self, button, data=None): + pw1 = self.entry1.get_text() + pw2 = self.entry2.get_text() + if not pw1 == pw2: + return + + self.pw = pw1.encode('utf8') + + bus = SystemBus() + object_path = bus.get("org.freedesktop.Accounts").FindUserById(os.getuid()) + user_object = bus.get("org.freedesktop.Accounts", object_path) + # lock the screen once the 'Changed' signal was received + user_object.Changed.connect(self.wait_until_password_set_and_lock_screen) + + p = subprocess.Popen("passwd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p.stdin.write(self.pw + b"\n") + p.stdin.write(self.pw) + p.stdin.flush() + out, err = p.communicate() + if p.returncode != 0: + print("passwd stdout: %s" % out) + print("passwd stderr: %s" % err) + raise RuntimeError("passwd returned %r" % p.returncode) + + # We close the window here for the case that lock_screen does not return immediately, + # otherwise it would look like the app is unresponsive + self.window.close() + + def on_key_pressed(self, widget, event): + if Gdk.keyval_name(event.keyval) == "Escape": + sys.exit(1) + + if self.ok_button.get_sensitive() and Gdk.keyval_name(event.keyval) == "Return": + self.ok_button.clicked() + + def wait_until_password_set_and_lock_screen(self): + # TODO: Remove this once this is fixed: https://bugzilla.gnome.org/show_bug.cgi?id=761969 + p = pam() + while not p.authenticate(pwd.getpwuid(os.getuid()).pw_name, self.pw): + logging.debug("PAM not updated yet...") + time.sleep(0.01) + # We close the window here for the case that lock_screen does not return immediately, + # otherwise it would look like the app is unresponsive + self.window.close() + GLib.idle_add(lock_screen) + + def run(self): + self.window.show() + + def __init__(self): + self.pw = None + + self.ok_button = Gtk.Button( + label=_("Lock Screen"), + receives_default=True, + sensitive=False, + width_request=86 + ) + self.ok_button.connect("clicked", self.on_ok_clicked) + self.ok_button.get_style_context().add_class('suggested-action') + + cancel_button = Gtk.Button( + label=_("Cancel"), + width_request=86 + ) + cancel_button.connect("clicked", self.on_cancel_clicked) + + headerbar = Gtk.HeaderBar( + title=_("Screen Locker"), + ) + headerbar.pack_start(cancel_button) + headerbar.pack_end(self.ok_button) + + label_subtitle = Gtk.Label( + label=_("Set up a password to unlock the screen."), + ) + + self.entry1 = Gtk.Entry( + can_focus=True, + visibility=False, + width_request=200 + ) + self.entry1.connect("changed", self.on_entry_changed) + + self.entry2 = Gtk.Entry( + can_focus=True, + visibility=False, + width_request=200 + ) + self.entry2.connect("changed", self.on_entry_changed) + + grid = Gtk.Grid(row_spacing=2, column_spacing=10) + grid.attach(Gtk.Label(label=_("Password"), xalign=1), 0, 0, 1, 1) + grid.attach(Gtk.Label(label=_("Confirm"), xalign=1), 0, 1, 1, 1) + grid.attach(self.entry1, 1, 0, 1, 1) + grid.attach(self.entry2, 1, 1, 1, 1) + + content_box = Gtk.Box(Gtk.Orientation.HORIZONTAL) + content_box.pack_start(Gtk.Box(hexpand=True), False, False, 0) + content_box.pack_end(Gtk.Box(hexpand=True), False, False, 0) + content_box.add(grid) + + box = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, + margin_top=18, + margin_bottom=18, + margin_left=18, + margin_right=18, + spacing=18 + ) + box.add(label_subtitle) + box.add(content_box) + + self.window = Gtk.Window( + type_hint=Gdk.WindowTypeHint.DIALOG, + ) + self.window.connect("key-press-event", self.on_key_pressed) + self.window.set_titlebar(headerbar) + self.window.add(box) + self.window.show_all() + + +def get_lock(): + # Source: https://stackoverflow.com/a/7758075 + # Original author: https://stackoverflow.com/users/639295/aychedee + # Without holding a reference to our socket somewhere it gets garbage + # collected when the function exits + get_lock._lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + get_lock._lock_socket.bind('\0' + 'tails-screen-locker') + + +def main(): + get_lock() + if is_password_set(): + lock_screen() + return + + dialog = PasswordDialog() + GLib.idle_add(dialog.run) + mainloop.run() + + +if __name__ == "__main__": + main() diff --git a/config/chroot_local-includes/usr/local/bin/tails-security-check b/config/chroot_local-includes/usr/local/bin/tails-security-check new file mode 100755 index 0000000000000000000000000000000000000000..ce86ee17e4628b950e2a61a4e7df737d71c3780b --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-security-check @@ -0,0 +1,202 @@ +#! /usr/bin/perl + +use strict; +use warnings FATAL => 'all'; +use 5.10.1; + +#man{{{ + +=head1 NAME + +tails-security-check + +=cut + + +=head1 DESCRIPTION + +=head1 SYNOPSIS + +tails-security-check [ ATOM_FEED_BASE_URL ] + + ATOM_FEED_BASE_URL will be appended /index.XX.atom, + for XX in (current locale's language code, 'en'), + until success is reported by the HTTP layer. + +=head1 AUTHOR + +Tails developers +See https://tails.boum.org/. + +=cut + +#}}} + +use Carp; +use Carp::Assert::More; +use Fatal qw{open close}; +use Locale::gettext; +use POSIX; +use Tails::Download::HTTPS; +use Try::Tiny; +use XML::Atom; +use XML::Atom::Feed; + +setlocale(LC_MESSAGES, ""); +textdomain("tails"); + +### configuration + +my $default_base_url = 'https://tails.boum.org/security/'; + +=head1 FUNCTIONS + +=head2 current_lang + +Returns the two-letters language code of the current session. + +=cut +sub current_lang { + my ($code) = ($ENV{LANG} =~ m/([a-z]{2}).*/); + + return $code; +} + +=head2 atom_str + +Argument: an Atom feed URL + +Returns the Atom's feed content on success, undef on failure. + +=cut +sub atom_str { + my $url = shift; + assert_defined($url); + + my $downloader = Tails::Download::HTTPS->new( + max_download_size => 256 * 2**10, + ); + my $content; + try { $content = $downloader->get_url($url); }; + defined $content ? return $content : return undef; +} + +=head2 get_entries + +Arguments: the Atom feed URL. + +Returns the list of XML::Atom::Entry objects from the feed. + +We use this manual Accept-Language algorithm as the website +layout does not allow us to use content negotiation. + +=cut +sub get_entries { + my $base_url = shift; + assert_defined($base_url); + assert_nonblank($base_url); + + my $separator = ''; + $separator = '/' unless $base_url =~ m{/\z}xms; + + my @try_urls = ( + $base_url . $separator . 'index.' . current_lang() . '.atom', + $base_url . $separator . 'index.en.atom', + ); + + my $feed_str; + foreach my $url (@try_urls) { + last if ($feed_str = atom_str($url)); + } + assert_defined($feed_str); + + return XML::Atom::Feed->new(\$feed_str)->entries(); +} + +=head2 notify_user + +Notify the user about the Atom entries passed as arguments. + +=cut +sub notify_user { + my @entries = @_; + + my $body = gettext('This version of Tails has known security issues:') . "\n"; + + for (@entries) { + $body .= '• ' . '' . $_->title . '' . "\n"; + } + + say $body; + + exec( + qw{/usr/bin/zenity --warning}, + q{--title}, gettext('Known security issues'), + q{--text}, $body, + ); +} + +=head2 categories + +Return the list of categories of the input XML::Atom::Entry object. + +=cut +sub categories { + my $entry = shift; + my $ns = XML::Atom::Namespace->new( + dc => 'http://purl.org/dc/elements/1.1/' + ); + my @category = ($entry->can('categories')) + ? $entry->categories + : $entry->category; + @category + ? (map { $_->label || $_->term } @category) + : $entry->getlist($ns, 'subject'); +} + +=head2 is_not_fixed + +Returns true iff. the input XML::Atom::Entry object hasn't the +security/fixed tag. + +=cut +sub is_not_fixed { + my $entry = shift; + assert_isa($entry, 'XML::Atom::Entry'); + + ! grep { $_ eq 'security/fixed' } categories($entry); +} + +=head2 unfixed_entries + +Filter the input list of XML::Atom::Entry objects to only keep entries +that are not marked as fixed yet. + +=cut +sub unfixed_entries { + my @entries = @_; + + grep { is_not_fixed($_) } @entries; +} + + +=head1 MAIN + +=head2 parse command line args + +=cut +my $base_url = shift || $default_base_url; +my $opt_since = shift; + + +=head2 do the work + +=cut +my @unfixed_entries = unfixed_entries(get_entries($base_url)); + +if (! @unfixed_entries) { + exit 0; +} +else { + notify_user(@unfixed_entries); +} diff --git a/config/chroot_local-includes/usr/local/bin/tails-upgrade-frontend-wrapper b/config/chroot_local-includes/usr/local/bin/tails-upgrade-frontend-wrapper new file mode 100755 index 0000000000000000000000000000000000000000..e85bf6f5699a993d0bae3fd09712fe3d9bd85402 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-upgrade-frontend-wrapper @@ -0,0 +1,106 @@ +#! /usr/bin/env python3 +""" +Tails upgrade frontend wrapper. + +Test with "python3 tails-upgrade-frontend-wrapper.py doctest". +The tests will start the upgrade process which could pop up a dialog box +so you probably want to use a tester that handles user interaction or +run the tests from the command line and answer prompts as needed. + +goodcrypto.com converted from bash to python and added basic tests. + +>>> # run this script (without waiting 30 seconds) +>>> sh.Command(sys.argv[0])("--no-wait") + +""" + +import os +import sys +import time +from gettext import gettext + +import sh +import psutil + +os.environ['PATH'] = '/usr/local/bin:/usr/bin:/bin' +os.environ['TEXTDOMAIN'] = 'tails' + +CMD = os.path.basename(sys.argv[0]) +TORDATE_DIR = '/run/tordate' +TORDATE_DONE_FILE = '{}/done'.format(TORDATE_DIR) +INOTIFY_TIMEOUT = 60 +MIN_AVAILABLE_MEMORY = (300 * 1024 * 1024) # In Bytes +RUN_AS_USER = 'tails-upgrade-frontend' + +ERROR_MESSAGE = gettext('''\"Not enough memory available to check for upgrades. + +Make sure this system satisfies the requirements for running Tails. +See file:///usr/share/doc/tails/website/doc/about/requirements.en.html + +Try to restart Tails to check for upgrades again. + +Or do a manual upgrade. +See https://tails.boum.org/doc/first_steps/upgrade#manual\"''') + + +def main(*args): + if "--no-wait" not in args: + time.sleep(30) + else: + args = (arg for arg in args if arg != "--no-wait") + + check_free_memory(MIN_AVAILABLE_MEMORY) + + # Go to a place where everyone, especially Archive::Tar::Wrapper called by + # tails-install-iuk, can chdir back after it has chdir'd elsewhere to do + # its job. + os.chdir('/') + + os.execv( + "/bin/sh", + ( + "/bin/sh", "-c", + "xhost +SI:localuser:{user};" + "sudo -u {user} /usr/bin/tails-upgrade-frontend {args};" + "xhost -SI:localuser:{user}".format(user=RUN_AS_USER, args=" ".join(args)) + ) + ) + + +def error(msg): + """Show error and exit.""" + cli_text = '{}: {} {}'.format(CMD, gettext('error:'), msg) + dialog_text = '''{}\n\n{}'''.format(gettext('Error'), msg) + print(cli_text, file=sys.stderr) + + sh.zenity('--error', '--title', "", '--text', dialog_text, _ok_code=[0,1,5]) + sys.exit(1) + + +def check_free_memory(min_available_memory): + """Check for enough free memory. + + # 1 KiB should be available when running the doctest + >>> check_free_memory(1024) + # 1 TiB should not be available, an error prompt should be displayed + >>> try: + ... check_free_memory(1024*1024*1024*1024) + ... fail() + ... except SystemExit: + ... pass + """ + + available_memory = psutil.virtual_memory().available + + if available_memory < min_available_memory: + print('Only {} Bytes memory available, while {} is needed'.format( + available_memory, min_available_memory), file=sys.stderr) + error(ERROR_MESSAGE) + + +if __name__ == '__main__': + if len(sys.argv) > 1 and sys.argv[1] == 'doctest': + import doctest + doctest.testmod() + else: + main(*sys.argv[1:]) diff --git a/config/chroot_local-includes/usr/local/bin/tails-version b/config/chroot_local-includes/usr/local/bin/tails-version new file mode 100755 index 0000000000000000000000000000000000000000..1c4efd05d0856a123cefa4f069df779cc4e027de --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tails-version @@ -0,0 +1,3 @@ +#!/bin/sh + +cat /etc/amnesia/version diff --git a/config/chroot_local-includes/usr/local/bin/thunderbird b/config/chroot_local-includes/usr/local/bin/thunderbird new file mode 100755 index 0000000000000000000000000000000000000000..454ef58644763bcb4cfaec020cda5e368979424d --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/thunderbird @@ -0,0 +1,89 @@ +#!/bin/sh + +set -e +set -u +set -x + +# Import set_mozilla_pref() +. /usr/local/lib/tails-shell-library/tor-browser.sh + +THUNDERBIRD_CONFIG_DIR="${HOME}/.thunderbird" +PROFILE="${THUNDERBIRD_CONFIG_DIR}/profile.default" + +thunderbird_config_is_persistent() { + [ "$(findmnt --noheadings --output SOURCE --target "${THUNDERBIRD_CONFIG_DIR}")" = "/dev/mapper/TailsData_unlocked[/thunderbird]" ] +} + +configure_locale() { + # Thunderbird will set the locale based on the environment when + # this pref is empty, but will then save the result to this pref + # disabling this "guess" for the next time. We want Thunderbird to + # always match the locale of the Tails session. + set_mozilla_pref "${PROFILE}/prefs.js" \ + "intl.locale.requested" \ + '""' \ + user_pref +} + +disable_autocrypt() { + # Disable Autocrypt since it is not safe (#15923). + set_mozilla_pref "${PROFILE}/prefs.js" \ + "mail.server.default.enableAutocrypt" \ + "false" \ + user_pref +} + +configure_default_incoming_protocol() { + # For extensions.torbirdy.defaultprotocol, POP = 0, IMAP = 1 + local default_protocol + if thunderbird_config_is_persistent; then + default_protocol=0 + else + default_protocol=1 + fi + set_mozilla_pref "${PROFILE}/prefs.js" \ + "extensions.torbirdy.defaultprotocol" \ + "${default_protocol}" \ + user_pref +} + +reconfigure_profile() { + mkdir -p "${PROFILE}" + configure_locale + disable_autocrypt + configure_default_incoming_protocol + + # Suppress Enigmail's configuration wizard by pretending that the current + # version was already configured. Only do this on first run though: + # once we've done this we let Enigmail manage this setting itself + # so it can run any migration code it wants to on upgrades. + if thunderbird_profile_is_new; then + initialize_enigmail_configured_version + fi +} + +thunderbird_profile_is_new() { + [ ! -f "${PROFILE}/extensions.json" ] +} + +initialize_enigmail_configured_version() { + mkdir -p "${PROFILE}/preferences" + version="$(dpkg-query --show \ + --showformat='${source:Upstream-Version}' \ + enigmail | sed -E 's,\+.*$,,')" + # Set the value in prefs.js so that Enigmail can manage it itself + # once we've done this once. + set_mozilla_pref "${PROFILE}/prefs.js" \ + "extensions.enigmail.configuredVersion" \ + "\"${version}\"" \ + 'user_pref' +} + +start_thunderbird() { + export GNOME_ACCESSIBILITY=1 + unset SESSION_MANAGER + reconfigure_profile + exec /usr/bin/thunderbird --class "Thunderbird" -profile "${PROFILE}" "${@}" +} + +start_thunderbird "${@}" diff --git a/config/chroot_local-includes/usr/local/bin/tor-browser b/config/chroot_local-includes/usr/local/bin/tor-browser new file mode 100755 index 0000000000000000000000000000000000000000..14a624530ee2873944f453919b9aafed25fbdd3a --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tor-browser @@ -0,0 +1,77 @@ +#!/bin/sh + +# AppArmor Ux rules don't sanitize $PATH, which can lead to an +# exploited application (that's allowed to run this script unconfined) +# having this script run arbitrary code, violating that application's +# confinement. Let's prevent that by setting PATH to a list of +# directories where only root can write. +export PATH='/usr/local/bin:/usr/bin:/bin' + +set -e +set -u + +. gettext.sh +TEXTDOMAIN="tails" +export TEXTDOMAIN + +PROFILE="${HOME}/.tor-browser/profile.default" + +# Import exec_firefox() and configure_best_tor_browser_locale() +. /usr/local/lib/tails-shell-library/tor-browser.sh + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +# Allow Torbutton access to the control port filter (for new identity). +# Setting a password is required, otherwise Torbutton attempts to +# read the authentication cookie file instead, which fails. +export TOR_CONTROL_HOST='127.0.0.1' +export TOR_CONTROL_PORT='9051' +export TOR_CONTROL_PASSWD='passwd' +# Hide Torbutton's "Tor Network Settings..." context menu entry since +# it doesn't work in Tails, and we deal with those configurations +# strictly through Tor Launcher. +export TOR_NO_DISPLAY_NETWORK_SETTINGS='yes' + + +ask_for_confirmation() { + if [ "${TOR_BROWSER_SKIP_OFFLINE_WARNING:-}" = 'yes' ] || \ + pgrep -u "${LIVE_USERNAME}" -f "${TBB_INSTALL}/firefox.real"; then + return + fi + + local dialog_title="`gettext \"Tor is not ready\"`" + local dialog_text="`gettext \"Tor is not ready. Start Tor Browser anyway?\"`" + local dialog_start="`gettext \"Start Tor Browser\"`" + local dialog_cancel="`gettext \"Cancel\"`" + zenity --question --title "$dialog_title" --text="$dialog_text" \ + --default-cancel --ok-label "$dialog_start" --cancel-label "$dialog_cancel" +} + +start_browser() { + if [ ! -d "${PROFILE}" ]; then + /usr/local/lib/generate-tor-browser-profile + fi + + TMPDIR="${PROFILE}/tmp" + mkdir --mode=0700 -p "$TMPDIR" + export TMPDIR + + configure_tor_browser_memory_usage "${PROFILE}" + + # We need to set general.useragent.locale properly to get + # localized search plugins (and perhaps other things too). It is + # not enough to simply set intl.locale.matchOS to true. + configure_best_tor_browser_locale "${PROFILE}" + + exec_firefox -allow-remote --class "Tor Browser" -profile "${PROFILE}" "${@}" +} + + +if /usr/local/sbin/tor-has-bootstrapped || ask_for_confirmation; then + # Torbutton 1.5.1+ uses those environment variables + export TOR_SOCKS_HOST='127.0.0.1' + export TOR_SOCKS_PORT='9150' + + start_browser "${@}" +fi diff --git a/config/chroot_local-includes/usr/local/bin/tor-launcher b/config/chroot_local-includes/usr/local/bin/tor-launcher new file mode 100755 index 0000000000000000000000000000000000000000..f2b01b3e0f97b9e38e1b232e0f049ca49e3c91a0 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/tor-launcher @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +# Import: +# - the TBB_EXT and TOR_LAUNCHER_INSTALL variables; +# - the exec_unconfined_firefox() and configure_best_tor_launcher_locale() +# functions. +. /usr/local/lib/tails-shell-library/tor-browser.sh + +unset TOR_CONTROL_PASSWD +unset TOR_FORCE_NET_CONFIG +export TOR_CONFIGURE_ONLY=1 +export TOR_CONTROL_PORT=9051 +export TOR_CONTROL_COOKIE_AUTH_FILE=/run/tor/control.authcookie +export TOR_HIDE_BROWSER_LOGO=1 +if echo "$@" | grep -qw -- --force-net-config; then + export TOR_FORCE_NET_CONFIG=1 +fi + +PROFILE="${HOME}/.tor-launcher/profile.default" +if [ ! -d "${PROFILE}" ]; then + mkdir -p "${PROFILE}/extensions" + for ext in "${TBB_EXT}"/langpack-*.xpi; do + ln -s "${ext}" "${PROFILE}/extensions/" + done + configure_best_tor_launcher_locale "${PROFILE}" +fi + +exec_unconfined_firefox \ + -app "${TOR_LAUNCHER_INSTALL}/application.ini" \ + -profile "${PROFILE}" diff --git a/config/chroot_local-includes/usr/local/bin/totem b/config/chroot_local-includes/usr/local/bin/totem new file mode 100755 index 0000000000000000000000000000000000000000..cb72b214f7c55618161ed6491bc8b6060d0fa0a5 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/totem @@ -0,0 +1,2 @@ +#!/bin/sh +exec torsocks /usr/bin/totem "$@" diff --git a/config/chroot_local-includes/usr/local/bin/unlock-veracrypt-volumes b/config/chroot_local-includes/usr/local/bin/unlock-veracrypt-volumes new file mode 100644 index 0000000000000000000000000000000000000000..c7299fff106964ac66393ccb0b60cab2270a2269 --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/unlock-veracrypt-volumes @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import argparse +import logging +from typing import List +import sys +import signal + +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('UDisks', '2.0') +gi.require_version('GUdev', '1.0') +from gi.repository import Gtk, Gio + +from unlock_veracrypt_volumes.volume_manager import VolumeManager +from unlock_veracrypt_volumes.exceptions import AlreadyUnlockedError + + +logger = logging.getLogger(__name__) + + +class App(Gtk.Application): + def __init__(self): + super().__init__(application_id="org.boum.tails.unlock_veracrypt_volumes", flags=Gio.ApplicationFlags.HANDLES_OPEN) + self.manager = None # type: VolumeManager + + def do_activate(self): + if self.manager: + # Raise window of the primary instance + self.manager.window.present() + else: + self.manager = VolumeManager(self) + + def do_open(self, files: List[Gio.File], n_files, hint: str): + logger.debug("in do_open. files: %s", files) + + # Show the window before unlocking the files + self.activate() + + for file in files: + try: + self.manager.unlock_file_container(file.get_path(), open_after_unlock=True) + except AlreadyUnlockedError: + self.manager.open_file_container(file.get_path()) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", action="store_true") + parser.add_argument("PATH", nargs="*", help="file containers to unlock") + return parser.parse_args() + + +def init(args): + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + logger.debug("args: %r", args) + + +def main(): + args = parse_args() + init(args) + app_args = sys.argv[:1] + args.PATH + + # Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=622084 + signal.signal(signal.SIGINT, signal.SIG_DFL) + + app = App() + app.run(app_args) + + +if __name__ == "__main__": + main() diff --git a/config/chroot_local-includes/usr/local/bin/whois b/config/chroot_local-includes/usr/local/bin/whois new file mode 100755 index 0000000000000000000000000000000000000000..0bfe673eed918c3f6fb82bebea183e3b348b688a --- /dev/null +++ b/config/chroot_local-includes/usr/local/bin/whois @@ -0,0 +1,2 @@ +#!/bin/sh +exec torsocks /usr/bin/whois "$@" diff --git a/config/chroot_local-includes/usr/local/lib/add-GNOME-bookmarks b/config/chroot_local-includes/usr/local/lib/add-GNOME-bookmarks new file mode 100755 index 0000000000000000000000000000000000000000..400820b4febf9af11bd6858ebd40e25d795f17c0 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/add-GNOME-bookmarks @@ -0,0 +1,36 @@ +#!/bin/sh + +set -e +set -u + +# We're a no-op unless running as the default desktop user +[ "$(/usr/bin/id -u)" = 1000 ] || exit 0 + +. /usr/local/lib/tails-shell-library/tails-greeter.sh + +add_gtk_bookmark_for() { + local target + target=$(echo "$1" | sed 's, ,%20,g') + + if [ $# -ge 2 ]; then + title="$2" + echo "file://$target $title" >> "${HOME}/.gtk-bookmarks" + else + echo "file://$target" >> "${HOME}/.gtk-bookmarks" + fi +} + +add_gtk_bookmark_for "${HOME}/Tor Browser" + +if persistence_is_enabled_for "${HOME}/Persistent" ; then + add_gtk_bookmark_for "${HOME}/Persistent" + + if persistence_is_enabled_read_write ; then + add_gtk_bookmark_for "${HOME}/Persistent/Tor Browser" \ + "Tor Browser (persistent)" + fi +fi + +for launcher in Report_an_error tails-documentation ; do + gio set "${HOME}/Desktop/${launcher}.desktop" metadata::trusted yes +done diff --git a/config/chroot_local-includes/usr/local/lib/boot-profile b/config/chroot_local-includes/usr/local/lib/boot-profile new file mode 100755 index 0000000000000000000000000000000000000000..456873c156c18455c08d19ae682ea3c11dee61c2 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/boot-profile @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +from pyinotify import WatchManager, Notifier, \ + ThreadedNotifier, ProcessEvent, IN_OPEN, IN_ACCESS, IN_CREATE, IN_MOVED_TO +import re +import sys +import atexit +from signal import signal, SIGTERM +import os.path + +# Ignore files matching this regular expression +IGNORE_RE = "^/(tmp|sys|proc|dev|live/cow)" + +# Remove the following prefix (except the last /) from all paths +IGNORE_PREFIX="/lib/live/mount/rootfs/filesystem.squashfs/" + +class ProfileProcessor(ProcessEvent): + def __init__(self, profile_path): + self.priority = 32767 + self.files = {} + self.ignored_files = {} + self.ignore_re = re.compile(IGNORE_RE) + self.profile_path = profile_path + + def add_file(self, path): + if ' ' in path: + # Skip path with white spaces: mksquashfs -sort does not + # handle them! fscanf(fd, "%s %d", ...) + return + if path.startswith(IGNORE_PREFIX): + path = path[len(IGNORE_PREFIX)-1:] + if path not in self.files: + self.files[path] = self.priority + self.priority -= 1 + + def ignore_file(self, path): + if path.startswith(IGNORE_PREFIX): + path = path[len(IGNORE_PREFIX)-1:] + self.ignored_files[path] = None + + def process_IN_OPEN(self, event): + if not event.dir: + self.add_file(event.pathname) + + def process_IN_ACCESS(self, event): + if not event.dir: + self.add_file(event.pathname) + + def process_IN_CREATE(self, event): + self.ignore_file(event.pathname) + + def process_IN_MOVED_TO(self, event): + self.ignore_file(event.pathname) + + def is_excluded(self, path): + if path.startswith(IGNORE_PREFIX): + path = path[len(IGNORE_PREFIX)-1:] + return self.ignore_re.match(path) + + def end_profiling(self): + profile = open(self.profile_path, 'w') + priorities = {} + for path, priority in self.files.items(): + if path not in self.ignored_files: + priorities[priority] = path + keys = list(priorities.keys()) + keys.sort(reverse=True) + for key in keys: + profile.write("%-68s %s\n" % (priorities[key][1:], key)) + profile.close() + +def main(): + if len(sys.argv) < 2: + print("usage: %s " % sys.argv[0], file=sys.stderr) + sys.exit(0) + + wm = WatchManager() + profiler = ProfileProcessor(sys.argv[1]) + + atexit.register(profiler.end_profiling) + signal(SIGTERM, lambda signum, stack_frame: sys.exit(0)) + + notifier = Notifier(wm, profiler) + wm.add_watch('/', IN_OPEN | IN_ACCESS | IN_CREATE | IN_MOVED_TO, rec=True, exclude_filter=profiler.is_excluded) + notifier.loop(daemonize=True, pid_file='/boot-profile.pid') + +if __name__ == '__main__': + main() diff --git a/config/chroot_local-includes/usr/local/lib/create-tor-browser-directories b/config/chroot_local-includes/usr/local/lib/create-tor-browser-directories new file mode 100755 index 0000000000000000000000000000000000000000..3e486a539dd5fdbd2937d16ed1e62f8a28d3ae7c --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/create-tor-browser-directories @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e +set -u + +# We're a no-op unless running as the default desktop user +[ "$(/usr/bin/id -u)" = 1000 ] || exit 0 + +TOR_BROWSER_AMNESIAC_DIR='/home/amnesia/Tor Browser' +TOR_BROWSER_PERSISTENT_DIR='/home/amnesia/Persistent/Tor Browser' + +. /usr/local/lib/tails-shell-library/tails-greeter.sh + +install -d -o amnesia -g amnesia -m 0700 "$TOR_BROWSER_AMNESIAC_DIR" + +if persistence_is_enabled_for "${HOME}/Persistent" && \ + persistence_is_enabled_read_write ; then + install -d -o amnesia -g amnesia -m 0700 "$TOR_BROWSER_PERSISTENT_DIR" +fi diff --git a/config/chroot_local-includes/usr/local/lib/do_not_ever_run_me b/config/chroot_local-includes/usr/local/lib/do_not_ever_run_me new file mode 100755 index 0000000000000000000000000000000000000000..60c2d16a5febd2e9030f25624a6620291783115a --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/do_not_ever_run_me @@ -0,0 +1,39 @@ +#!/bin/sh +# +# This script fully disables the iptables firewall, and thus the +# transparent forwarding thru Tor of all non-local network +# connections... which defeats the whole purpose of this OS, hence +# this script's name. + +IPT=/sbin/iptables +IP6T=/sbin/ip6tables + +[ -x "$IPT" ] || exit 67 +[ -x "$IP6T" ] || exit 68 + +$IPT -P INPUT ACCEPT +$IPT -P FORWARD ACCEPT +$IPT -P OUTPUT ACCEPT + +$IPT -t nat -P PREROUTING ACCEPT +$IPT -t nat -P POSTROUTING ACCEPT +$IPT -t nat -P OUTPUT ACCEPT + +$IPT -t mangle -P PREROUTING ACCEPT +$IPT -t mangle -P INPUT ACCEPT +$IPT -t mangle -P FORWARD ACCEPT +$IPT -t mangle -P OUTPUT ACCEPT +$IPT -t mangle -P POSTROUTING ACCEPT + +$IPT -F +$IPT -t nat -F +$IPT -t mangle -F + +$IPT -X +$IPT -t nat -X +$IPT -t mangle -X + +$IP6T -F +$IP6T -P INPUT ACCEPT +$IP6T -P FORWARD ACCEPT +$IP6T -P OUTPUT ACCEPT diff --git a/config/chroot_local-includes/usr/local/lib/end-profile b/config/chroot_local-includes/usr/local/lib/end-profile new file mode 100755 index 0000000000000000000000000000000000000000..4aee0c7c77bdcde2ad4728db08e2a475eecef791 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/end-profile @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +test -e /boot-profile.pid || exit 0 + +# Wait some time hoping Tor has bootstrapped and Tor Browser is started +sleep 180 + +sudo -n /usr/local/lib/kill-boot-profile diff --git a/config/chroot_local-includes/usr/local/lib/generate-tor-browser-profile b/config/chroot_local-includes/usr/local/lib/generate-tor-browser-profile new file mode 100755 index 0000000000000000000000000000000000000000..1ded3836d97748dbb1aa447ff71ca09757444cf4 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/generate-tor-browser-profile @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e +set -u + +# Import the TBB_PROFILE variable +. /usr/local/lib/tails-shell-library/tor-browser.sh + +USER_PROFILE="${HOME}/.tor-browser" + +if [ -e "${USER_PROFILE}" ]; then + echo "A tor-browser profile already exists at: ${USER_PROFILE}" >&2 + exit 1 +fi + +mkdir -p "${USER_PROFILE}" +cp -a "${TBB_PROFILE}" "${USER_PROFILE}"/profile.default diff --git a/config/chroot_local-includes/usr/local/lib/initramfs-pre-shutdown-hook b/config/chroot_local-includes/usr/local/lib/initramfs-pre-shutdown-hook new file mode 100755 index 0000000000000000000000000000000000000000..607c257978488be4819218e36b13c32a9d838e08 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/initramfs-pre-shutdown-hook @@ -0,0 +1,56 @@ +#!/bin/sh + +# This script is installed by /usr/share/initramfs-tools/hooks/shutdown +# into the initramfs, as /lib/systemd/system-shutdown/tails. It's run by the +# copy of systemd-shutdown that runs (as /shutdown) from inside +# the unpacked initramfs, immediately before executing the requested action +# (halt/poweroff/reboot). + +set -x + +### Unmount relevant filesystems + +# Debugging +mount + +# Otherwise aufs pseudo-links can't be cleaned and we cannot drop caches. +# This may also help for tracking remaining mounts. +mount -o remount,rw /proc + +# Otherwise we can't create new mountpoints in /mnt +mount -o remount,rw / + +# Otherwise aufs pseudo-links can't be removed while unmounting /oldroot, +# and we can't clean up the content of /mnt/live/overlay. +mount -o remount,rw /oldroot/lib/live/mount/overlay + +# Move /oldroot/* mountpoints out of the way +mkdir -p /mnt/live/overlay +mount --move \ + /oldroot/lib/live/mount/overlay \ + /mnt/live/overlay +mkdir -p /mnt/live/squashfs +mount --move \ + /oldroot/lib/live/mount/rootfs/filesystem.squashfs \ + /mnt/live/squashfs +mkdir -p /mnt/live/medium +mount --move \ + /oldroot/lib/live/mount/medium \ + /mnt/live/medium + +# Finally, really unmount relevant filesystems +umount /oldroot +rm -rf /mnt/live/overlay/.w* /mnt/live/overlay/* +umount /mnt/live/overlay + +# Debugging +mount + +### Ensure any remaining disk cache is erased by Linux' memory poisoning +echo 3 > /proc/sys/vm/drop_caches + +### Pause if the test suite wants us to +if [ -e /tails_shutdown_debugging ] ; then + echo "Going to sleep 2 minutes. Happy dumping!" + sleep 120 +fi diff --git a/config/chroot_local-includes/usr/local/lib/initramfs-restore b/config/chroot_local-includes/usr/local/lib/initramfs-restore new file mode 100755 index 0000000000000000000000000000000000000000..7f006a9c2b9ee04e9e7ab0230d4d07dd92b6f31f --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/initramfs-restore @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e +set -u + +WORKDIR=$(/bin/mktemp -d) + +/usr/bin/unmkinitramfs \ + "$(/usr/local/bin/tails-get-bootinfo initrd)" \ + "$WORKDIR" + +# We should not need any kernel modules in there at shutdown time, +# and they take 66% of the entire uncompressed initramfs size, so +# let's save some RAM. +/bin/rm -rf "$WORKDIR"/main/lib/modules + +/bin/mv "$WORKDIR"/main/* /run/initramfs/ + +/bin/rm -rf "$WORKDIR" diff --git a/config/chroot_local-includes/usr/local/lib/kill-boot-profile b/config/chroot_local-includes/usr/local/lib/kill-boot-profile new file mode 100755 index 0000000000000000000000000000000000000000..3828f609e2b27149a16a0426916e59cdad7c1549 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/kill-boot-profile @@ -0,0 +1,3 @@ +#!/bin/sh + +sudo kill $(cat /boot-profile.pid) diff --git a/config/chroot_local-includes/usr/local/lib/onion-grater b/config/chroot_local-includes/usr/local/lib/onion-grater new file mode 100755 index 0000000000000000000000000000000000000000..b8369b91bc20dd9abbd5ec48a24ca284402e0de9 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/onion-grater @@ -0,0 +1,731 @@ +#!/usr/bin/python3 -u + +# This filter proxy allows fine-grained access whitelists of commands +# (and their argunents) and events on a per-application basis, stored +# in: +# +# /etc/onion-grater.d/ +# +# that are pretty self-explanatory as long as you understand the Tor +# ControlPort language. The format is expressed in YAML where the +# top-level is supposed to be a list, where each element is a +# dictionary looking something like this: +# +# - name: blabla +# apparmor-profiles: +# - path_to_executable_if_that_is_the_name_of_the_apparmor_profile +# # or +# - explicit_apparmor_profile_name +# ... +# users: +# - user +# ... +# hosts: +# - host +# ... +# commands: +# command: +# - command_arg_rule +# ... +# ... +# confs: +# conf: +# - conf_arg_rule +# ... +# ... +# events: +# event: +# event_option: event_option_value +# ... +# ... +# +# `name` (optional) is a string which gives an internal name, useful +# for debugging. When not given, filters will default to the name of +# the file (excluding extension) they were read from (so there can be +# duplicates!). It is advisable to define one filter per file, and +# give helpful filenames instead of using this field. +# +# A filter is matched if for each of the relevant qualifiers at +# least one of the elements match the client. For local (loopback) +# clients the following qualifiers are relevant: +# +# * `apparmor-profiles`: a list of strings, each being the name +# of the AppArmor profile applied to the binary or script of the client, +# with `*` matching anything. While this matcher always works for binaries, +# it only works for scripts with an enabled AppArmor profile (not +# necessarily enforced, complain mode is good enough). +# +# * `users`: a list of strings, each describing the user of the +# client with `*` matching anything. +# +# For remote (non-local) clients, the following qualifiers are +# relevant: +# +# * hosts: a list of strings, each describing the IPv4 address +# of the client with `*` matching anything. +# +# A filter can serve both local and remote clients by having +# qualifiers of both types. +# +# `commands` (optional) is a list where each item is a dictionary with +# the obligatory `pattern` key, which is a regular expression that is +# matched against the full argument part of the command. The default +# behavior is to just proxy the line through if matched, but it can be +# altered with these keys: +# +# * `replacement`: this rewrites the arguments. The value is a Python +# format string (str.format()) which will be given the match groups +# from the match of `pattern`. The rewritten command is then proxied +# without the need to match any rule. There are also some special +# patterns that will be replaced as follows: +# +# - {client-address}: the client's IP address +# - {client-port}: the client's port +# - {server-address}: the server's IP address +# - {server-port}: the server's (listening) port +# +# * `response`: a list of dictionaries, where the `pattern` and +# `replacement` keys work exactly as for commands arguments, but now +# for the response. Note that this means that the response is left +# intact if `pattern` doesn't match it, and if many `pattern`:s +# match, only the first one (in the order listed) will trigger a +# replacement. +# +# If a simple regex (as string) is given, it is assumed to be the +# `pattern` which allows a short-hand for this common type of rule. +# +# Note that to allow a command to be run without arguments, the empty +# string must be explicitly given as a `pattern`. Hence, an empty +# argument list does not allow any use of the command. +# +# `confs` (optional) is a dictionary, and it's just syntactic sugar to +# generate GETCONF/SETCONF rules. If a key exists, GETCONF of the +# keyname is allowed, and if it has a non-empty list as value, those +# values are allowed to be set. The empty string means that resetting +# it is allowed. This is very useful for applications that like to +# SETCONF on multiple configurations at the same time. +# +# `events` (optional) is a dictionary where the key represents the +# event. If a key exists the event is allowed. The value is another +# dictionary of options: +# +# * `suppress`: a boolean determining whether we should just fool the +# client that it has subscribed to the event (i.e. the client +# request is not filtered) while we suppress them. +# +# * `response`: a dictionary, where the `pattern` and `replacement` +# keys work exactly as for `response` for commands, but now for the +# events. +# +# `restrict-stream-events` (optional) is a boolean, and if set any +# STREAM events sent to the client (after it has subscribed to them) +# will be restricted to those belonging to the client itself. This +# option only works for local clients and will be unset for remote +# clients. + +import argparse +import fcntl +import glob +import ipaddress +import os.path +import psutil +import re +import socket +import socketserver +import stem +import stem.control +import stem.connection +import struct +import sys +import textwrap +import yaml + +DEFAULT_LISTEN_ADDRESS = 'localhost' +DEFAULT_LISTEN_PORT = 9051 +DEFAULT_COOKIE_PATH = '/run/tor/control.authcookie' +DEFAULT_CONTROL_SOCKET_PATH = '/run/tor/control' + + +class NoRewriteMatch(RuntimeError): + """ + Error when no matching rewrite rule was found but one was expected. + """ + pass + + +def log(msg): + print(msg, file=sys.stderr) + sys.stderr.flush() + + +def pid_of_laddr(address): + try: + return next(conn for conn in psutil.net_connections() + if conn.laddr == address).pid + except StopIteration: + return None + + +def apparmor_profile_of_pid(pid): + # Here we leverage AppArmor's in-kernel solution for determining + # the exact executable invoked. Looking at /proc/pid/exe when an + # interpreted script is running will just point to the + # interpreter's binary, which is not fine-grained enough, but + # AppArmor will be aware of which script is running for processes + # using one of its profiles. However, we fallback to /proc/pid/exe + # in case there is no AppArmor profile, so the only unsupported + # mode here is unconfined scripts. + enabled_aa_profile_re = r'^(.+) \((?:complain|enforce)\)$' + with open('/proc/{}/attr/current'.format(str(pid)), "rb") as fh: + aa_profile_status = str(fh.read().strip(), 'UTF-8') + apparmor_profile_match = re.match(enabled_aa_profile_re, aa_profile_status) + if apparmor_profile_match: + return apparmor_profile_match.group(1) + else: + return psutil.Process(pid).exe() + + +def get_ip_address(ifname): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + return socket.inet_ntoa(fcntl.ioctl( + s.fileno(), + 0x8915, # SIOCGIFADDR + struct.pack('256s', bytes(ifname[:15], 'utf-8')) + )[20:24]) + + +class FilteredControlPortProxySession: + """ + Class used to deal with a single session, delegated from the handler + (FilteredControlPortProxyHandler). Its main job is proxying the traffic + between the client and the real control port, blocking or rewriting + it as dictated by the filter rule set. + """ + + # Limit the length of a line, to prevent DoS attacks trying to + # crash this filter proxy by sending infinitely long lines. + MAX_LINESIZE = 10*1024 + + def __init__(self, handler): + self.allowed_commands = handler.allowed_commands + self.allowed_events = handler.allowed_events + self.client_address = handler.client_address + self.client_pid = handler.client_pid + self.controller = handler.controller + self.debug_log = handler.debug_log + self.filter_name = handler.filter_name + self.restrict_stream_events = handler.restrict_stream_events + self.rfile = handler.rfile + self.server_address = handler.server_address + self.wfile = handler.wfile + self.client_streams = set() + self.subscribed_event_listeners = [] + + def debug_log_send(self, line): + if global_args.print_responses: + self.debug_log(line, format_multiline=True, sep=': <- ') + + def debug_log_recv(self, line): + if global_args.print_requests: + self.debug_log(line, format_multiline=True, sep=': -> ') + + def debug_log_rewrite(self, kind, old, new): + if kind not in ['command', 'received event', 'response'] or \ + (kind == 'command' and not global_args.print_responses) or \ + (kind in ['received event', 'response'] + and not global_args.print_requests): + return + if new != old: + old = textwrap.indent(old.strip(), ' '*4) + new = textwrap.indent(new.strip(), ' '*4) + self.debug_log("rewrote {}:\n{}\nto:\n{}".format(kind, old, new), + format_multiline=False) + + def respond(self, line, raw=False): + if line.isspace(): + return + self.debug_log_send(line) + self.wfile.write(bytes(line, 'ascii')) + if not raw: + self.wfile.write(bytes("\r\n", 'ascii')) + self.wfile.flush() + + def get_rule(self, cmd, arg_str): + allowed_args = self.allowed_commands.get(cmd, []) + return next((rule for rule in allowed_args + if re.match(rule['pattern'] + "$", arg_str)), None) + + def proxy_line(self, line, args_rewriter=None, response_rewriter=None): + if args_rewriter: + new_line = args_rewriter(line) + self.debug_log_rewrite('command', line, new_line) + line = new_line + response = self.controller.msg(line.strip()).raw_content() + if response_rewriter: + new_response = response_rewriter(response) + self.debug_log_rewrite('response', response, new_response) + response = new_response + self.respond(response, raw=True) + + def filter_line(self, line): + self.debug_log("command filtered: {}".format(line)) + self.respond("510 Command filtered") + + def rewrite_line(self, replacers, line): + builtin_replacers = { + 'client-address': self.client_address[0], + 'client-port': str(self.client_address[1]), + 'server-address': self.server_address[0], + 'server-port': str(self.server_address[1]), + } + terminator = '' + if line[-2:] == "\r\n": + terminator = "\r\n" + line = line[:-2] + for r in replacers: + match = re.match(r['pattern'] + "$", line) + if match: + return r['replacement'].format( + *match.groups(), **builtin_replacers + ) + terminator + raise NoRewriteMatch() + + def rewrite_matched_line(self, replacers, line): + try: + return self.rewrite_line(replacers, line) + except NoRewriteMatch: + return line + + def rewrite_matched_lines(self, replacers, lines): + split_lines = lines.strip().split("\r\n") + return "\r\n".join([self.rewrite_matched_line(replacers, line) + for line in split_lines]) + "\r\n" + + def event_cb(self, event, event_rewriter=None): + if self.restrict_stream_events and \ + isinstance(event, stem.response.events.StreamEvent) and \ + not global_args.disable_filtering: + if event.id not in self.client_streams: + if event.status in [stem.StreamStatus.NEW, + stem.StreamStatus.NEWRESOLVE] and \ + self.client_pid == pid_of_laddr((event.source_address, + event.source_port)): + self.client_streams.add(event.id) + else: + return + elif event.status in [stem.StreamStatus.FAILED, + stem.StreamStatus.CLOSED]: + self.client_streams.remove(event.id) + raw_event_content = event.raw_content() + if event_rewriter: + new_raw_event_content = event_rewriter(raw_event_content) + self.debug_log_rewrite( + 'received event', raw_event_content, new_raw_event_content + ) + raw_event_content = new_raw_event_content + if raw_event_content.strip() == '': + return + self.respond(raw_event_content, raw=True) + + def update_event_subscriptions(self, events): + for listener, event in self.subscribed_event_listeners: + if event not in events: + self.controller.remove_event_listener(listener) + self.subscribed_event_listeners.remove((listener, event)) + if global_args.print_responses: + self.debug_log("unsubscribed from event '{}'".format(event)) + for event in events: + if any(event == event_ for _, event_ in self.subscribed_event_listeners): + if global_args.print_responses: + self.debug_log("already subscribed to event '{}'" + .format(event)) + continue + rule = self.allowed_events.get(event, {}) or {} + if not rule.get('suppress', False) or \ + global_args.disable_filtering: + event_rewriter = None + if 'response' in rule: + replacers = rule['response'] + def _event_rewriter(line): + return self.rewrite_matched_line(replacers, line) + event_rewriter = _event_rewriter + def _event_cb(event): + self.event_cb(event, event_rewriter=event_rewriter) + self.controller.add_event_listener( + _event_cb, getattr(stem.control.EventType, event) + ) + self.subscribed_event_listeners.append((_event_cb, event)) + if global_args.print_responses: + self.debug_log("subscribed to event '{}'".format(event)) + else: + if global_args.print_responses: + self.debug_log("suppressed subscription to event '{}'" + .format(event)) + self.respond("250 OK") + + def handle(self): + while True: + binary_line = self.rfile.readline(self.MAX_LINESIZE) + if binary_line == b'': + # Deal with clients that close the socket without a QUIT. + break + line = str(binary_line, 'ascii') + if line.isspace(): + self.debug_log('ignoring received empty (or whitespace-only) ' + + 'line') + continue + match = re.match( + r'(?P\S+)(?P\s*)(?P[^\r\n]*)\r?\n$', + line + ) + if not match: + self.debug_log("received bad line (escapes made explicit): " + + repr(line)) + # Hopefully the next line is ok... + continue + self.debug_log_recv(line) + cmd = match.group('cmd') + cmd_arg_sep = match.group('cmd_arg_sep') + arg_str = match.group('arg_str') + args = arg_str.split() + cmd = cmd.upper() + + if cmd == "PROTOCOLINFO": + # Stem calls PROTOCOLINFO before authenticating. Tell the + # client that there is no authentication. + self.respond("250-PROTOCOLINFO 1") + self.respond("250-AUTH METHODS=NULL") + self.respond("250-VERSION Tor=\"{}\"" + .format(self.controller.get_version())) + self.respond("250 OK") + + elif cmd == "AUTHENTICATE": + # We have already authenticated, and the filtered port is + # access-restricted according to our filter instead. + self.respond("250 OK") + + elif cmd == "QUIT": + self.respond("250 closing connection") + break + + elif cmd == "SETEVENTS": + # The control language doesn't care about case for + # the event type. + events = [event.upper() for event in args] + if not global_args.disable_filtering and \ + any(event not in self.allowed_events for event in events): + self.filter_line(line) + else: + self.update_event_subscriptions(events) + + else: + rule = self.get_rule(cmd, arg_str) + if rule is None and global_args.disable_filtering: + rule = {} + if rule is not None: + args_rewriter = None + response_rewriter = None + + if 'response' in rule: + def _response_rewriter(lines): + return self.rewrite_matched_lines(rule['response'], + lines) + response_rewriter = _response_rewriter + + if 'replacement' in rule: + def _args_rewriter(line): + # We also want to match the command in `line` + # and add it back to the replacement string. + # We make sure to keep the exact white spaces + # separating the command and arguments, to not + # rewrite the line unnecessarily. + prefix = cmd + cmd_arg_sep + replacer = { + 'pattern': prefix + rule['pattern'], + 'replacement': prefix + rule['replacement'] + } + return self.rewrite_line([replacer], line) + args_rewriter = _args_rewriter + + self.proxy_line(line, args_rewriter=args_rewriter, + response_rewriter=response_rewriter) + else: + self.filter_line(line) + + +class FilteredControlPortProxyHandler(socketserver.StreamRequestHandler): + """ + Class handing each control port connection and collecting information + about the origin and using it to find a matching filter rule set. It + then delegates the session handling (the actual filtering) to a + FilteredControlPortProxySession object. + """ + + def debug_log(self, line, format_multiline=False, sep=': '): + line = line.strip() + if format_multiline and "\n" in line: + sep += "(multi-line)\n" + line = textwrap.indent(line, ' '*4) + log(self.client_desc + sep + line) + + def setup(self): + super(type(self), self).setup() + self.allowed_commands = {} + self.allowed_events = {} + self.client_desc = None + self.client_pid = None + self.client_streams = set() + self.controller = None + self.filter_name = None + self.filters = [] + self.restrict_stream_events = False + self.server_address = self.server.server_address + self.subscribed_event_listeners = [] + for filter_file in glob.glob('/etc/onion-grater.d/*.yml'): + try: + with open(filter_file, "rb") as fh: + filters = yaml.safe_load(fh.read()) + name = re.sub(r'\.yml$', '', os.path.basename(filter_file)) + for filter_ in filters: + if name not in filter_: + filter_['name'] = name + self.filters += filters + except (yaml.parser.ParserError, yaml.scanner.ScannerError) as err: + log("filter '{}' has bad YAML and was not loaded: {}" + .format(filter_file, str(err))) + + def add_allowed_commands(self, commands): + for cmd in commands: + allowed_args = commands[cmd] + # An empty argument list allows nothing, but will + # make some code below easier than if it can be + # None as well. + if allowed_args is None: + allowed_args = [] + for i in range(len(allowed_args)): + if isinstance(allowed_args[i], str): + allowed_args[i] = {'pattern': allowed_args[i]} + self.allowed_commands[cmd.upper()] = allowed_args + + def add_allowed_confs_commands(self, confs): + combined_getconf_rule = {'pattern': "(" + "|".join([ + key for key in confs]) + ")"} + setconf_reset_part = "\s*|\s*".join([ + key for key in confs + if isinstance(confs[key], list) and '' in confs[key]] + ) + setconf_assignment_part = "\s*|\s*".join([ + "{}=({})".format( + key, "|".join(confs[key]) + ) + for key in confs + if isinstance(confs[key], list) and len(confs[key]) > 0]) + setconf_parts = [] + for part in [setconf_reset_part, setconf_assignment_part]: + if part and part != '': + setconf_parts.append(part) + combined_setconf_rule = { + 'pattern': "({})+".format("\s*|\s*".join(setconf_parts)) + } + for cmd, rule in [('GETCONF', combined_getconf_rule), + ('SETCONF', combined_setconf_rule)]: + if rule['pattern'] != "()+": + if cmd not in self.allowed_commands: + self.allowed_commands[cmd] = [] + self.allowed_commands[cmd].append(rule) + + def add_allowed_events(self, events): + for event in events: + opts = events[event] + # Same as for the `commands` argument list, let's + # add an empty dict to simplify later code. + if opts is None: + opts = {} + self.allowed_events[event.upper()] = opts + + def match_and_parse_filter(self, matchers): + matched_filters = [filter_ for filter_ in self.filters + if all(any(val == expected_val or val == '*' + for val in filter_.get(key, [])) + for key, expected_val in matchers)] + if len(matched_filters) == 0: + return + elif len(matched_filters) > 1: + raise RuntimeError('multiple filters matched: ' + + ', '.join(matched_filters)) + matched_filter = matched_filters[0] + self.filter_name = matched_filter['name'] + commands = matched_filter.get('commands', {}) or {} + self.add_allowed_commands(commands) + confs = matched_filter.get('confs', {}) or {} + self.add_allowed_confs_commands(confs) + events = matched_filter.get('events', {}) or {} + self.add_allowed_events(events) + self.restrict_stream_events = bool(matched_filter.get( + 'restrict-stream-events', False + )) + + def connect_to_real_control_port(self): + controller = stem.connection.connect(control_socket=global_args.control_socket_path) + stem.connection.authenticate_cookie(controller, cookie_path=global_args.control_cookie_path) + return controller + + def handle(self): + client_host = self.client_address[0] + local_connection = ipaddress.ip_address(client_host).is_loopback + if local_connection: + self.client_pid = pid_of_laddr(self.client_address) + # Deal with the race between looking up the PID, and the + # client being killed before we find the PID. + if not self.client_pid: + return + client_apparmor_profile = apparmor_profile_of_pid(self.client_pid) + client_user = psutil.Process(self.client_pid).username() + matchers = [ + ('apparmor-profiles', client_apparmor_profile), + ('users', client_user), + ] + else: + self.client_pid = None + matchers = [ + ('hosts', client_host), + ] + self.match_and_parse_filter(matchers) + if local_connection: + self.client_desc = '{aa_profile} (pid: {pid}, user: {user}, ' \ + 'port: {port}, filter: {filter_name})'.format( + aa_profile=client_apparmor_profile, + pid=self.client_pid, + user=client_user, + port=self.client_address[1], + filter_name=self.filter_name + ) + else: + self.client_desc = '{1}:{2} (filter: {0})'.format( + self.filter_name, *self.client_address + ) + if self.restrict_stream_events and not local_connection: + self.debug_log( + "filter '{}' has `restrict-stream-events` set " + "and we are remote so the option was disabled" + .format(self.filter_name) + ) + self.restrict_stream_events = False + + if len(self.filters) == 0: + status = 'no matching filter found, using an empty one' + else: + status = 'loaded filter: {}'.format(self.filter_name) + log('{} connected: {}'.format(self.client_desc, status)) + if global_args.debug: + log('Final rules:') + log(yaml.dump({ + 'commands': self.allowed_commands, + 'events': self.allowed_events, + 'restrict-stream-events': self.restrict_stream_events, + })) + disconnect_reason = "client quit" + try: + self.controller = self.connect_to_real_control_port() + session = FilteredControlPortProxySession(self) + session.handle() + except (ConnectionResetError, BrokenPipeError) as err: + # Handle clients disconnecting abruptly + disconnect_reason = str(err) + except stem.SocketError: + # Handle client closing its socket abruptly + disconnect_reason = "Client closed its socket" + except stem.SocketClosed: + # Handle Tor closing its socket abruptly + disconnect_reason = "Tor closed its socket" + finally: + if self.controller: + self.controller.close() + log('{} disconnected: {}'.format(self.client_desc, + disconnect_reason)) + + +class FilteredControlPortProxy(socketserver.ThreadingTCPServer): + """ + Simple subclass just setting some defaults differently. + """ + + # So we can restart when the listening port if in TIME_WAIT state + # after an abrupt shutdown. + allow_reuse_address = True + # So all server threads immediately quit when the main thread + # quits. + daemon_threads = True + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--listen-address", + type=str, metavar='ADDR', default=DEFAULT_LISTEN_ADDRESS, + help="specifies the address on which the server listens " + + "(default: {})".format(DEFAULT_LISTEN_ADDRESS) + ) + parser.add_argument( + "--listen-port", + type=int, metavar='PORT', default=DEFAULT_LISTEN_PORT, + help="specifies the port on which the server listens " + + "(default: {})".format(DEFAULT_LISTEN_PORT) + ) + parser.add_argument( + "--listen-interface", + type=str, metavar='INTERFACE', + help="specifies the interface on which the server listens " + + "(default: NULL)" + ) + parser.add_argument( + "--control-cookie-path", + type=str, metavar='PATH', default=DEFAULT_COOKIE_PATH, + help="specifies the path to Tor's control authentication cookie " + + "(default: {})".format(DEFAULT_COOKIE_PATH) + ) + parser.add_argument( + "--control-socket-path", + type=str, metavar='PATH', default=DEFAULT_CONTROL_SOCKET_PATH, + help="specifies the path to Tor's control socket " + + "(default: {})".format(DEFAULT_CONTROL_SOCKET_PATH) + ) + parser.add_argument( + "--complain", + action='store_true', default=False, + help="disables all filtering and just prints the commands sent " + + "by the client" + ) + parser.add_argument( + "--debug", + action='store_true', default=False, + help="prints all requests and responses" + ) + # We put the argparse results in the global scope since it's + # awkward to extend socketserver so additional data can be sent to + # the request handler, where we need access to the arguments. + global global_args + global_args = parser.parse_args() + # Deal with overlapping functionality between arguments + global_args.__dict__['disable_filtering'] = global_args.complain + global_args.__dict__['print_requests'] = global_args.complain or \ + global_args.debug + global_args.__dict__['print_responses'] = global_args.debug + if global_args.listen_interface: + ip_address = get_ip_address(global_args.listen_interface) + if global_args.debug: + log("IP address for interface {} : {}".format( + global_args.listen_interface,ip_address)) + else: + ip_address = global_args.listen_address + address = (ip_address, global_args.listen_port) + server = FilteredControlPortProxy(address, FilteredControlPortProxyHandler) + log("Tor control port filter started, listening on {}:{}".format(*address)) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + + +if __name__ == "__main__": + main() diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/__init__.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..50f48c271b3703b6209421989099b53efbba19bc --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/__init__.py @@ -0,0 +1,12 @@ +# Translation stuff + +import os +import gettext + + +if os.path.exists('po/locale'): + translation = gettext.translation("tails", 'po/locale', fallback=True) +else: + translation = gettext.translation("tails", '/usr/share/locale', fallback=True) + +_ = translation.gettext diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/config.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/config.py new file mode 100644 index 0000000000000000000000000000000000000000..6d025c3c840b3064db5c97b730c2b63e972fe510 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/config.py @@ -0,0 +1,7 @@ +from os import path + +APP_NAME = "unlock-veracrypt-volumes" +DATA_DIR = "/usr/share/tails/%s/" % APP_NAME +MAIN_UI_FILE = path.join(DATA_DIR, "main.ui") +VOLUME_UI_FILE = path.join(DATA_DIR, "volume.ui") +TRANSLATION_DOMAIN = "tails" diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/exceptions.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..01a728d8a00c894eec7297497be925ebbb487344 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/exceptions.py @@ -0,0 +1,10 @@ +class UdisksObjectNotFoundError(Exception): + pass + + +class VolumeNotFoundError(Exception): + pass + + +class AlreadyUnlockedError(Exception): + pass \ No newline at end of file diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py new file mode 100644 index 0000000000000000000000000000000000000000..417bc79faaad63ee041514342743bfb32c387f5b --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py @@ -0,0 +1,370 @@ +from logging import getLogger +from typing import Union + +from gi.repository import Gtk, GLib, Gio, UDisks + +from unlock_veracrypt_volumes import _ +from unlock_veracrypt_volumes.config import TRANSLATION_DOMAIN, VOLUME_UI_FILE +from unlock_veracrypt_volumes.exceptions import UdisksObjectNotFoundError, AlreadyUnlockedError + +logger = getLogger(__name__) + + +class Volume(object): + def __init__(self, manager, + gio_volume: Gio.Volume = None, + udisks_object: UDisks.Object = None, + with_udisks=True): + self.manager = manager + self.udisks_client = manager.udisks_client + self.udev_client = manager.udev_client + self.gio_volume = gio_volume + + if udisks_object: + self.udisks_object = udisks_object + elif self.gio_volume and with_udisks: + self.udisks_object = self._find_udisks_object() + else: + self.udisks_object = None + + self.spinner_is_showing = False + self.dialog_is_showing = False + + self.builder = Gtk.Builder.new_from_file(VOLUME_UI_FILE) + self.builder.set_translation_domain(TRANSLATION_DOMAIN) + self.builder.connect_signals(self) + self.list_box_row = self.builder.get_object("volume_row") # type: Gtk.ListBoxRow + self.box = self.builder.get_object("volume_box") # type: Gtk.Box + self.label = self.builder.get_object("volume_label") # type: Gtk.Label + self.button_box = self.builder.get_object("volume_button_box") # type: Gtk.ButtonBox + self.open_button = self.builder.get_object("open_button") # type: Gtk.Button + self.lock_button = self.builder.get_object("lock_button") # type: Gtk.Button + self.unlock_button = self.builder.get_object("unlock_button") # type: Gtk.Button + self.detach_button = self.builder.get_object("detach_button") # type: Gtk.Button + self.spinner = Gtk.Spinner(visible=True, margin_right=10) + + def __eq__(self, other: "Volume"): + return self.device_file == other.device_file + + @property + def name(self) -> str: + """Short description for display to the user. The block device + label or partition label, if any, plus the size""" + block_label = self.udisks_object.get_block().props.id_label + partition = self.udisks_object.get_partition() + if block_label: + # Translators: Don't translate {volume_label} or {volume_size}, + # they are placeholders and will be replaced. + return _("{volume_label} ({volume_size})").format(volume_label=block_label, + volume_size=self.size_for_display) + elif partition and partition.props.name: + # Translators: Don't translate {partition_name} or {partition_size}, + # they are placeholders and will be replaced. + return _("{partition_name} ({partition_size})").format(partition_name=partition.props.name, + partition_size=self.size_for_display) + else: + # Translators: Don't translate {volume_size}, it's a placeholder + # and will be replaced. + return _("{volume_size} Volume").format(volume_size=self.size_for_display) + + @property + def size_for_display(self) -> str: + size = self.udisks_object.get_block().props.size + return self.udisks_client.get_size_for_display(size, use_pow2=False, long_string=False) + + @property + def drive_name(self) -> str: + if self.is_file_container: + return str() + + if self.is_unlocked: + drive_object = self.udisks_client.get_object(self.backing_udisks_object.get_block().props.drive) + else: + drive_object = self.drive_object + + if drive_object: + return "%s %s" % (drive_object.get_drive().props.vendor, drive_object.get_drive().props.model) + else: + return str() + + @property + def backing_file_name(self) -> str: + if not self.is_file_container: + return str() + if self.is_unlocked: + return self.backing_udisks_object.get_loop().props.backing_file + elif self.is_loop_device: + return self.udisks_object.get_loop().props.backing_file + elif self.partition_table_object and self.partition_table_object.get_loop(): + return self.partition_table_object.get_loop().props.backing_file + + @property + def description(self) -> str: + """Longer description for display to the user.""" + if self.udisks_object.get_block().props.read_only: + # Translators: Don't translate {volume_name}, it's a placeholder and + # will be replaced. + desc = _("{volume_name} (Read-Only)").format(volume_name=self.name) + else: + desc = self.name + + if self.partition_table_object and self.partition_table_object.get_loop(): + # This is a partition of a loop device, so lets include the backing file name + # Translators: Don't translate {partition_name} and {container_path}, they + # are placeholders and will be replaced. + return _("{partition_name} in {container_path}").format(partition_name=desc, + container_path=self.backing_file_name) + elif self.is_file_container: + # This is file container, lets include the file name + # Translators: Don't translate {volume_name} and {path_to_file_container}, + # they are placeholders and will be replaced. You should only have to translate + # this string if it makes sense to reverse the order of the placeholders. + return _("{volume_name} – {path_to_file_container}").format(volume_name=desc, + path_to_file_container=self.backing_file_name) + elif self.is_partition and self.drive_object: + # This is a partition on a drive, lets include the drive name + # Translators: Don't translate {partition_name} and {drive_name}, they + # are placeholders and will be replaced. + return _("{partition_name} on {drive_name}").format(partition_name=desc, + drive_name=self.drive_name) + elif self.drive_name: + # This is probably an unpartitioned drive, so lets include the drive name + # Translators: Don't translate {volume_name} and {drive_name}, + # they are placeholders and will be replaced. You should only have to translate + # this string if it makes sense to reverse the order of the placeholders. + return _("{volume_name} – {drive_name}").format(volume_name=desc, + drive_name=self.drive_name) + else: + return desc + + @property + def device_file(self) -> str: + if self.gio_volume: + return self.gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) + elif self.udisks_object: + return self.udisks_object.get_block().props.device + + @property + def backing_volume(self) -> Union["Volume", None]: + if self.backing_udisks_object: + return Volume(self.manager, udisks_object=self.backing_udisks_object) + return None + + @property + def backing_udisks_object(self) -> Union[UDisks.Object, None]: + return self.udisks_client.get_object(self.udisks_object.get_block().props.crypto_backing_device) + + @property + def partition_table_object(self) -> Union[UDisks.Object, None]: + if not self.udisks_object.get_partition(): + return None + return self.udisks_client.get_object(self.udisks_object.get_partition().props.table) + + @property + def drive_object(self) -> Union[UDisks.Object, None]: + return self.udisks_client.get_object(self.udisks_object.get_block().props.drive) + + @property + def is_unlocked(self) -> bool: + return bool(self.backing_udisks_object) + + @property + def is_loop_device(self) -> bool: + return bool(self.udisks_object.get_loop()) + + @property + def is_loop_device_partition(self) -> bool: + return bool(self.partition_table_object and self.partition_table_object.get_loop()) + + @property + def is_partition(self) -> bool: + return bool(self.udisks_object.get_partition()) + + @property + def is_tcrypt(self) -> bool: + if self.is_unlocked: + udisks_object = self.backing_udisks_object + else: + udisks_object = self.udisks_object + + return bool(udisks_object.get_encrypted() and + udisks_object.get_block().props.id_type in ("crypto_TCRYPT", "crypto_unknown")) + + @property + def is_file_container(self) -> bool: + if "/dev/loop" in self.device_file: + return True + + if "/dev/dm" in self.device_file: + return bool(self.backing_udisks_object and self.backing_udisks_object.get_loop()) + + def unlock(self, open_after_unlock=False): + + def on_mount_operation_reply(mount_op: Gtk.MountOperation, result: Gio.MountOperationResult): + logger.debug("in on_mount_operation_reply") + if result == Gio.MountOperationResult.HANDLED: + self.show_spinner() + + def mount_cb(gio_volume: Gio.Volume, result: Gio.AsyncResult): + logger.debug("in mount_cb") + self.hide_spinner() + try: + gio_volume.mount_finish(result) + except GLib.Error as e: + if e.code == Gio.IOErrorEnum.FAILED_HANDLED: + logger.warning("Couldn't unlock volume: %s:", e.message) + return + + logger.exception(e) + + if "No key available with this passphrase" in e.message or \ + "No device header detected with this passphrase" in e.message: + title = _("Wrong passphrase or parameters") + else: + title = _("Error unlocking volume") + + # Translators: Don't translate {volume_name} or {error_message}, + # they are placeholder and will be replaced. + body = _("Couldn't unlock volume {volume_name}:\n{error_message}".format(volume_name=self.name, error_message=e.message)) + self.manager.show_warning(title, body) + return + finally: + self.manager.mount_op_lock.release() + + if open_after_unlock: + # The GVolume now changed from the loop device to the dm device, so + # by also updating the udisks object we change this volume from the + # crypto backing loop device to the unlocked device-mapper device, + # which we can then open + self.udisks_object = self._find_udisks_object() + self.open() + + if self.is_unlocked: + raise AlreadyUnlockedError("Volume %s is already unlocked" % self.device_file) + + logger.info("Unlocking volume %s", self.device_file) + self.dialog_is_showing = False + mount_operation = Gtk.MountOperation() + mount_operation.set_username("user") + mount_operation.connect("reply", on_mount_operation_reply) + + # Things break if multiple mount operations are running at the same time, + # so we use a lock to prevent that + self.manager.acquire_mount_op_lock() + self.gio_volume.mount(0, # Gio.MountMountFlags + mount_operation, # Gtk.MountOperation + None, # Gio.Cancellable + mount_cb) # callback + + def lock(self): + logger.info("Locking volume %s", self.device_file) + self.udisks_object.get_encrypted().call_lock_sync(GLib.Variant('a{sv}', {}), # options + None) # cancellable + + def unmount(self): + logger.info("Unmounting volume %s", self.device_file) + unmounted_at_least_once = False + while self.udisks_object.get_filesystem().props.mount_points: + try: + self.udisks_object.get_filesystem().call_unmount_sync(GLib.Variant('a{sv}', {}), # options + None) # cancellable + unmounted_at_least_once = True + except GLib.Error as e: + # Ignore "not mounted" error if the volume was already unmounted + if "org.freedesktop.UDisks2.Error.NotMounted" in e.message and unmounted_at_least_once: + return + raise + + def detach_loop_device(self): + logger.info("Detaching volume %s", self.device_file) + if self.is_loop_device: + self.udisks_object.get_loop().call_delete_sync(GLib.Variant('a{sv}', {}), # options + None) # cancellable + elif self.is_loop_device_partition: + self.partition_table_object.get_loop().call_delete_sync(GLib.Variant('a{sv}', {}), # options + None) # cancellable + + def open(self): + logger.info("Opening volume %s", self.device_file) + mount_points = self.udisks_object.get_filesystem().props.mount_points + if not mount_points: + self.mount() + self.open() + else: + self.manager.open_uri(GLib.filename_to_uri(mount_points[0])) + + def mount(self): + logger.info("Mounting volume %s", self.device_file) + self.udisks_object.get_filesystem().call_mount_sync(GLib.Variant('a{sv}', {}), # options + None) # cancellable + + def show_spinner(self): + logger.debug("in show_spinner") + self.button_box.hide() + self.button_box.set_no_show_all(True) + self.box.add(self.spinner) + self.spinner.start() + self.spinner.show() + + def hide_spinner(self): + logger.debug("in hide_spinner") + self.button_box.set_no_show_all(False) + self.button_box.show() + self.spinner.stop() + self.box.remove(self.spinner) + + def on_lock_button_clicked(self, button): + logger.debug("in on_lock_button_clicked") + loop = self.backing_volume.udisks_object.get_loop() + if loop: + # Ensure that the loop device is removed after locking the volume + loop.call_set_autoclear_sync(True, + GLib.Variant('a{sv}', {}), # options + None) # cancellable + try: + self.unmount() + self.backing_volume.lock() + except GLib.Error as e: + # Translators: Don't translate {volume_name} or {error_message}, + # they are placeholder and will be replaced. + body = _("Couldn't lock volume {volume_name}:\n{error_message}".format(volume_name=self.name, + error_message=e.message)) + self.manager.show_warning(_("Error locking volume"), body) + return + + def on_unlock_button_clicked(self, button): + logger.debug("in on_unlock_button_clicked") + self.unlock() + + def on_detach_button_clicked(self, button): + logger.debug("in on_detach_button_clicked") + self.detach_loop_device() + + def on_open_button_clicked(self, button): + logger.debug("in on_open_button_clicked") + self.open() + + def update_list_box_row(self): + logger.debug("in update_list_box_row. is_unlocked: %s", self.is_unlocked) + self.label.set_label(self.description) + self.open_button.set_visible(self.is_unlocked) + self.lock_button.set_visible(self.is_unlocked) + self.unlock_button.set_visible(not self.is_unlocked) + self.detach_button.set_visible(not self.is_unlocked and (self.is_loop_device or self.is_loop_device_partition)) + + def _find_udisks_object(self) -> UDisks.Object: + device_file = self.gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) + if not device_file: + raise UdisksObjectNotFoundError("Couldn't get device file for volume") + + udev_volume = self.udev_client.query_by_device_file(device_file) + if not udev_volume: + raise UdisksObjectNotFoundError("Couldn't get udev volume for %s" % device_file) + + device_number = udev_volume.get_device_number() + udisks_block = self.udisks_client.get_block_for_dev(device_number) + if not udisks_block: + raise UdisksObjectNotFoundError("Couldn't get UDisksBlock for volume %s" % device_file) + + object_path = udisks_block.get_object_path() + return self.udisks_client.get_object(object_path) diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_list.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_list.py new file mode 100644 index 0000000000000000000000000000000000000000..12404d505bb9c4dd1abb21d46e603dacf1cb7af2 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_list.py @@ -0,0 +1,98 @@ +from logging import getLogger +import abc +from typing import List, Union + +from gi.repository import Gtk + +from unlock_veracrypt_volumes import _ +from unlock_veracrypt_volumes.volume import Volume +from unlock_veracrypt_volumes.exceptions import VolumeNotFoundError + +logger = getLogger(__name__) + + +class VolumeList(object, metaclass=abc.ABCMeta): + + placeholder_label = str() + + def __init__(self): + self.volumes = list() + self.list_box = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) + self.list_box.set_header_func(self.listbox_header_func) + self.placeholder_row = Gtk.ListBoxRow(activatable=False, selectable=False) + self.placeholder_row.add(Gtk.Label(self.placeholder_label)) + self.show_placeholder() + + def __getitem__(self, item): + return self.volumes[item] + + @staticmethod + def listbox_header_func(row, before, data=None): + if not before: + return + separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) + row.set_header(separator) + + def add(self, volume: Volume): + if volume in self.volumes: + self.update(volume) + return + + volume.update_list_box_row() + self.list_box.add(volume.list_box_row) + self.volumes.append(volume) + + if len(self.volumes) == 1: + self.hide_placeholder() + + self.list_box.show_all() + + def remove(self, volume: Volume): + # Note that we can't use any properties and functions of the volume here + # which use udisks, because the volume might be already removed from udisks + if volume not in self.volumes: + logger.warning("Can't remove volume %s: Not in list", volume.device_file) + return + + index = self.volumes.index(volume) + self.list_box.remove(self.list_box.get_children()[index]) + self.volumes.remove(volume) + + if not self.volumes: + self.show_placeholder() + + self.list_box.show_all() + + def update(self, volume: Volume): + self.remove(volume) + self.add(volume) + + def clear(self): + for child in self.list_box.get_children(): + self.list_box.remove(child) + + def show_placeholder(self): + self.list_box.add(self.placeholder_row) + + def hide_placeholder(self): + self.list_box.remove(self.placeholder_row) + + +class ContainerList(VolumeList): + """Manages attached file containers""" + placeholder_label = _("No file containers added") + + @property + def backing_file_paths(self) -> List[str]: + return [volume.backing_file_name for volume in self.volumes] + + def find_by_backing_file(self, path: str) -> Union[Volume, None]: + for volume in self.volumes: + if volume.backing_file_name == path: + return volume + raise VolumeNotFoundError() + + +class DeviceList(VolumeList): + """Manages physically connected drives and partitions""" + placeholder_label = _("No VeraCrypt devices detected") diff --git a/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_manager.py b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..5a1e3e39e8a4768618ff61ef5cc32873850f56e7 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/python3/dist-packages/unlock_veracrypt_volumes/volume_manager.py @@ -0,0 +1,268 @@ +import subprocess +import time +import os +from logging import getLogger +from typing import List, Union +from threading import Lock + +from gi.repository import Gtk, Gio, UDisks, GUdev, GLib + +from unlock_veracrypt_volumes import _ +from unlock_veracrypt_volumes.volume_list import ContainerList, DeviceList +from unlock_veracrypt_volumes.volume import Volume +from unlock_veracrypt_volumes.exceptions import UdisksObjectNotFoundError, VolumeNotFoundError +from unlock_veracrypt_volumes.config import MAIN_UI_FILE, TRANSLATION_DOMAIN + + +WAIT_FOR_LOOP_SETUP_TIMEOUT = 1 + + +logger = getLogger(__name__) + + +class VolumeManager(object): + def __init__(self, application: Gtk.Application): + self.udisks_client = UDisks.Client.new_sync() + self.udisks_manager = self.udisks_client.get_manager() + self.gio_volume_monitor = Gio.VolumeMonitor.get() + self.gio_volume_monitor.connect("volume-changed", self.on_volume_changed) + self.gio_volume_monitor.connect("volume-added", self.on_volume_added) + self.gio_volume_monitor.connect("volume-removed", self.on_volume_removed) + self.udev_client = GUdev.Client() + self.mount_op_lock = Lock() + + self.builder = Gtk.Builder.new_from_file(MAIN_UI_FILE) + self.builder.set_translation_domain(TRANSLATION_DOMAIN) + self.builder.connect_signals(self) + + self.window = self.builder.get_object("window") # type: Gtk.ApplicationWindow + self.window.set_application(application) + self.window.set_title(_("Unlock VeraCrypt Volumes")) + + self.container_list = ContainerList() + self.device_list = DeviceList() + + containers_frame = self.builder.get_object("containers_frame") + containers_frame.add(self.container_list.list_box) + devices_frame = self.builder.get_object("devices_frame") + devices_frame.add(self.device_list.list_box) + + self.add_tcrypt_volumes() + + logger.debug("showing window") + self.window.show_all() + self.window.present() + + def add_tcrypt_volumes(self): + logger.debug("in add_tcrypt_volumes") + for volume in self.get_tcrypt_volumes(): + self.add_volume(volume) + + def add_volume(self, volume: Volume): + logger.info("Adding volume %s", volume.device_file) + if volume.is_file_container: + self.container_list.add(volume) + else: + self.device_list.add(volume) + + def remove_volume(self, volume: Volume): + logger.info("Removing volume %s", volume.device_file) + if volume in self.container_list: + self.container_list.remove(volume) + elif volume in self.device_list: + self.device_list.remove(volume) + + def update_volume(self, volume: Volume): + logger.debug("Updating volume %s", volume.device_file) + if volume.is_file_container: + self.container_list.remove(volume) + self.container_list.add(volume) + else: + self.device_list.remove(volume) + self.device_list.add(volume) + + def get_tcrypt_volumes(self) -> List[Volume]: + """Returns all connected TCRYPT volumes""" + return [volume for volume in self.get_all_volumes() if volume.is_tcrypt] + + def get_all_volumes(self) -> List[Volume]: + """Returns all connected volumes""" + volumes = list() + gio_volumes = self.gio_volume_monitor.get_volumes() + + for gio_volume in gio_volumes: + device_file = gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) + if not device_file: + continue + + logger.debug("volume: %s", device_file) + + try: + volumes.append(Volume(self, gio_volume)) + logger.debug("is_file_container: %s", volumes[-1].is_file_container) + logger.debug("is_tcrypt: %s", volumes[-1].is_tcrypt) + logger.debug("is_unlocked: %s", volumes[-1].is_unlocked) + except UdisksObjectNotFoundError as e: + logger.exception(e) + + return volumes + + def on_add_file_container_button_clicked(self, button, data=None): + path = self.choose_container_path() + + if path in self.container_list.backing_file_paths: + self.show_warning(title=_("Container already added"), + body=_("The file container %s should already be listed.") % path) + return + + if path: + self.unlock_file_container(path) + + def attach_file_container(self, path: str) -> Union[Volume, None]: + logger.debug("attaching file %s. backing_file_paths: %s", path, self.container_list.backing_file_paths) + warning = dict() + + try: + fd = os.open(path, os.O_RDWR) + except PermissionError as e: + # Try opening read-only + try: + fd = os.open(path, os.O_RDONLY) + warning["title"] = _("Container opened read-only") + # Translators: Don't translate {path}, it's a placeholder and will be replaced. + warning["body"] = _("The file container {path} could not be opened with write access. " + "It was opened read-only instead. You will not be able to modify the " + "content of the container.\n" + "{error_message}").format(path=path, error_message=str(e)) + except PermissionError as e: + self.show_warning(title=_("Error opening file"), body=str(e)) + return None + + fd_list = Gio.UnixFDList() + fd_list.append(fd) + udisks_path, __ = self.udisks_manager.call_loop_setup_sync(GLib.Variant('h', 0), # fd index + GLib.Variant('a{sv}', {}), # options + fd_list, # the fd list + None) # cancellable + logger.debug("Created loop device %s", udisks_path) + + volume = self._wait_for_loop_setup(path) + if volume: + if warning: + self.show_warning(title=warning["title"], body=warning["body"]) + return volume + elif not self._udisks_object_is_tcrypt(udisks_path): + # Remove the loop device + self.udisks_client.get_object(udisks_path).get_loop().call_delete(GLib.Variant('a{sv}', {}), # options + None, # cancellable + None, # callback + None) # user data + self.show_warning(title=_("Not a VeraCrypt container"), + body=_("The file %s does not seem to be a VeraCrypt container.") % path) + else: + self.show_warning(title=_("Failed to add container"), + body=_("Could not add file container %s: Timeout while waiting for loop setup.\n" + "Please try using the Disks application instead.") % path) + + def _wait_for_loop_setup(self, path: str) -> Union[Volume, None]: + start_time = time.perf_counter() + while time.perf_counter() - start_time < WAIT_FOR_LOOP_SETUP_TIMEOUT: + try: + return self.container_list.find_by_backing_file(path) + except VolumeNotFoundError: + self.process_mainloop_events() + time.sleep(0.1) + + def _udisks_object_is_tcrypt(self, path: str) -> bool: + if not path: + return False + + udisks_object = self.udisks_client.get_object(path) + if not udisks_object: + return False + + return Volume(self, udisks_object=udisks_object).is_tcrypt + + @staticmethod + def process_mainloop_events(): + context = GLib.MainLoop().get_context() + while context.pending(): + context.iteration() + + def open_file_container(self, path: str): + volume = self.ensure_file_container_is_attached(path) + if volume: + volume.open() + + def unlock_file_container(self, path: str, open_after_unlock=False): + volume = self.ensure_file_container_is_attached(path) + if volume: + volume.unlock(open_after_unlock=open_after_unlock) + + def ensure_file_container_is_attached(self, path: str) -> Volume: + try: + return self.container_list.find_by_backing_file(path) + except VolumeNotFoundError: + return self.attach_file_container(path) + + def choose_container_path(self): + dialog = Gtk.FileChooserDialog(_("Choose File Container"), + self.window, + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT)) + result = dialog.run() + if result != Gtk.ResponseType.ACCEPT: + dialog.destroy() + return + + path = dialog.get_filename() + dialog.destroy() + return path + + def on_volume_changed(self, volume_monitor: Gio.VolumeMonitor, gio_volume: Gio.Volume): + logger.debug("in on_volume_changed. volume: %s", + gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)) + try: + volume = Volume(self, gio_volume) + if volume.is_tcrypt: + self.update_volume(volume) + except UdisksObjectNotFoundError: + self.remove_volume(Volume(self, gio_volume, with_udisks=False)) + + def on_volume_added(self, volume_monitor: Gio.VolumeMonitor, gio_volume: Gio.Volume): + logger.debug("in on_volume_added. volume: %s", + gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)) + volume = Volume(self, gio_volume) + if volume.is_tcrypt: + self.add_volume(volume) + + def on_volume_removed(self, volume_monitor: Gio.VolumeMonitor, gio_volume: Gio.Volume): + logger.debug("in on_volume_removed. volume: %s", + gio_volume.get_identifier(Gio.VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)) + self.remove_volume(Volume(self, gio_volume, with_udisks=False)) + + def open_uri(self, uri: str): + # This is the recommended way, but it turns the cursor into wait status for up to + # 10 seconds after the file manager was already opened. + # Gtk.show_uri_on_window(self.window, uri, Gtk.get_current_event_time()) + subprocess.Popen(["xdg-open", uri]) + + def show_warning(self, title: str, body: str): + dialog = Gtk.MessageDialog(self.window, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.WARNING, + Gtk.ButtonsType.CLOSE, + title) + dialog.format_secondary_markup(body) + # Make the body selectable to allow users to easily copy/paste the error message + dialog.get_message_area().get_children()[-1].set_selectable(True) + + dialog.run() + dialog.close() + + def acquire_mount_op_lock(self): + while True: + if self.mount_op_lock.acquire(timeout=0.1): + return + self.process_mainloop_events() diff --git a/config/chroot_local-includes/usr/local/lib/start-systemd-desktop-target b/config/chroot_local-includes/usr/local/lib/start-systemd-desktop-target new file mode 100755 index 0000000000000000000000000000000000000000..f4905b461401246a0475cbeb546666a28e1eb2bf --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/start-systemd-desktop-target @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e +set -u + +# XXX: check if we still need that in Stretch + +# Import (almost all) XDG_*, locale-related and DBUS_SESSION_BUS_ADDRESS variables +# into the systemd user instance's environment. We're filtering some +# XDG_* out in order not to pretend that processes run via `systemd --user` +# are part of the desktop session. +/usr/bin/env \ + | /bin/grep '^XDG_' \ + | /bin/grep -E -v '^XDG_(SEAT=|SESSION_)' \ + | /usr/bin/xargs /bin/systemctl --user set-environment +/usr/bin/locale | /usr/bin/xargs /bin/systemctl --user set-environment +/bin/systemctl --user import-environment \ + DBUS_SESSION_BUS_ADDRESS \ + DISPLAY \ + XAUTHORITY + +# Start desktop.target +/bin/systemctl --user start desktop.target diff --git a/config/chroot_local-includes/usr/local/lib/tails-additional-software-notify b/config/chroot_local-includes/usr/local/lib/tails-additional-software-notify new file mode 100755 index 0000000000000000000000000000000000000000..90b36b9317293946b0ac3d90ca9a649ce59e870e --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-additional-software-notify @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import gettext +import os +import os.path +import subprocess +import sys + +from tailslib.gnome import gnome_env_vars + +import gi + +from gi.repository import GLib + +gi.require_version('Notify', '0.7') +from gi.repository import Notify # NOQA: E402 + +_ = gettext.gettext + + +class ASPNotifier(object): + """Display a notification and exit with a meaningful code.""" + + def __init__(self, title, body, accept_label=None, deny_label=None, + documentation_target=None, urgent=False): + """Shows a notification with two optional action buttons. + + If there are no buttons, exit straight away with a meaningful code. + """ + Notify.init("org.boum.tails.additional-software-packages") + + # We need to hold a reference to the notification until the callbacks + # are called. That's why we use an instance variable. + self.notification = Notify.Notification.new( + title, body, icon="package-x-generic") + if urgent: + self.notification.set_urgency(Notify.Urgency.CRITICAL) + if documentation_target: + self.notification.add_action("documentation", _("Documentation"), + self.cb_notification_clicked, + documentation_target) + if deny_label: + self.notification.add_action("deny", deny_label, + self.cb_notification_clicked, None) + if accept_label: + self.notification.add_action("accept", accept_label, + self.cb_notification_clicked, None) + self.notification.connect("closed", self.cb_notification_closed) + self.notification.show() + sys.stdout.write("id=%i" % self.notification.props.id) + if not (accept_label or deny_label or documentation_target): + sys.exit(2) + + def cb_notification_clicked(self, notification, action, user_data=None): + """Exit the program with a meaningful code on action triggering.""" + if action == "accept": + sys.exit(0) + elif action == "deny": + sys.exit(3) + elif action == "documentation": + subprocess.Popen( + ["env", *gnome_env_vars(), "tails-documentation", user_data] + ) + sys.exit(5) + + def cb_notification_closed(self, notification): + """Exit the program with a meaningful code on notification close.""" + sys.exit(4) + + +def print_help(): + """The subcommand which displays help + """ + program_name = os.path.basename(sys.argv[0]) + sys.stderr.write( + "Usage: %s [ [ " + "[documentation_target []]]]\n" % program_name) + sys.stderr.write( + "Shows a notification with , and optional " + "buttons.\n" + "\n" + "Returns: 0 if the button with is selected\n" + " 2 if the arguments are wrong\n" + " 3 if the button with is selected\n" + " 4 if the notification is closed another way\n", + " 5 if the documentation button is selected and the" + " documentation helper is launched.\n") + + +if __name__ == "__main__": + os.environ["DBUS_SESSION_BUS_ADDRESS"] = \ + "unix:path=/run/user/{uid}/bus".format(uid=os.getuid()) + + gettext.install("tails") + + if not 3 <= len(sys.argv) <= 7: + print_help() + sys.exit(2) + + mainloop = GLib.MainLoop.new(None, False) + ASPNotifier(*sys.argv[1:]) + mainloop.run() diff --git a/config/chroot_local-includes/usr/local/lib/tails-autotest-remote-shell b/config/chroot_local-includes/usr/local/lib/tails-autotest-remote-shell new file mode 100755 index 0000000000000000000000000000000000000000..8660cd6905c4ffcfc66eb651f1bafbbbf70ba049 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-autotest-remote-shell @@ -0,0 +1,191 @@ +#!/usr/bin/python3 + +# ATTENTION: Yes, this can be used as a backdoor, but only for an +# adversary with access to you *physical* serial port, which means +# that you are screwed any way. + +import base64 +import fcntl +import io +import json +import os +import pwd +import serial +import signal +import subprocess +import sys +import systemd.daemon +import textwrap +import traceback + +REMOTE_SHELL_DEV = '/dev/ttyS0' + + +def mk_switch_user_fn(user): + pwd_user = pwd.getpwnam(user) + def switch_user(): + os.initgroups(user, pwd_user.pw_gid) + os.setgid(pwd_user.pw_gid) + os.setuid(pwd_user.pw_uid) + return switch_user + + +def get_user_env(user): + # We try to create an environment identical to what's expected + # inside Tails for the user by logging in (via `su`) as the user, + # setting up the GNOME shell environment, and extracting the + # environment via `env`; not that we will run `env` unconditionally + # since the former command could fail, e.g. if GNOME is not running. + env_cmd = '. /usr/local/lib/tails-shell-library/gnome.sh && ' + \ + 'export_gnome_env ; ' + \ + 'env' + wrapped_env_cmd = "su -c '{}' {}".format(env_cmd, user) + pipe = subprocess.Popen(wrapped_env_cmd, stdout=subprocess.PIPE, shell=True) + env_data = pipe.communicate()[0].decode('utf-8') + return dict((line.split('=', 1) for line in env_data.splitlines())) + + +# Dogtail does not seem to support the root user interacting with +# other users' applications, and it does not support Python 3 (which +# this script is written in) so let's wrap around an interactive +# Python shell started as a subprocess. +class PythonSession: + def __init__(self, user = None): + interactive_shell_code = '; '.join([ + "import sys", + "import code", + "sys.ps1 = ''", + "sys.ps2 = ''", + "code.interact(banner='')", + ]) + if not user: + user = pwd.getpwuid(os.getuid()).pw_name + env = get_user_env(user) + cwd = env['HOME'] + self.process = subprocess.Popen( + ["python2", "-u", "-c", interactive_shell_code], + bufsize = 0, + shell=False, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + cwd=cwd, + preexec_fn=mk_switch_user_fn(user) + ) + init_code = """ + import cStringIO + import json + import sys + orig_stdout = sys.stdout + orig_stderr = sys.stderr + """.replace(' ', '').lstrip() + self.process.stdin.write(init_code.encode()) + self.process.stdin.flush() + + def execute(self, code): + # This wrapping ensures that we can run almost any reasonable + # code and capture what it does. + wrapper = """ + fake_stdout = cStringIO.StringIO() + fake_stderr = cStringIO.StringIO() + sys.stdout = fake_stdout + sys.stderr = fake_stderr + exc = None + try: + {code} + except Exception as e: + exc = '%s: %s' % (type(e).__name__, str(e)) + # This newline is needed to end the `try` statement. + + sys.stdout = orig_stdout + sys.stderr = orig_stderr + out_data = fake_stdout.getvalue() + err_data = fake_stderr.getvalue() + fake_stdout.close() + fake_stderr.close() + print(json.dumps([exc, out_data, err_data])) + """.replace(' ', '').lstrip() + indented_code = textwrap.indent(code, prefix=' '*4) + wrapped_code = wrapper.format(code=indented_code) + self.process.stdin.write(wrapped_code.encode()) + self.process.stdin.flush() + return str(self.process.stdout.readline().strip(), 'utf-8') + + +def run_cmd_as_user(cmd, user): + switch_user_fn = mk_switch_user_fn(user) + env = get_user_env(user) + cwd = env['HOME'] + return subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=True, env=env, cwd=cwd, preexec_fn=switch_user_fn + ) + + +def main(): + port = serial.Serial(port = REMOTE_SHELL_DEV, baudrate = 4000000) + python_sessions = dict() + + # Notify systemd that we're ready + systemd.daemon.notify('READY=1') + systemd.daemon.notify('STATUS=Processing requests...\n') + + while True: + line = port.readline().decode('utf-8') + try: + id, cmd_type, *rest = json.loads(line) + ret = "" + if cmd_type in ['sh_call', 'sh_spawn']: + user, cmd = rest + p = run_cmd_as_user(cmd, user) + if cmd_type == "sh_spawn": + returncode, stdout, stderr = 0, "", "" + else: + stdout_b, stderr_b = p.communicate() + stdout = stdout_b.decode('utf-8') + stderr = stderr_b.decode('utf-8') + returncode = p.returncode + ret = json.dumps([id, 'success', returncode, stdout, stderr]) + elif cmd_type == 'python_execute': + user, code = rest + if user not in python_sessions: + python_sessions[user] = PythonSession(user) + session = python_sessions[user] + result_str = session.execute(code) + result = json.loads(result_str) + ret = json.dumps([id, 'success'] + result) + elif cmd_type in ['file_read', 'file_write', 'file_append']: + path, *rest = rest + open_mode = cmd_type[5] + 'b' + with open(path, open_mode) as f: + if cmd_type == 'file_read': + assert(rest == []) + ret = str(base64.b64encode(f.read()), 'utf-8') + elif cmd_type in ['file_write', 'file_append']: + assert(len(rest) == 1) + data = base64.b64decode(rest[0]) + ret = f.write(data) + if ret != len(data): + raise IOError("we only wrote {} bytes out of {}" + .format(ret, len(data))) + ret = json.dumps([id, 'success'] + [ret]) + else: + raise ValueError("unknown command type") + response = (ret + "\n").encode('utf-8') + port.write(response) + port.flush() + except Exception as e: + print("Error caught while processing line:", file=sys.stderr) + print(" " + line, file=sys.stderr) + print("The error was:", file=sys.stderr) + traceback.print_exc(file=sys.stdout) + print("-----", file=sys.stderr) + sys.stderr.flush() + exc_str = '{}: {}'.format(type(e).__name__, str(e)) + port.write(json.dumps([id, 'error', exc_str]).encode('utf-8') + b"\n") + port.flush() + continue + +if __name__ == "__main__": + main() diff --git a/config/chroot_local-includes/usr/local/lib/tails-boot-device-can-have-persistence b/config/chroot_local-includes/usr/local/lib/tails-boot-device-can-have-persistence new file mode 100755 index 0000000000000000000000000000000000000000..4ff759f99584340e867928579d223c489df84eb5 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-boot-device-can-have-persistence @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +=head1 NAME + +tails-boot-device-can-have-persistence - test if the boot device is supported for persistence + +=cut + +use strictures 2; +use 5.10.1; + +use FindBin; +use lib "$FindBin::Bin/../lib"; + +use Tails::RunningSystem; + +my $running_system = Tails::RunningSystem->new; + +if (! $running_system->started_from_writable_device) { + say STDERR "Tails was started from a DVD or a read-only device"; + exit 16; +} + +if (! $running_system->started_from_device_installed_with_tails_installer) { + say STDERR "The boot device was not created using Tails Installer"; + exit 32; +} + +exit 0; diff --git a/config/chroot_local-includes/usr/local/lib/tails-configure-keyboard b/config/chroot_local-includes/usr/local/lib/tails-configure-keyboard new file mode 100755 index 0000000000000000000000000000000000000000..c25119c42b93c807604f8292762499c2ae75b79d --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-configure-keyboard @@ -0,0 +1,57 @@ +#!/bin/sh + +set -e +set -u + +# Get $XKBMODEL, $XKBLAYOUT, $XKBVARIANT and $XKBOPTIONS +. /var/lib/tails-user-session/keyboard + +if [ -z "${XKBVARIANT:-}" ] ; then + XKBCONF="$XKBLAYOUT" +else + XKBCONF="$XKBLAYOUT+$XKBVARIANT" +fi + +# Choose the keyboard layout we'll use regardless of the IBus input methods +if [ "$XKBLAYOUT" = 'us' ] ; then + SOURCES="('xkb', '$XKBCONF')" +else + SOURCES="('xkb', '$XKBCONF'), ('xkb', 'us')" +fi + +# Choose preferred IBus input methods +LANGPREFIX=`echo "$LANG" | sed 's/_.*//'` +case "$LANGPREFIX" in + ja) + PRELOAD="['anthy', 'libpinyin', 'hangul', 'Unikey', 'chewing']" + SOURCES="[$SOURCES, ('ibus', 'anthy'), ('ibus', 'libpinyin'), ('ibus', 'chewing'), ('ibus', 'hangul'), ('ibus', 'Unikey')]" + ;; + ko) + PRELOAD="['hangul', 'libpinyin', 'anthy', 'Unikey', 'chewing']" + SOURCES="[$SOURCES, ('ibus', 'hangul'), ('ibus', 'libpinyin'), ('ibus', 'chewing'), ('ibus', 'anthy'), ('ibus', 'Unikey')]" + ;; + vi) + PRELOAD="['Unikey', 'hangul', 'libpinyin', 'anthy', 'chewing']" + SOURCES="[$SOURCES, ('ibus', 'Unikey'), ('ibus', 'hangul'), ('ibus', 'libpinyin'), ('ibus', 'chewing'), ('ibus', 'anthy')]" + ;; + zh) + PRELOAD="['libpinyin', 'chewing', 'anthy', 'hangul', 'Unikey']" + SOURCES="[$SOURCES, ('ibus', 'libpinyin'), ('ibus', 'chewing'), ('ibus', 'anthy'), ('ibus', 'hangul'), ('ibus', 'Unikey')]" + ;; + *) + PRELOAD="['libpinyin', 'anthy', 'hangul', 'Unikey', 'chewing']" + SOURCES="[$SOURCES, ('ibus', 'libpinyin'), ('ibus', 'anthy'), ('ibus', 'hangul'), ('ibus', 'Unikey'), ('ibus', 'chewing')]" + ;; +esac + +# Configure enabled input methods and their preferred order +dconf write /desktop/ibus/general/preload-engines "$PRELOAD" +dconf write /org/gnome/desktop/input-sources/sources "$SOURCES" +if [ -n "${XKBOPTIONS:-}" ] ; then + dconf write /org/gnome/desktop/input-sources/xkb-options "$XKBOPTIONS" +fi + +# Export environment variables to enable use of IBus +export GTK_IM_MODULE='ibus' +export QT_IM_MODULE='ibus' +export XMODIFIERS='@im=ibus' diff --git a/config/chroot_local-includes/usr/local/lib/tails-htp-notify-user b/config/chroot_local-includes/usr/local/lib/tails-htp-notify-user new file mode 100755 index 0000000000000000000000000000000000000000..afa90d6c2f65fbbc79db8e8ed05ba556b0509f35 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-htp-notify-user @@ -0,0 +1,93 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use 5.10.1; + +#man{{{ + +=head1 NAME + +tails-htp-notify-user + +=head1 VERSION + +Version X.XX + +=head1 AUTHOR + +Tails dev team +See https://tails.boum.org/. + +=cut + +#}}} + +use Data::Dumper; +use Desktop::Notify; +use English '-no_match_vars'; +use Locale::gettext; +use POSIX; + +### initialization +setlocale(LC_MESSAGES, ""); +textdomain("tails"); +my $htp_done_file = '/run/htpdate/done'; +my $htp_success_file = '/run/htpdate/success'; +my $htp_log_file = '/var/log/htpdate.log'; +my $debug; + +### subroutines + +sub debug { say STDERR $_[0] if $debug; } + +### main + +exit 0 if -e $htp_success_file; + +my $notify = Desktop::Notify->new() + or die "Failed creating Desktop::Notify object."; +debug('$notify:' . "\n" . Dumper($notify)); + +my $summary = gettext("Synchronizing the system's clock"); +my $body = gettext("Tor needs an accurate clock to work properly, especially for Hidden Services. Please wait..."); + +my $notification = $notify->create(summary => $summary, + body => $body, + timeout => 0) + or die "Failed to create notification object"; +debug('$notification:' . "\n" . Dumper($notification)); + +# Wait until notifications can be shown +until (system("pidof", "ibus-daemon") == 0) { + sleep 1 +} + +$notification->show() or warn "Failed showing notification."; + +# Wait until htpdate is done +until ( -e $htp_done_file ) { + sleep 1; +} + +$notification->close(); + +# in case htpdate failed, notify the user with the corresponding logs +unless (-e $htp_success_file) { + open(my $htp_log, '<', $htp_log_file) + or die "Can not open file '$htp_log_file': $OS_ERROR"; + my $last_log; + while (<$htp_log>) { + if ($_ =~ /^Running htpdate\./) { + $last_log = ''; + next; + } + $last_log .= $_; + } + my $failure_summary = gettext("Failed to synchronize the clock!"); + my $failure_body = $last_log; + my $failure_notification = $notify->create(summary => $failure_summary, + body => $failure_body, + timeout => 0); + $failure_notification->show(); +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-set-wireless-devices-state b/config/chroot_local-includes/usr/local/lib/tails-set-wireless-devices-state new file mode 100755 index 0000000000000000000000000000000000000000..bf23d2e3ebaf6c06e036b46b8b77a71b6713681a --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-set-wireless-devices-state @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +[ -e /dev/rfkill ] || exit 0 + +rfkill block all + +for devtype in wifi wwan wimax ; do + rfkill unblock "$devtype" +done diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/build.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..baaf5468a2709c343ed0c8375325f44ba9627482 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/build.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +# Import is_package_installed +. /usr/local/lib/tails-shell-library/common.sh + +strip_nondeterminism_wrapper() { + apt-get --yes install strip-nondeterminism + strip-nondeterminism "${@}" + apt-get --yes purge strip-nondeterminism '^libfile-stripnondeterminism-perl' +} + +# Ensure that the packages whose names are passed as arguments are +# installed. If they are installed now, they will be marked as +# "automatically installed" so the next `apt-get autoremove` action +# *unless* they are later explicitly installed (or other packages +# depends on them). +ensure_hook_dependency_is_installed() { + # Filter out already installed packages from $@. + for p in "${@}"; do + shift + if ! echo "${p}" | grep -q --extended-regexp '^[a-z0-9.+-]+$'; then + echo "ensure_hook_dependency_is_installed():" \ + "doesn't look like a package name: ${p}" >&2 + exit 1 + fi + if is_package_installed "${p}"; then + continue + fi + set -- "${@}" "${p}" + done + if [ -z "${*}" ]; then + return + fi + apt-get install --yes "${@}" + apt-mark auto "${@}" +} + +install_fake_package() { + local name version section provides tmp control_file + name="${1}" + version="${2}" + section="${3:-misc}" + provides="${4:-}" + ensure_hook_dependency_is_installed equivs + tmp="$(mktemp -d)" + control_file="${tmp}/${name}_${version}.control" + cat > "${control_file}" << EOF +Section: ${section} +Priority: optional +Homepage: https://tails.boum.org/ +Standards-Version: 3.9.6 + +Package: ${name} +Version: ${version} +Maintainer: Tails developers +Architecture: all +Provides: ${provides} +Description: (Fake) ${name} + Dummy packaged used to meet some dependency without installing the + real ${name} package. +EOF + ( + cd "${tmp}" + equivs-build "${control_file}" + dpkg -i "${tmp}/${name}_${version}_all.deb" + ) + rm -R "${tmp}" +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/chroot-browser.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/chroot-browser.sh new file mode 100644 index 0000000000000000000000000000000000000000..3deed22908a7eaadee739b5abd7224671cc34c0e --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/chroot-browser.sh @@ -0,0 +1,277 @@ +#!/bin/sh + +# This shell library is meant to be used with `set -e`. + +if [ "$(whoami)" != "root" ]; then + echo "This library is useless for non-root users. Exiting..." >&2 + exit 1 +fi + +# Import the TBB_INSTALL, TBB_PROFILE and TBB_EXT variables, and +# configure_xulrunner_app_locale(). +. /usr/local/lib/tails-shell-library/tor-browser.sh + +# Import try_for(). +. /usr/local/lib/tails-shell-library/common.sh + +# Break down the chroot and kill all of its processes +try_cleanup_browser_chroot () { + local chroot="${1}" + local cow="${2}" + local user="${3}" + try_for 10 "pkill -u ${user} 1>/dev/null 2>&1" 0.1 || \ + pkill -9 -u "${user}" || : + # findmnt sorts submounts so we just have to revert the list to + # have the proper umount order. We use `tail` to suppress the + # "TARGET" column header. + local chroot_mounts="$( + findmnt --output TARGET --list --submounts "${chroot}" | tail -n+2 | tac + )" + for mnt in ${chroot_mounts} "${cow}"; do + try_for 10 "umount ${mnt} 2>/dev/null" 0.1 + done + rmdir "${cow}" "${chroot}" +} + +# Setup a chroot on a clean aufs "fork" of the root filesystem. +setup_chroot_for_browser () { + local chroot="${1}" + local cow="${2}" + local user="${3}" + + # FIXME: When LXC matures to the point where it becomes a viable option + # for creating isolated jails, the chroot can be used as its rootfs. + + local cleanup_cmd="try_cleanup_browser_chroot \"${chroot}\" \"${cow}\" \"${user}\"" + trap "${cleanup_cmd}" INT EXIT + + local rootfs_dir + local rootfs_dirs_path="/lib/live/mount/rootfs" + local tails_module_path="/lib/live/mount/medium/live/Tails.module" + local aufs_dirs= + + # We have to pay attention to the order we stack the filesystems; + # newest must be first, and remember that the .module file lists + # oldest first, newest last. + while read rootfs_dir; do + rootfs_dir="${rootfs_dirs_path}/${rootfs_dir}" + mountpoint -q "${rootfs_dir}" && \ + aufs_dirs="${rootfs_dir}=rr+wh:${aufs_dirs}" + done < "${tails_module_path}" + # But our copy-on-write dir must be at the very top. + aufs_dirs="${cow}=rw:${aufs_dirs}" + + mkdir -p "${cow}" "${chroot}" && \ + mount -t tmpfs tmpfs "${cow}" && \ + mount -t aufs -o "noatime,noxino,dirs=${aufs_dirs}" aufs "${chroot}" && \ + mount -t proc proc "${chroot}/proc" && \ + mount --bind "/dev" "${chroot}/dev" && \ + mount -t tmpfs -o rw,nosuid,nodev tmpfs "${chroot}/dev/shm" || \ + return 1 + + # Workaround for #6110 + chmod -t "${cow}" +} + +browser_conf_dir () { + local browser_name="${1}" + local browser_user="${2}" + echo "/home/${browser_user}/.${browser_name}" +} + +browser_profile_dir () { + local conf_dir="$(browser_conf_dir "${@}")" + echo "${conf_dir}/profile.default" +} + +chroot_browser_conf_dir () { + local chroot="${1}"; shift + echo "${chroot}/$(browser_conf_dir "${@}")" +} + +chroot_browser_profile_dir () { + local conf_dir="$(chroot_browser_conf_dir "${@}")" + echo "${conf_dir}/profile.default" +} + +set_chroot_browser_permissions () { + local chroot="${1}" + local browser_name="${2}" + local browser_user="${3}" + local browser_conf="$(chroot_browser_conf_dir "${chroot}" "${browser_name}" "${browser_user}")" + chown -R "${browser_user}:${browser_user}" "${browser_conf}" +} + +configure_chroot_browser_profile () { + local chroot="${1}" ; shift + local browser_name="${1}" ; shift + local browser_user="${1}" ; shift + local home_page="${1}" ; shift + # Now $@ is a list of paths (that must be valid after chrooting) + # to extensions to enable. + + # Prevent sudo from complaining about failing to resolve the 'amnesia' host + echo "127.0.0.1 localhost amnesia" > "${chroot}/etc/hosts" + + # Create a fresh browser profile for the clearnet user + local browser_profile="$(chroot_browser_profile_dir "${chroot}" "${browser_name}" "${browser_user}")" + local browser_ext="${browser_profile}/extensions" + mkdir -p "${browser_profile}" "${browser_ext}" + + # Select extensions to enable + local extension + while [ -n "${*:-}" ]; do + extension="${1}" ; shift + ln -s "${extension}" "${browser_ext}" + done + + # Set preferences + local browser_prefs="${browser_profile}/user.js" + local chroot_browser_config="/usr/share/tails/chroot-browsers" + cat "${chroot_browser_config}/common/prefs.js" \ + "${chroot_browser_config}/${browser_name}/prefs.js" > "${browser_prefs}" + + # Set browser home page to something that explains what's going on + if [ -n "${home_page:-}" ]; then + echo 'user_pref("browser.startup.homepage", "'"${home_page}"'");' >> \ + "${browser_prefs}" + fi + + # Set an appropriate theme + cat "${chroot_browser_config}/${browser_name}/theme.js" >> "${browser_prefs}" + + # Customize the GUI. + local browser_chrome="${browser_profile}/chrome/userChrome.css" + mkdir -p "$(dirname "${browser_chrome}")" + cat "${chroot_browser_config}/common/userChrome.css" \ + "${chroot_browser_config}/${browser_name}/userChrome.css" >> \ + "${browser_chrome}" + + set_chroot_browser_permissions "${chroot}" "${browser_name}" "${browser_user}" +} + +set_chroot_browser_locale () { + local chroot="${1}" + local browser_name="${2}" + local browser_user="${3}" + local locale="${4}" + local browser_profile="$(chroot_browser_profile_dir "${chroot}" "${browser_name}" "${browser_user}")" + configure_xulrunner_app_locale "${browser_profile}" "${locale}" +} + +# Must be called after configure_chroot_browser_profile(), since it +# depends on which extensions are installed in the profile. +set_chroot_browser_name () { + local chroot="${1}" + local human_readable_name="${2}" + local browser_name="${3}" + local browser_user="${4}" + local locale="${5}" + local ext_dir="${chroot}/${TBB_EXT}" + local browser_profile_ext_dir="$(chroot_browser_profile_dir "${chroot}" "${browser_name}" "${browser_user}")/extensions" + + # If Torbutton is installed in the browser profile, it will decide + # the browser name. + if [ -e "${browser_profile_ext_dir}/torbutton@torproject.org" ]; then + local torbutton_locale_dir="${ext_dir}/torbutton/chrome/locale/${locale}" + if [ ! -d "${torbutton_locale_dir}" ]; then + # Surprisingly, the default locale is en, not en-US + torbutton_locale_dir="${chroot}/usr/share/xul-ext/torbutton/chrome/locale/en" + fi + sed -i "s/<"'!'"ENTITY\s\+brand\(Full\|Short\|Shorter\)Name.*$/<"'!'"ENTITY brand\1Name \"${human_readable_name}\">/" "${torbutton_locale_dir}/brand.dtd" + # Since Torbutton decides the name, we don't have to mess with + # with the browser's own branding, which will save time and + # memory. + return + fi + + local pack top rest + if [ "${locale}" != "en-US" ]; then + pack="${ext_dir}/langpack-${locale}@firefox.mozilla.org.xpi" + top="browser/chrome" + rest="${locale}/locale" + else + pack="${chroot}/${TBB_INSTALL}/browser/omni.ja" + top="chrome" + rest="en-US/locale" + fi + local tmp="$(mktemp -d)" + local branding_dtd="${top}/${rest}/branding/brand.dtd" + local branding_properties="${top}/${rest}/branding/brand.properties" + 7z x -o"${tmp}" "${pack}" "${branding_dtd}" "${branding_properties}" + sed -i "s/<"'!'"ENTITY\s\+brand\(Full\|Short\|Shorter\)Name.*$/<"'!'"ENTITY brand\1Name \"${human_readable_name}\">/" "${tmp}/${branding_dtd}" + perl -pi -E \ + 's/^(brand(?:Full|Short|Shorter)Name=).*$/$1'"${human_readable_name}/" \ + "${tmp}/${branding_properties}" + (cd ${tmp} ; 7z u -tzip "${pack}" .) + chmod a+r "${pack}" + rm -Rf "${tmp}" +} + +delete_chroot_browser_searchplugins() { + local chroot="${1}" + local locale="${2}" + local ext_dir="${chroot}/${TBB_EXT}" + + if [ "${locale}" != "en-US" ]; then + pack="${ext_dir}/langpack-${locale}@firefox.mozilla.org.xpi" + top="browser/chrome" + rest="${locale}/locale" + else + pack="${chroot}/${TBB_INSTALL}/browser/omni.ja" + top="chrome" + rest="en-US/locale" + fi + local searchplugins_dir="${top}/${rest}/browser/searchplugins" + local searchplugins_list="${searchplugins_dir}/list.json" + local tmp="$(mktemp -d)" + ( + cd "${tmp}" + 7z x -tzip "${pack}" "${searchplugins_dir}" + ls "${searchplugins_dir}"/*.xml | xargs 7z d -tzip "${pack}" + echo '{"default": {"visibleDefaultEngines": []}, "experimental-hidden": {"visibleDefaultEngines": []}}' \ + > "${searchplugins_list}" + 7z u -tzip "${pack}" "${searchplugins_list}" + ) + rm -r "${tmp}" + chmod a+r "${pack}" +} + +configure_chroot_browser () { + local chroot="${1}" ; shift + local browser_user="${1}" ; shift + local browser_name="${1}" ; shift + local human_readable_name="${1}" ; shift + local home_page="${1}" ; shift + # Now $@ is a list of paths (that must be valid after chrooting) + # to extensions to enable. + local best_locale="$(guess_best_tor_browser_locale)" + + configure_chroot_browser_profile "${chroot}" "${browser_name}" \ + "${browser_user}" "${home_page}" "${@}" + set_chroot_browser_locale "${chroot}" "${browser_name}" "${browser_user}" \ + "${best_locale}" + set_chroot_browser_name "${chroot}" "${human_readable_name}" \ + "${browser_name}" "${browser_user}" "${best_locale}" + delete_chroot_browser_searchplugins "${chroot}" "${best_locale}" + set_chroot_browser_permissions "${chroot}" "${browser_name}" \ + "${browser_user}" +} + +# Start the browser in the chroot +run_browser_in_chroot () { + local chroot="${1}" + local browser_name="${2}" + local chroot_user="${3}" + local local_user="${4}" + local wm_class="${5}" + local profile="$(browser_profile_dir ${browser_name} ${chroot_user})" + + sudo -u "${local_user}" xhost "+SI:localuser:${chroot_user}" + chroot "${chroot}" sudo -u "${chroot_user}" /bin/sh -c \ + ". /usr/local/lib/tails-shell-library/tor-browser.sh && \ + exec_firefox -DISPLAY='${DISPLAY}' \ + --class='${wm_class}' \ + -profile '${profile}'" + sudo -u "${local_user}" xhost "-SI:localuser:${chroot_user}" +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/common.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/common.sh new file mode 100644 index 0000000000000000000000000000000000000000..b90504f18c024880279a48212621f358e8ef477e --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/common.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Get monotonic time in seconds. See clock_gettime(2) for details. +# Note: we limit ourselves to seconds simply because floating point +# arithmetic is a PITA in the shell. +clock_gettime_monotonic() { + perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC \ + -E 'say int(clock_gettime(CLOCK_MONOTONIC))' +} + +# Run `check_expr` until `timeout` seconds has passed, and sleep +# `delay` (optional, defaults to 1) seconds in between the calls. +# Note that execution isn't aborted exactly after `timeout` +# seconds. In the worst case (the timeout happens right after we check +# if the timeout has happened) we'll wait in total: `timeout` seconds + +# `delay` seconds + the time needed for `check_expr`. +wait_until() { + local timeout check_expr delay timeout_at + timeout="${1}" + check_expr="${2}" + delay="${3:-1}" + timeout_at=$(expr $(clock_gettime_monotonic) + ${timeout}) + until eval "${check_expr}"; do + if [ "$(clock_gettime_monotonic)" -ge "${timeout_at}" ]; then + return 1 + fi + sleep ${delay} + done + return 0 +} + +# Just an alias. The second argument (wait_until()'s check_expr) is +# the "try code block". Just like in `wait_until()`, the timeout isn't +# very accurate. +try_for() { + wait_until "${@}" +} + +# Runs the wrapped command while temporarily disabling `set -e`, if +# enabled. It will always return 0 to not make scripts with `set -e` +# enabled abort but will instead store the wrapped command's return +# value into the global variable _NO_ABORT_RET. +no_abort() { + local set_e_was_enabled + if echo "${-}" | grep -q 'e'; then + set +e + set_e_was_enabled=true + else + set_e_was_enabled=false + fi + "${@}" + _NO_ABORT_RET=${?} + if [ "${set_e_was_enabled}" = true ]; then + set -e + fi + return 0 +} + +is_package_installed() { + local package_name package_status + package_name="${1}" + package_status="$(no_abort dpkg-query --show \ + --showformat='${db:Status-Status}' "${package_name}" \ + 2>/dev/null)" + [ "${package_status}" = "installed" ] +} + +extract_from_file_between_markers () { + local file start stop + file="${1}" + start="${2}" + stop="${3}" + awk "/${start}/ { between=1; next; } + /${stop}/ { between=0; } + { if (between) { print; } }" \ + "${file}" +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/gnome.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/gnome.sh new file mode 100644 index 0000000000000000000000000000000000000000..da390d3b0ca7480b7a3f2663c992b5d6c6abe57a --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/gnome.sh @@ -0,0 +1,18 @@ +GNOME_ENV_VARS=" +DBUS_SESSION_BUS_ADDRESS +DISPLAY +XAUTHORITY +XDG_RUNTIME_DIR +" + +export_gnome_env() { + # Get LIVE_USERNAME + . /etc/live/config.d/username.conf + local gnome_shell_pid="$(pgrep --newest --euid ${LIVE_USERNAME} gnome-shell)" + local tmp_env_file="$(tempfile)" + local vars="($(echo ${GNOME_ENV_VARS} | tr ' ' '|'))" + tr '\0' '\n' < "/proc/${gnome_shell_pid}/environ" | \ + grep -E "^${vars}=" > "${tmp_env_file}" + while read line; do export "${line}"; done < "${tmp_env_file}" + rm "${tmp_env_file}" +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/hardware.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/hardware.sh new file mode 100644 index 0000000000000000000000000000000000000000..821ec4777daa4f3dd3a1a04928b9b85a1f8a70f1 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/hardware.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +get_all_ethernet_nics() { + for i in /sys/class/net/*; do + # type = 1 means ethernet (ARPHDR_ETHER, see Linux' sources, + # beginning of include/linux/if_arp.h) + if [ "$(cat "${i}"/type)" = 1 ]; then + basename "${i}" + fi + done +} + +nic_exists() { + [ -e /sys/class/net/"${1}" ] +} + +nic_is_up() { + [ "$(cat /sys/class/net/"${1}"/operstate)" = "up" ] +} + +# The following "nic"-related functions require that the argument is a +# NIC that exists + +nic_ipv4_addr() { + ip addr show "${1}" | sed -n 's,^\s*inet \([0-9\.]\+\)/.*$,\1,p' +} + +nic_ipv6_addr() { + ip addr show "${1}" | sed -n 's,^\s*inet6 \([0-9a-fA-F:]\+\)/.*$,\1,p' +} + +# Will just output nothing on failure +get_current_mac_of_nic() { + local mac + mac="$(macchanger "${1}" | sed -n "s/^Current\s*MAC:\s*\([0-9a-f:]\+\)\s.*$/\1/p" || :)" + if echo "${mac}:" | grep -q "^\([0-9a-fA-F]\{2\}:\)\{6\}$"; then + echo "${mac}" + fi +} + +get_module_used_by_nic() { + basename "$(readlink "/sys/class/net/${1}/device/driver/module")" +} + +get_name_of_nic() { + vendor=$(sed 's/^0x\(.*\)$/\1/' "/sys/class/net/${1}/device/vendor") + device=$(sed 's/^0x\(.*\)$/\1/' "/sys/class/net/${1}/device/device") + lspci -nn | sed -n "s/^\S\+\s\+[^:]\+:\s\+\(.*\)\s\+\[$vendor:$device\].*$/\1/p" +} + +# Auxillary function for mod_rev_dep(). It recurses over the graph of +# kernel module depencies of $@ (note that it only works for loaded +# modules). To deal with circular dependencies a global variable +# MOD_REV_DEP_VISITED keeps track of already visited nodes, and it +# should be unset before the first call of this function. +mod_rev_dep_aux() { + local mod + local rev_deps + for mod in ${@}; do + if echo ${MOD_REV_DEP_VISITED} | grep -qw ${mod}; then + continue + fi + MOD_REV_DEP_VISITED="${MOD_REV_DEP_VISITED} ${mod}" + # extract the "Used by" column for $mod from lsmod + rev_deps=$(lsmod | \ + sed -n "s/^${mod}\s\+\S\+\s\+\S\+\s\+\(\S\+\)/\1/p" | \ + tr ',' ' ') + mod_rev_dep_aux ${rev_deps} + echo ${mod} + done +} + +# Prints a list of all loaded modules depending on $1, including $1. It's +# ordered by descending "maximum dependency distance" from $1, so the +# output is ideal if we want to unload $1 and (by necessity) all +# modules that uses $1. +mod_rev_dep() { + MOD_REV_DEP_VISITED="" + mod_rev_dep_aux ${1} +} + +# Unloads module $1, and all modules that (transatively) depends on +# $1 (i.e. its reverse dependencies). +unload_module_and_rev_deps() { + /sbin/modprobe -r $(mod_rev_dep ${1}) +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/localization.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/localization.sh new file mode 100644 index 0000000000000000000000000000000000000000..df7dd7c26d5f30bf70118990f2137a7cd262c313 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/localization.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# Extracts the language part of a given locale, e.g. "en_US.UTF-8" +# yields "en". Often $LANG will be passed as the argument. +language_code_from_locale () { + echo "${1}" | sed "s,\(_\|\.\).*$,," +} + +# Prints the path to the localized (according to the environment's +# LANG) version of `page` in the local copy of Tails' website. `page` +# should specify only the name of the page, not the language code (of +# course!) or the ".html" extension. If a localized page doesn't exist +# the default is the English version. +localized_tails_doc_page () { + local page="${1}" + local lang_code="$(language_code_from_locale "${LANG}")" + local try_page + for locale in "${lang_code}" "en"; do + try_page="${page}.${locale}.html" + if [ -r "${try_page}" ]; then + echo "${try_page}" + return 0 + fi + done + return 1 +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/log.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/log.sh new file mode 100644 index 0000000000000000000000000000000000000000..6d677371dcadc6ace23f565591ca1aef58b8d47e --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/log.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +warn() { + echo "$*" >&2 +} + +die() { + warn "$*" + exit 1 +} + +# Shouldn't be used in shell libraries; a script including such a +# library would overwrite the library's log tag. +set_log_tag() { + _LOG_TAG=$1 +} + +log() { + if [ "${_LOG_TAG}" ]; then + logger -t "${_LOG_TAG}" "$*" || : + else + logger "$*" || : + fi +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh new file mode 100644 index 0000000000000000000000000000000000000000..bb041f5706e4b4942f6524ecd25ee1c50562aae5 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh @@ -0,0 +1,40 @@ +# This shell library is meant to be used with `set -e` and `set -u`. + +po_languages () { + for po in po/*.po ; do + rel="${po%.po}" + echo "${rel#po/}" + done +} + +diff_without_pot_creation_date () { + diff --ignore-matching-lines '^"POT-Creation-Date:' "${@}" +} + +diff_without_pot_creation_date_and_comments () { + diff --ignore-matching-lines '^"POT-Creation-Date:' \ + --ignore-matching-lines '^#: .*:[0-9]\+$' "${@}" +} + +intltool_update_po () { + ( + cd po + for locale in "$@" ; do + intltool-update --dist --gettext-package=tails $locale -o ${locale}.po.new + + [ -f ${locale}.po ] || continue + [ -f ${locale}.po.new ] || continue + + if [ "${FORCE:-}" = yes ]; then + echo "Force-updating '${locale}.po'." + mv ${locale}.po.new ${locale}.po + elif diff_without_pot_creation_date -q "${locale}.po" "${locale}.po.new"; then + echo "${locale}: Only header changes in PO file: keeping the old one" + rm ${locale}.po.new + else + echo "${locale}: Real changes in PO file: switching to the updated one" + mv ${locale}.po.new ${locale}.po + fi + done + ) +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh new file mode 100644 index 0000000000000000000000000000000000000000..dc6cc26ce0cc5f676c6d89f77c161e85ac55d037 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +PERSISTENCE_STATE='/var/lib/live/config/tails.persistence' +PHYSICAL_SECURITY_SETTINGS='/var/lib/live/config/tails.physical_security' + +_get_tg_setting() { + if [ -r "${1}" ]; then + . "${1}" + eval "echo \${${2}:-}" + fi +} + +persistence_is_enabled() { + [ "$(_get_tg_setting "${PERSISTENCE_STATE}" TAILS_PERSISTENCE_ENABLED)" = true ] +} + +persistence_is_enabled_for() { + persistence_is_enabled && mountpoint -q "$1" 2>/dev/null +} + +persistence_is_enabled_read_write() { + persistence_is_enabled && \ + [ "$(_get_tg_setting "${PERSISTENCE_STATE}" TAILS_PERSISTENCE_READONLY)" != true ] +} + +mac_spoof_is_enabled() { + # Only return false when explicitly told so to increase failure + # safety. + [ "$(_get_tg_setting "${PHYSICAL_SECURITY_SETTINGS}" TAILS_MACSPOOF_ENABLED)" != false ] +} + +tails_netconf() { + _get_tg_setting "${PHYSICAL_SECURITY_SETTINGS}" TAILS_NETCONF +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor-browser.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor-browser.sh new file mode 100644 index 0000000000000000000000000000000000000000..71cdfe5e7607febdd017d823a964eadf438647a9 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor-browser.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +TBB_INSTALL=/usr/local/lib/tor-browser +TBB_PROFILE=/etc/tor-browser/profile +TBB_EXT=/usr/local/share/tor-browser-extensions +TOR_LAUNCHER_INSTALL=/usr/local/lib/tor-launcher-standalone +TOR_LAUNCHER_LOCALES_DIR="${TOR_LAUNCHER_INSTALL}/chrome/locale" + +# For strings it's up to the caller to add double-quotes ("") around +# the value. +set_mozilla_pref() { + local file name value prefix + file="${1}" + name="${2}" + value="${3}" + # Sometimes we might want to do e.g. user_pref + prefix="${4:-pref}" + [ -e "${file}" ] && sed -i "/^${prefix}(\"${name}\",/d" "${file}" + echo "${prefix}(\"${name}\", ${value});" >> "${file}" +} + +exec_firefox_helper() { + local binary="${1}"; shift + + export LD_LIBRARY_PATH="${TBB_INSTALL}" + export FONTCONFIG_PATH="${TBB_INSTALL}/TorBrowser/Data/fontconfig" + export FONTCONFIG_FILE="fonts.conf" + export GNOME_ACCESSIBILITY=1 + + # The Tor Browser often assumes that the current directory is + # where the browser lives, e.g. for the fixed set of fonts set by + # fontconfig above. + cd "${TBB_INSTALL}" + + # From start-tor-browser: + unset SESSION_MANAGER + + exec "${TBB_INSTALL}"/"${binary}" "${@}" +} + +exec_firefox() { + exec_firefox_helper firefox.real "${@}" +} + +exec_unconfined_firefox() { + exec_firefox_helper firefox-unconfined "${@}" +} + +guess_best_tor_browser_locale() { + local long_locale short_locale similar_locale + long_locale="$(echo ${LANG} | sed -e 's/\..*$//' -e 's/_/-/')" + short_locale="$(echo ${long_locale} | cut -d"-" -f1)" + if [ -e "${TBB_EXT}/langpack-${long_locale}@firefox.mozilla.org.xpi" ]; then + echo "${long_locale}" + return + elif [ -e "${TBB_EXT}/langpack-${short_locale}@firefox.mozilla.org.xpi" ]; then + echo "${short_locale}" + return + fi + # If we use locale xx-YY and there is no langpack for xx-YY nor xx + # there may be a similar locale xx-ZZ that we should use instead. + similar_locale="$(ls -1 "${TBB_EXT}" | \ + sed -n "s,^langpack-\(${short_locale}-[A-Z]\+\)@firefox.mozilla.org.xpi$,\1,p" | \ + head -n 1)" || : + if [ -n "${similar_locale:-}" ]; then + echo "${similar_locale}" + return + fi + + echo 'en-US' +} + +guess_best_tor_launcher_locale() { + local long_locale short_locale + long_locale="$(echo ${LANG} | sed -e 's/\..*$//' -e 's/_/-/')" + short_locale="$(echo ${long_locale} | cut -d"-" -f1)" + if [ -e "${TOR_LAUNCHER_LOCALES_DIR}/${long_locale}" ]; then + echo ${long_locale} + elif ls -1 "${TOR_LAUNCHER_LOCALES_DIR}" | grep -q "^${short_locale}\(-[A-Z]\+\)\?$"; then + # See comment in guess_best_firefox_locale() + echo ${short_locale} + else + echo en-US + fi +} + +configure_xulrunner_app_locale() { + local profile locale + profile="${1}" + locale="${2}" + mkdir -p "${profile}"/preferences + set_mozilla_pref "${profile}"/prefs.js \ + "intl.locale.requested" "\"${locale}\"" \ + "user_pref" +} + +configure_best_tor_browser_locale() { + local profile best_locale + profile="${1}" + best_locale="$(guess_best_tor_browser_locale)" + configure_xulrunner_app_locale "${profile}" "${best_locale}" + cat "/etc/tor-browser/locale-profiles/${best_locale}.js" \ + >> "${profile}/prefs.js" +} + +configure_best_tor_launcher_locale() { + configure_xulrunner_app_locale "${1}" "$(guess_best_tor_launcher_locale)" +} + +supported_tor_browser_locales() { + # The default is always supported + echo en-US + for langpack in "${TBB_EXT}"/langpack-*@firefox.mozilla.org.xpi; do + basename "${langpack}" | sed 's,^langpack-\([^@]\+\)@.*$,\1,' + done +} + +set_firefox_content_process_count() { + local profile="$1" + local count="$2" + + set_mozilla_pref "${profile}/prefs.js" \ + "dom.ipc.processCount" "$count" \ + user_pref +} + +configure_tor_browser_memory_usage() { + local profile="${1}" + + # Unit: KiB + system_ram=$(awk '/^MemTotal:/ { print $2 }' /proc/meminfo) + + if [ "$system_ram" -lt "$((3 * 1024 * 1024))" ]; then + set_firefox_content_process_count "$profile" 2 + fi +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor.sh new file mode 100755 index 0000000000000000000000000000000000000000..e2c0f5afe02e0175cfaba732e9caeebd068b44ed --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tor.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +TOR_RC_DEFAULTS=/usr/share/tor/tor-service-defaults-torrc +TOR_RC=/etc/tor/torrc +TOR_LOG=/var/log/tor/log +TOR_DIR=/var/lib/tor +TOR_DESCRIPTORS=${TOR_DIR}/cached-microdescs +NEW_TOR_DESCRIPTORS=${TOR_DESCRIPTORS}.new + +tor_rc_lookup() { + grep --no-filename "^${1}\s" "${TOR_RC_DEFAULTS}" "${TOR_RC}" | \ + sed --regexp-extended "s/^${1}\s+(.+)$/\1/" | tail -n1 +} + +tor_control_cookie_path() { + local path + path="$(tor_rc_lookup CookieAuthFile)" + [ -e "${path}" ] && echo "${path}" +} + +tor_control_send() { + local control_port cookie_path hexcookie + control_port="$(tor_rc_lookup ControlPort)" + cookie_path="$(tor_control_cookie_path)" + if [ -e "${cookie_path}" ] && [ -n "${control_port}" ]; then + hexcookie=$(xxd -c 32 -g 0 "${cookie_path}" | cut -d' ' -f2) + /bin/echo -ne "AUTHENTICATE ${hexcookie}\r\n${1}\r\nQUIT\r\n" | \ + /bin/nc 127.0.0.1 "${control_port}" | tr -d "\r" + else + return 1 + fi +} + +# Only handles GETINFO keys with single-line answers +tor_control_getinfo() { + tor_control_send "GETINFO ${1}" | \ + sed --regexp-extended -n "s|^250-${1}=(.*)$|\1|p" +} + +tor_control_getconf() { + tor_control_send "GETCONF ${1}" | \ + sed --regexp-extended -n "s|^250 ${1}=(.*)$|\1|p" +} + +tor_control_setconf() { + tor_control_send "SETCONF ${1}" >/dev/null +} + +tor_bootstrap_progress() { + local res + res=$(tor_control_getinfo status/bootstrap-phase | \ + sed --regexp-extended 's/^.* BOOTSTRAP PROGRESS=([[:digit:]]+) .*$/\1/') + echo ${res:-0} +} + +tor_is_working() { + [ "$(tor_bootstrap_progress)" -eq 100 ] +} + +tor_append_to_torrc () { + echo "${@}" >> "${TOR_RC}" +} + +# Set a (possibly existing) option $1 to $2 in torrc. Shouldn't be +# used for options that can be set multiple times (e.g. the listener +# options). Does not support configuration entries split into multiple +# lines (with the backslash character). +tor_set_in_torrc () { + sed -i "/^${1}\s/d" "${TOR_RC}" + tor_append_to_torrc "${1} ${2}" +} diff --git a/config/chroot_local-includes/usr/local/lib/tails-spoof-mac b/config/chroot_local-includes/usr/local/lib/tails-spoof-mac new file mode 100755 index 0000000000000000000000000000000000000000..b43811cd33400cb9ce471f936913afcf2246f466 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-spoof-mac @@ -0,0 +1,155 @@ +#!/bin/sh + +set -e +set -u + +# This script spoofs or resets the MAC address of all NICs given as +# arguments according to the setting in Tails Greeter. The default (i.e +# before Tails Greeter has been run) is to enable MAC spoofing. + +. /usr/local/lib/tails-shell-library/hardware.sh +. /usr/local/lib/tails-shell-library/log.sh +. /usr/local/lib/tails-shell-library/tails-greeter.sh + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +. /usr/bin/gettext.sh +TEXTDOMAIN="tails" +export TEXTDOMAIN + +stop_and_disable_NM() { + for s in NetworkManager-dispatcher.service \ + NetworkManager-wait-online.service \ + NetworkManager.service; do + systemctl stop "${s}" + systemctl disable "${s}" + systemctl mask "${s}" + done + log "Networking disabled" +} + +show_notification() { + # We must wait until all the facilities necessary for showing the + # notification to the Live user is available to prevent it from + # getting lost. + until pgrep -u "${LIVE_USERNAME}" '^ibus-daemon' >/dev/null ; do + sleep 1 + done + # The above doesn't seem to be enough. The best we can do seems to + # be to statically wait a bit longer. The amount chosen is just + # arbitrarily picked, and may not work on slow hardware or even + # DVD boot, but should at least work in our automated test suite. + sleep 10 + /usr/local/sbin/tails-notify-user "${1}" "${2}" 0 +} + +notify_panic_success() { + local nic + local nic_name + nic="${1}" + nic_name="${2}" + show_notification "`gettext \"Network card \\\${nic} disabled\"`" \ +"`eval_gettext \"MAC spoofing failed for network card \\\${nic_name} (\\\${nic}) so it is temporarily disabled. +You might prefer to restart Tails and disable MAC spoofing.\"`" +} + +notify_panic_failure() { + local nic + local nic_name + nic="${1}" + nic_name="${2}" + show_notification "`gettext \"All networking disabled\"`" \ +"`eval_gettext \"MAC spoofing failed for network card \\\${nic_name} (\\\${nic}). The error recovery also failed so all networking is disabled. +You might prefer to restart Tails and disable MAC spoofing.\"`" +} + +mac_spoof_panic() { + local nic + local module + local nic_name + local unload_success + nic=${1} + if ! /sbin/ip link set dev "${nic}" down; then + log "Failed to down NIC ${nic} in panic mode." + fi + module=$(get_module_used_by_nic "${nic}") + nic_name="$(get_name_of_nic ${nic})" + echo "install ${module} /bin/true" >> \ + /etc/modprobe.d/"${module}"-blacklist.conf + unload_module_and_rev_deps "${module}" || : + if nic_exists "${nic}"; then + log "Failed to unload module ${module} of NIC ${nic}." + stop_and_disable_NM + notify_panic_failure "${nic}" "${nic_name}" & + else + log "Successfully unloaded module ${module} of NIC ${nic}." + notify_panic_success "${nic}" "${nic_name}" & + fi +} + +spoof_mac() { + local msg + set +e + msg="$(macchanger -e "${1}" 2>&1)" + ret="${?}" + set -e + if [ "${ret}" != 0 ]; then + log "macchanger failed for NIC ${1}, returned ${ret} and said: ${msg}" + return 1 + fi +} + +set_log_tag spoof-mac + +NIC="${1}" + +if ! mac_spoof_is_enabled; then + exit 0 +fi + +log "Trying to spoof MAC address of NIC ${NIC}..." + +if ! nic_exists "${NIC}"; then + log "NIC ${NIC} doesn't exist, skipping" + exit 1 +fi + +OLD_MAC="$(get_current_mac_of_nic "${NIC}")" + +# There is a 1/2^24 chance macchanger will randomly pick the real MAC +# address. We try to making it really unlikely repeating it up to +# three times. Theoretically speaking this leaks information about the +# real MAC address at each occasion but actually leaking the real MAC +# address will be more serious in practice. +for i in 1 2 3; do + if ! spoof_mac "${NIC}"; then + # If our MAC spoofing primitive fails, we fail safe by forcing + # us to enter into panic mode. + unset NEW_MAC + break + fi + NEW_MAC="$(get_current_mac_of_nic "${NIC}")" + if [ "${OLD_MAC}" != "${NEW_MAC}" ]; then + break + fi +done + +# MAC spoofing fail-safe: if $NIC's MAC address isn't spoofed at this +# point we have to take some drastic measures in order to prevent +# potential leaks. +if [ -z "${OLD_MAC:-}" ] || [ -z "${NEW_MAC:-}" ] || \ + [ "${OLD_MAC:-}" = "${NEW_MAC:-}" ] +then + log "Failed to spoof MAC address of NIC ${NIC}. Going into panic mode." + if ! mac_spoof_panic "${NIC}"; then + # If mac_spoof_panic() fails we're quite screwed, so we kill + # NetworkManager without notification to do our best to + # prevent a MAC address leak. + log "Panic mode failed for NIC ${NIC}." + stop_and_disable_NM + fi + exit 1 +fi + +log "Successfully spoofed MAC address of NIC ${NIC}" diff --git a/config/chroot_local-includes/usr/local/lib/tails-unblock-network b/config/chroot_local-includes/usr/local/lib/tails-unblock-network new file mode 100755 index 0000000000000000000000000000000000000000..f2c07d3f7dddddc6e9e11ecd4a26b9e66d21d665 --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-unblock-network @@ -0,0 +1,50 @@ +#!/bin/sh + +set -e +set -u +set -x + +systemctl start tails-unblock-network.service + +# Without this, network is sometimes not unblocked, probably due to some +# race condition between tails-unblock-network.service (that deletes the +# blacklist file) and udevadm trigger, possibly caused by yet another aufs +# weirdness (#9012)... +echo "Sleeping..." >&2 +sleep 5 +echo "slept." >&2 + +# XXX: add debugging information for #9012 to the Journal +ls /etc/modprobe.d +/sbin/lsmod +ls -l /sys/class/net + +# Now we'll load any present network device previously blocked by +# the blacklist. In particular, the MAC spoofing udev rule should trigger +# for each network device added. +echo "Restarting systemd-udev-trigger.service..." >&2 +systemctl restart systemd-udev-trigger.service +echo "systemd-udev-trigger.service restarted." >&2 + +# Block until all triggers have been run. NetworkManager is started immediately +# after, and without the blocking behaviour there's a race between NM +# and the MAC spoof udev triggers. When NM takes control of some network device, +# some operations are not possible on the device, like MAC spoofing. Hence, +# if NM wins, the udev-triggered run of tails-spoof-mac will fail. +echo "Restarting systemd-udev-settle.service..." >&2 +systemctl restart systemd-udev-settle.service +echo "systemd-udev-settle.service restarted." >&2 + +# XXX: add debugging information for #9012 to the Journal +/sbin/lsmod +ls -l /sys/class/net + +# Enable and start NetworkManager services +# No need to manually enable NetworkManager-dispatcher.service, +# as NetworkManager.service has "Also=NetworkManager-dispatcher.service" +# in its [Install] section. +# If tails-spoof-mac goes into panic mode but fails to disable the +# problematic device, the NetworkManager services will be masked. +systemctl enable NetworkManager.service NetworkManager-wait-online.service || : +systemctl start NetworkManager.service NetworkManager-dispatcher.service || : +systemctl --no-block start NetworkManager-wait-online.service || : diff --git a/config/chroot_local-includes/usr/local/lib/tails-virt-notify-user b/config/chroot_local-includes/usr/local/lib/tails-virt-notify-user new file mode 100755 index 0000000000000000000000000000000000000000..f9678ef060cec24401237211d81fd9166e4e801a --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/tails-virt-notify-user @@ -0,0 +1,85 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +#man{{{ + +=head1 NAME + +tails-virt-notify-user + +=head1 VERSION + +Version X.XX + +=head1 AUTHOR + +Tails dev team +See https://tails.boum.org/. + +=cut + +#}}} + +use Desktop::Notify; +use English '-no_match_vars'; +use IPC::System::Simple qw{capturex $EXITVAL}; +use Locale::gettext; +use Net::DBus::Reactor; +use POSIX; + +### initialization +setlocale(LC_MESSAGES, ""); +textdomain("tails"); + +### callbacks + +sub action_cb { + my $reactor = shift; + unless (fork) { + exec( + '/usr/local/bin/tails-documentation', + 'doc/advanced_topics/virtualization', + 'security' + ); + } + $reactor->shutdown; +} + +### main + +# both 0 and 1 are acceptable exit values: +# - 0 means that we're running in a virtualized environment +# - 1 means that we're not running in a virtualized environment +# - anything else means there is a problem, and capturex will throw an exception +my $vm_name = capturex([0, 1], qw{/usr/bin/systemd-detect-virt --vm}); +exit 0 if $EXITVAL == 1; + +my @whitelist = qw(bochs kvm qemu uml virtualbox xen); + +my $reactor = Net::DBus::Reactor->main; + +my $notify = Desktop::Notify->new(); +$notify->action_callback(sub { action_cb($reactor, @_) }); +$notify->close_callback(sub { $reactor->shutdown; }); + +my ($body, $summary); + +chomp($vm_name); +if (grep {$_ eq $vm_name} @whitelist) { + $summary = gettext("Warning: virtual machine detected!"); +} +else { + $summary = gettext("Warning: non-free virtual machine detected!"); +} + +$body = gettext("Both the host operating system and the virtualization software are able to monitor what you are doing in Tails. Only free software can be considered trustworthy, for both the host operating system and the virtualization software."); + +$notify->create(summary => $summary, + body => $body, + actions => { "moreinfo_$PID" => gettext('Learn more'), }, + hints => { 'transient' => 1, }, + timeout => 0)->show(); + +$reactor->run; diff --git a/config/chroot_local-includes/usr/local/lib/udev-watchdog-wrapper b/config/chroot_local-includes/usr/local/lib/udev-watchdog-wrapper new file mode 100755 index 0000000000000000000000000000000000000000..8d7e1dd7bb1a2049d35dab7d37e6b331d0566d9f --- /dev/null +++ b/config/chroot_local-includes/usr/local/lib/udev-watchdog-wrapper @@ -0,0 +1,89 @@ +#!/bin/sh + +set -e + +### Helper functions + +# For whatever reason, the initscript that calls us sets a pretty scarse $PATH +PATH="/usr/bin:${PATH}" + +### Helper functions + +using_fromiso() { + grep -qs -w -E '(fromiso|isofrom)=' /proc/cmdline +} + +# Returns the boot device's path in a form that can be passed to the +# eject command, e.g. /dev/scd0 or /dev/block/NN:MM. +boot_device() { + if using_fromiso ; then + # When booting with e.g. fromiso=/dev/sdx3/tails-XXX.iso, a loop device + # is mounted onto /lib/live/mount/medium => we cannot get the boot device from there. + # This loop device's backing file is seen by the system as + # /isofrom/XXX.iso, which is not available presumably because pivotroot + # was run => we cannot get the boot device from there either. + # Instead, we parse fromiso='s argument the same way live-boot does + # in order to extract the device path (/dev/sdx3) + for ARGUMENT in $(cat /proc/cmdline) ; do + case "${ARGUMENT}" in + isofrom=*|fromiso=*) + FROMISO="${ARGUMENT#*=}" + ;; + esac + done + echo $(dirname "$FROMISO") + else + # Refactorer, beware: the rest of this script depends on the fact that + # the path returned in this case is suitable to be passed as an argument + # to --path in "udevadm info --query" commands... which is not the case + # of paths in the /dev/sdxN form. + DEV_NUMBER="$(udevadm info --device-id-of-file=/lib/live/mount/medium)" + echo "/dev/block/$DEV_NUMBER" + fi +} + +# First clean the screen, then brutally shutdown the machine. +do_stop() { + # Kill everything run by amnesia or Debian-gdm, otherwise emergency + # shutdown fails for some reason. Incidentally, this also allows + # the test suite to look for a known message ("Happy dumping!") + # on the screen. + /bin/loginctl --signal=9 kill-user amnesia || true + /bin/systemctl stop gdm.service || true + /bin/systemctl --signal=9 kill gdm.service || true + /bin/loginctl --signal=9 kill-user Debian-gdm || true + + # Finally, return to the initramfs and poweroff the system + /bin/systemctl --force poweroff +} + + +### Main + +BOOT_DEVICE=$(boot_device) + +# Assign to QUERY_SELECTOR an option that can be passed as a query selector +# to udevadm info --query commands. +if using_fromiso ; then + DEV_NAME=$(basename "$BOOT_DEVICE") + QUERY_SELECTOR="--name $DEV_NAME" +else + QUERY_SELECTOR="--path $BOOT_DEVICE" +fi + +DEV_UDEV_PATH=$(udevadm info --query path $QUERY_SELECTOR) +# SD in SDIO has no ID_TYPE, let's pretend it's a disk just like USB sticks +DEV_TYPE_LINE=$(udevadm info --query property $QUERY_SELECTOR | grep -w '^ID_TYPE') \ + || DEV_TYPE_LINE='ID_TYPE=disk' +DEV_TYPE="${DEV_TYPE_LINE#*=}" + +# If the world was sane we'd want to *disable* the eject lock, but it turns out +# that blocks the block events so udev-watchdog never receives the "change" +# event. See [[bugs/sdmem_on_eject_broken_for_CD]]. +# FIXME: we might be able to do the more sane "-i off" with future kernel/udev +if [ "$DEV_TYPE" = "cd" ]; then + eject -i on "${BOOT_DEVICE}" >/dev/null +fi + +# Start udev-watchdog and stop on clean exit. +/usr/local/sbin/udev-watchdog "$DEV_UDEV_PATH" "$DEV_TYPE" && do_stop diff --git a/config/chroot_local-includes/usr/local/sbin/fillram b/config/chroot_local-includes/usr/local/sbin/fillram new file mode 100755 index 0000000000000000000000000000000000000000..cf3808666b4dfdb785212e39ec4e8c684286c0ed --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/fillram @@ -0,0 +1,7 @@ +#!/usr/bin/python3 + +# NB: this program is subject to the system's per-process memory limits. + +string = "" +while True: + string = string + "wipe_didnt_work\n" diff --git a/config/chroot_local-includes/usr/local/sbin/htpdate b/config/chroot_local-includes/usr/local/sbin/htpdate new file mode 100755 index 0000000000000000000000000000000000000000..2aaf83f1bdaaad891f1a03a2441348f833e0e5af --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/htpdate @@ -0,0 +1,317 @@ +#!/usr/bin/perl +# +# htpdate time poller version 0.9.3 +# Copyright (C) 2005 Eddy Vervest +# Copyright (C) 2010-2011 Tails developers +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# http://www.gnu.org/copyleft/gpl.html + +use strict; +use warnings; + +use version; our $VERSION = qv('0.9.3'); + +use Carp; +use Cwd; +use Data::Dumper; +use DateTime; +use DateTime::Format::DateParse; +use English qw( -no_match_vars ); +use File::Path qw(rmtree); +use File::Spec::Functions; +use File::Temp qw/tempdir/; +use Getopt::Long::Descriptive; +use IPC::System::Simple qw(capturex); +use List::Util qw( shuffle ); +use open qw{:utf8 :std}; +use POSIX qw( WIFEXITED ); +use threads; +use Try::Tiny; + +my $datecommand = '/bin/date'; # "date" command to set time +my $dateparam = '-s'; # "date" parameter to set time +my $maxadjust = 0; # maximum time step in seconds (0 means no max.) +my $minadjust = 1; # minimum time step in seconds +my ( + $debug, $useragent, $log, $quiet, $set_date, + $done_file, $res_file, $usage, $opt, $runas, + $allowed_per_pool_failure_ratio, $proxy, @pools, +); + +sub done { + if (defined $done_file) { + $> = 0 if $runas; + open my $f, '>', $done_file or + print STDERR "Couldn't write done file: $done_file\n"; + close $f; + $> = getpwnam($runas) if $runas; + } +} + +$SIG{__DIE__} = sub { + # Avoid the "done" file to be created by an catched exception. + # When a eval block is being run, e.g. for exception catching, $^S is true. + # It is false otherwise. + done unless $^S; + die(@_); +}; + +sub message { + my @msg = @_; + + if ($log) { + open my $h, '>>', $log or die "Cannot open log file $log: $!"; + print $h "@msg\n"; + close $h; + } + else { + print "@msg\n" unless $quiet; + } +} + +sub debug { + message(@_) if $debug; +} + +sub error { + debug(@_); + croak @_; +} + +sub parseCommandLine () { + # specify valid switches + ($opt, $usage) = describe_options( + 'htpdate %o', + [ 'debug|d', "debug", { default => 0 } ], + [ 'help', "print usage message and exit" ], + [ 'quiet|q', "quiet", { default => 0 } ], + [ 'user|u:s', "userid to run as" ], + [ 'dont_set_date|x', "do not set the time (only show)", { default => 0 } ], + [ 'user_agent|a:s', "http user agent to use", { default => "htpdate/$VERSION" } ], + [ 'log_file|l:s', "log to this file rather than to STDOUT" ], + [ 'done_file|D:s', "create this file after quitting in any way" ], + [ 'success_file|T:s', "create this file after setting time successfully" ], + [ 'pool1=s@', "first pool of hostnames" ], + [ 'pool2=s@', "second pool of hostnames" ], + [ 'pool3=s@', "third pool of hostnames" ], + [ 'allowed_per_pool_failure_ratio:f', "ratio (0.0-1.0) of allowed per-pool failure", { default => 1.0 } ], + [ 'proxy|p:s', "what to pass to curl's --socks5-hostname (if unset, environment variables may affect curl's behavior -- see curl(1) for details)" ], + ); + + usage() if $opt->help; + usage() unless $opt->pool1 && $opt->pool2 && $opt->pool3; + + $runas = $opt->user if $opt->user; + $> = getpwnam($runas) if $runas; + $useragent = $opt->user_agent; + $debug = $opt->debug; + $log = $opt->log_file if $opt->log_file; + $quiet = $opt->quiet; + $set_date = ! $opt->dont_set_date; + $done_file = $opt->done_file if $opt->done_file; + $res_file = $opt->success_file if $opt->success_file; + $allowed_per_pool_failure_ratio = $opt->allowed_per_pool_failure_ratio; + $proxy = $opt->proxy if $opt->proxy; + @pools = map { + [ + map { + $_ = 'https://'.$_ unless $_ =~ /^http/i; + } split(/,/, join(',', @{$_})) + ] + } ($opt->pool1, $opt->pool2, $opt->pool3); +} + +sub usage () { + print STDERR $usage->text; + exit; +} + +sub newestDateHeader { + my ($dir) = @_; + + my @files = grep { ! ( $_ =~ m|/?\.{1,2}$| ) } glob("$dir/.* $dir/*"); + @files or error "No downloaded files can be found"; + + my $newestdt; + + foreach my $file (@files) { + next if -l $file || -d _; + my $date; + open(my $file_h, '<', $file) or die "Can not read file $file: $!"; + while (my $line = <$file_h>) { + chomp $line; + # empty line == we leave the headers to go into the content + last if $line eq ''; + last if ($date) = ($line =~ m/^\s*[Dd]ate:\s+(.*)$/m); + } + close $file_h; + if (defined $date) { + # RFC 2616 (3.3.1) says Date headers MUST be represented in GMT + my $dt = DateTime::Format::DateParse->parse_datetime( $date, 'GMT' ); + if (! defined $newestdt || DateTime->compare($dt, $newestdt) > 0) { + $newestdt = $dt; + } + } + } + + return $newestdt; +} + +=head2 random_first_with_allowed_failure_ratio + +Returns the result of the first successful application of +$args->{code} on a random element of $args->{list}. +Success is tested using the $args->{is_success} predicate, +called on the value returned by $args->{code}. + +$args->{allowed_failure_ratio} caps the maximum failure ratio before +giving up. + +$args->{code} is called with two arguments: the currently (randomly +picked) considered element, and $args->{args}. + +Any exceptions thrown by $args->{code} is catched. + +=cut +sub random_first_with_allowed_failure_ratio { + my $args = shift; + + my %tried; + $tried{$_} = 0 for (@{$args->{list}}); + my $failures = 0; + my $total = keys %tried; + + while ( $failures / $total <= $args->{allowed_failure_ratio} ) { + my @randomized_left = shuffle grep { ! $tried{$_} } keys(%tried); + my $picked = $randomized_left[0]; + $tried{$picked}++; + my $res; + try { + $res = $args->{code}->($picked, $args->{args}) + }; + return $res if $args->{is_success}->($res); + $failures++; + } + + return; +} + +sub getPoolDateDiff { + my $args = shift; + + random_first_with_allowed_failure_ratio({ + list => $args->{urls}, + code => \&getUrlDateDiff, + is_success => sub { defined shift }, + allowed_failure_ratio => $allowed_per_pool_failure_ratio, + }); +} + +sub getUrlDateDiff { + my $url = shift; + my $args = shift; + + defined $url or error "getUrlDateDiff must be passed an URL"; + debug("getUrlDateDiff: $url"); + + my $tmpdir = tempdir("XXXXXXXXXX", TMPDIR => 1); + + my @curl_options = ( + '--user-agent', $useragent, '--silent', + '--proto', '=https', '--tlsv1', + '--max-time', '30', + '--head', '--output', catfile($tmpdir, 'headers'), + ); + push @curl_options, ('--socks5-hostname', $proxy) if defined $proxy; + + my @cmdline = ('curl', @curl_options, $url); + + # fetch (the page and) referenced resources: + # images, stylesheets, scripts, etc. + my $before = DateTime->now->epoch(); + WIFEXITED(system(@cmdline)) or error "Failed to fetch content from $url: $!"; + my $local = DateTime->now->epoch(); + my $newestdt; + eval { $newestdt = newestDateHeader($tmpdir) }; + if ($EVAL_ERROR =~ m/No downloaded files can be found/) { + rmtree($tmpdir); + error "No file could be downloaded from $url."; + } + + rmtree($tmpdir); + + defined $newestdt or error "Could not get any Date header from $url"; + my $newest_epoch = $newestdt->epoch(); + + my $diff = $newest_epoch - $local; + my $took = $local - $before; + + debug("$url (took ${took}s) => diff = $diff second(s)"); + + return $diff; +} + +sub adjustDate { + my ($diff) = @_; + + defined $diff or error "adjustDate was passed an undefined diff"; + + my $local = DateTime->now->epoch(); + my $absdiff = abs($diff); + + debug("Median diff: $diff second(s)"); + + if ( $maxadjust && $absdiff gt $maxadjust ) { + message("Not setting clock as diff ($diff seconds) is too large."); + } + elsif ( $absdiff lt $minadjust) { + message("Not setting clock as diff ($diff seconds) is too small."); + } + else { + my $newtime = DateTime->now->epoch + $diff; + message("Setting time to $newtime..."); + if ($set_date) { + $> = 0 if $runas; + my $output; + try { + $output = capturex($datecommand, $dateparam, '@' . $newtime); + } catch { + error "An error occured setting the time\n$output"; + }; + $> = getpwnam($runas) if $runas; + } + } + if (defined $res_file) { + $> = 0 if $runas; + open my $res_h, '>>', $res_file or die "Cannot open res file $res_file: $!"; + print $res_h "$diff\n"; + close $res_h; + $> = getpwnam($runas) if $runas; + } +} + +sub median { + my @a = sort {$a <=> $b} @_; + return ($a[$#a/2] + $a[@a/2]) / 2; +} + +parseCommandLine(); +message("Running htpdate."); +my @diffs = grep { + defined $_ +} map { + my $diff = $_->join(); + if (! defined $diff) { + error('Aborting as one pool could not be reached'); + } + $diff; +} map { + threads->create(\&getPoolDateDiff, { urls => $_ }) +} @pools + or error "No Date header could be received."; +adjustDate(median(@diffs)); +done; diff --git a/config/chroot_local-includes/usr/local/sbin/live-persist b/config/chroot_local-includes/usr/local/sbin/live-persist new file mode 100755 index 0000000000000000000000000000000000000000..8bdba4f76c1e24c57fbad27c022fb55f33f63b5c --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/live-persist @@ -0,0 +1,604 @@ +#!/bin/bash + +error () +{ + echo "error: ${@}" >&2 + exit 1 +} + +warning () +{ + echo "warning: ${@}" >&2 +} + +# import Cmdline_old() +. /lib/live/boot/9990-cmdline-old \ + || error 'Could not source /lib/live/boot/9990-cmdline-old' + +# Set variable names needed by get_custom_mounts(), +# and now initialized by live-boot in a file that we certainly +# don't want to source. +export persistence_list="persistence.conf" +export old_persistence_list="nonexistent" + +# This will import the following functions and variables used below: +# activate_custom_mounts() +# get_custom_mounts() +# open_luks_device() +# probe_for_gpt_name() +# removable_dev() +# removable_usb_dev() +# storage_devices() +# where_is_mounted() +# $custom_overlay_label +. /lib/live/boot/9990-misc-helpers.sh \ + || error 'Could not source /lib/live/boot/9990-misc-helpers.sh' + +usage () +{ + local cmd=${0##*/} + echo "Usage: ${cmd} [OPTION]... list [LABEL]... +List (on stdout) all GPT partitions with names among LABEL(s) that are +compatible with live-boot's overlay persistence, and that are adhering to +live-boot's persistence filters (e.g. persistent-media). If no LABEL is given +the default in live-boot is used ('${custom_overlay_label}'). + or: ${cmd} [OPTION]... activate VOLUME... +Activates persistence on the given VOLUME(s). Successes and failures are +written to stdout. There are no checks for whether the given volumes adhere +to live-boot's options. + +Kernel command-line options are parsed just like in live-boot and have the same +effect (see live-boot(7) for more information) + +Arguments to options must be passed using an equality sign. LISTs are coma +separated. Most options correspond to the persistent-* options of live-boot, +and will override the corresponging options parsed from the kernel command-line. + +General options: + --help display this help and exit + --log-file=FILE log the bash execution trace to FILE + +Options affecting the 'list' action: + --encryption=LIST override 'persistent-encryption' + --media=VALUE override 'persistent-media' + +Options affecting the 'activate' action: + --read-only enable 'persistent-read-only' + --read-write disable 'persistent-read-only' + --union=VALUE override 'union' +" +} + +escape() { + printf "%s\n" "${2}" | sed --regexp-extended "s/[${1}]/\\\&/g" +} + +escape_dots() { + escape . "${@}" +} + +add_persistence_preset() +{ + local PRESET="${1}" + local PRESET_SOURCE="${2}" + local CONFIG="${3}" + if [ "${PERSISTENCE_READONLY}" = true ] + then + warning "We are trying to add a persistence preset while" \ + "persistence is in read-only mode" + else + echo "${PRESET} source=${PRESET_SOURCE}" \ + >> "${CONFIG}" || error "Failed to make ${PRESET}: $?" + warning "Successfully made ${PRESET} persistent" + fi +} + +remove_persistence_preset() +{ + local PRESET="${1}" + local CONFIG="${2}" + # The intent here is to simply remove the line starting with + # $PRESET, but since it is a path, and sed uses / as delimiter + # for patterns we can use together with d, we have to escape / + # (and . as usual). + sed -i "/^$(escape './' "${PRESET}")\s/d" "${CONFIG}" +} + +is_preset_enabled() { + local PRESET="${1}" + local PRESET_SOURCE="${2}" + local CONFIG="${3}" + grep --extended-regexp --line-regex --quiet --no-messages \ + -e "$(escape_dots ${PRESET})\s+source=${PRESET_SOURCE}" "$CONFIG" +} + +migrate_persistence_preset() +{ + local OLD="${1}" + local OLD_SOURCE="${2}" + local NEW="${3}" + local NEW_SOURCE="${4}" + local CONFIG="${5}" + if is_preset_enabled "${OLD}" "${OLD_SOURCE}" "${CONFIG}" && \ + ! is_preset_enabled "${NEW}" "${NEW_SOURCE}" "${CONFIG}" + then + warning "Need to make ${NEW} persistent" + add_persistence_preset "${NEW}" "${NEW_SOURCE}" \ + "${CONFIG}" + fi +} + +# We override live-boot's logging facilities to get more useful error messages +log_warning_msg () +{ + warning ${@} +} + +# We override live-boot's panic() since it does a lot of crazy stuff +panic () +{ + error ${@} +} + +list_gpt_volumes () +{ + local labels=${@} + + local whitelistdev="" + case "${PERSISTENCE_MEDIA}" in + removable) + whitelistdev="$(removable_dev)" + [ -z "${whitelistdev}" ] && return + ;; + removable-usb) + whitelistdev="$(removable_usb_dev)" + [ -z "${whitelistdev}" ] && return + ;; + *) + if grep -qs -w -E '(live-media|bootfrom)=removable-usb' /proc/cmdline ; then + whitelistdev="$(removable_usb_dev)" + [ -z "${whitelistdev}" ] && return + elif grep -qs -w -E '(live-media|bootfrom)=removable' /proc/cmdline ; then + whitelistdev="$(removable_dev)" + [ -z "${whitelistdev}" ] && return + else + whitelistdev="" + fi + ;; + esac + + for dev in $(storage_devices "" "${whitelistdev}") + do + if ( is_luks_partition ${dev} >/dev/null 2>&1 && \ + echo ${PERSISTENCE_ENCRYPTION} | grep -qve "\" ) || \ + + ( ! is_luks_partition ${dev} >/dev/null 2>&1 && \ + echo ${PERSISTENCE_ENCRYPTION} | grep -qve "\" ) + then + continue + fi + local result="$(probe_for_gpt_name "${labels}" ${dev})" + if [ -n "${result}" ] + then + echo ${result#*=} + fi + done + + exit 0 +} + +mountpoint_has_correct_access_rights () +{ + local mountpoint="$1" + local expected_user=root + local expected_group=root + local expected_perms=775 + local expected_acl="user::rwx +user:tails-persistence-setup:rwx +group::rwx +mask::rwx +other::r-x" + + if [ $(stat -c %U "$mountpoint") != "$expected_user" ] + then + warning "'$mountpoint' is not owned by the '$expected_user' user" + return 1 + fi + if [ $(stat -c %G "$mountpoint") != "$expected_group" ] + then + warning "'$mountpoint' is not owned by the '$expected_group' group" + return 2 + fi + if [ $(stat -c %a "$mountpoint") != "$expected_perms" ] + then + warning "'$mountpoint' permissions are not $expected_perms" + return 4 + fi + if [ "$(getfacl --omit-header --skip-base "$mountpoint" 2>/dev/null | grep -v '^\s*$')" \ + != "$expected_acl" ] + then + warning "'$mountpoint' has incorrect ACL" + return 8 + fi + return 0 +} + +persistence_conf_file_has_correct_access_rights () +{ + local conf="$1" + local expected_perms="$2" + local expected_user=tails-persistence-setup + local expected_group=tails-persistence-setup + local expected_acl="" + + if [ $(stat -c %U "$conf") != "$expected_user" ] + then + warning "'$conf' is not owned by the '$expected_user' user" + return 1 + fi + if [ $(stat -c %G "$conf") != "$expected_group" ] + then + warning "'$conf' is not owned by the '$expected_group' group" + return 2 + fi + if [ $(stat -c %a "$conf") != "$expected_perms" ] + then + warning "'$conf' permissions are not $expected_perms" + return 4 + fi + if [ "$(getfacl --omit-header --skip-base "$conf" 2>/dev/null | grep -v '^\s*$')" \ + != "$expected_acl" ] + then + warning "'$conf' has incorrect ACL" + return 8 + fi + return 0 +} + +disable_and_create_empty_persistence_conf_file () +{ + local conf="$1" + local mode="$2" + + if [ -z "$mode" ] + then + mode=0600 + fi + + mv "$conf" "${conf}.insecure_disabled" \ + || error "Failed to disable '$conf': $?" + create_empty_persistence_conf_file "$conf" "$mode" +} + +create_empty_persistence_conf_file () +{ + local conf="$1" + local mode="$2" + + install --owner tails-persistence-setup \ + --group tails-persistence-setup --mode "$mode" \ + /dev/null "$conf" \ + || error "Failed to create empty '$conf': $?" +} + +activate_volumes () +{ + local volumes=${@} + local ret=0 + local open_volumes="" + local successes="" + local failures="" + + # required by open_luks_device() + exec 6>&1 + + for vol in ${volumes} + do + if [ ! -b "${vol}" ] + then + warning "${vol} is not a block device" + failures="${failures} ${vol}" + ret=1 + continue + fi + if [ -n "$(what_is_mounted_on ${dev})" ] + then + warning "${vol} is already mounted" + failures="${failures} ${vol}" + ret=1 + continue + fi + local luks_vol="" + if /sbin/cryptsetup isLuks ${vol} >/dev/null 2>&1 + then + if luks_vol=$(open_luks_device "${vol}") + then + open_volumes="${open_volumes} ${luks_vol}" + else + failures="${failures} ${vol}" + fi + else + open_volumes="${open_volumes} ${vol}" + fi + done + + custom_mounts="$(mktemp /tmp/custom_mounts-XXXXXX.list)" + get_custom_mounts ${custom_mounts} ${open_volumes} + # ... and now the persistent volumes should be mounted. + + # Enable the acl mount option on all persistent filesystems. + for mountpoint in $(ls -d /live/persistence/*_unlocked || true) + do + mount -o remount,acl "$mountpoint" + done + + # Detect if we have incorrect ownership, permissions and ACL. + ACCESS_RIGHTS_ARE_CORRECT=true + for mountpoint in $(ls -d /live/persistence/*_unlocked || true) + do + if ! mountpoint_has_correct_access_rights "$mountpoint" + then + ACCESS_RIGHTS_ARE_CORRECT=false + break + fi + done + + # Create live-additional-software.conf if there is none + for mountpoint in $(ls -d /live/persistence/*_unlocked || true) + do + if test ! -f "$mountpoint/live-additional-software.conf" + then + create_empty_persistence_conf_file "$mountpoint/live-additional-software.conf" "0644" + fi + done + + # Disable all persistence configuration files if the mountpoint + # has wrong access rights. + if [ "$ACCESS_RIGHTS_ARE_CORRECT" != true ] + then + for f in $(ls /live/persistence/*_unlocked/persistence.conf || true) + do + warning "Disabling '$f': persistent volume has unsafe access rights" + disable_and_create_empty_persistence_conf_file "$f" + done + for f in $(ls /live/persistence/*_unlocked/live-additional-software.conf || true) + do + warning "Disabling '$f': persistent volume has unsafe access rights" + disable_and_create_empty_persistence_conf_file "$f" "644" + done + fi + + # Regardless of the mountpoint access rights, disable persistence + # configuration files with wrong access rights. + for f in $(ls /live/persistence/*_unlocked/persistence.conf || true) + do + if ! persistence_conf_file_has_correct_access_rights "$f" "600" + then + warning "Disabling '$f', that has unsafe access rights" + disable_and_create_empty_persistence_conf_file "$f" + fi + done + for f in $(ls /live/persistence/*_unlocked/live-additional-software.conf || true) + do + if persistence_conf_file_has_correct_access_rights "$f" "600" + then + chmod 0644 "$f" + fi + if ! persistence_conf_file_has_correct_access_rights "$f" "644" + then + warning "Disabling '$f', that has unsafe access rights" + disable_and_create_empty_persistence_conf_file "$f" "644" + fi + done + + # Fix permissions on persistent directories that were created + # with unsafe permissions. + for persistent_fs in $(ls -d /live/persistence/*_unlocked || true) + do + [ -d "$persistent_fs" ] || continue + for child in $(ls "$persistent_fs" || true) + do + subdir="$persistent_fs/$child" + [ -d "$subdir" ] || continue + # Note: we chmod even custom persistent directories. + # This may break things by changing otherwise correct + # permissions copied from the directory that was made + # persistent, so we only do that if the persistent directory + # is owned by amnesia:amnesia, and thus unlikely to be + # a system directory. This e.g. avoids setting wrong + # permissions on the APT, CUPS and NetworkManager + # persistent directories. + [ $(stat -c '%U' "$subdir") = 'amnesia' ] || continue + [ $(stat -c '%G' "$subdir") = 'amnesia' ] || continue + if [ "$PERSISTENCE_READONLY" = true ] + then + warning "Permissions of '$subdir' may need to be fixed, but read only was selected; please retry in read-write mode" + else + chmod go= "$subdir" + fi + done + done + + # Load the new persistence.conf. + custom_mounts="$(mktemp /tmp/custom_mounts-XXXXXX.list)" + get_custom_mounts ${custom_mounts} ${open_volumes} + + if [ -s "${custom_mounts}" ] + then + OLD_UMASK="$(umask)" + # Have activate_custom_mounts create new directories + # with safe permissions (#7443) + umask 0077 + activate_custom_mounts ${custom_mounts} &> /dev/null + umask "$OLD_UMASK" + fi + rm -f ${custom_mounts} 2> /dev/null + + # Update persistent GnuPG configuration for Stretch + if mountpoint --quiet /home/amnesia/.gnupg ; then + # Install current dirmngr.conf if there is no persistent one + if [ ! -e /home/amnesia/.gnupg/dirmngr.conf ] + then + install --owner amnesia --group amnesia --mode 0600 \ + /etc/skel/.gnupg/dirmngr.conf \ + /home/amnesia/.gnupg/dirmngr.conf \ + || warning "Could not install dirmngr.conf" + fi + # Disable gpg.conf settings that either are obsolete, + # or would break communication with keyservers + if [ -e /home/amnesia/.gnupg/gpg.conf ] + then + obsolete_keyserver_options_str='http-proxy|ca-cert-file' + obsolete_keyserver_options_bool='no-try-dns-srv|no-honor-keyserver-url' + sed -i --regexp-extended \ + "s/^(keyserver\s+)/#\1/ ; \ + s/^(keyserver-options\s+($obsolete_keyserver_options_str)=)/\#\\1/ ; \ + s/^(keyserver-options\s+($obsolete_keyserver_options_bool))\$/\#\\1/" \ + /home/amnesia/.gnupg/gpg.conf \ + || warning "Could not update gpg.conf" + fi + fi + + # Get rid of any Enigmail configuredVersion that we previously used + # to set in a way that would persistently override the value maintained + # by Enigmail itself (#12680, #15693). We stopped writing this pref + # there a long time ago but recently instructed users to reintroduce + # this problem as a workaround (#15692). + tb_profile="$(dirname "${conf}")/thunderbird/profile.default" + rm -f "${tb_profile}/preferences/0000tails.js" + + for vol in ${open_volumes} + do + if grep -qe "^${vol}\>" /proc/mounts + then + successes="${successes} ${vol}" + else + failures="${failures} ${vol}" + ret=1 + fi + done + + if [ -n "${successes}" ] + then + echo "Successes:" + for vol in ${successes} + do + echo " - ${vol}" + done + fi + + if [ -n "${failures}" ] + then + echo "Failures:" + for vol in ${failures} + do + echo " - ${vol}" + done + fi + exit ${ret} +} + +close_volumes () +{ + local volumes=${@} + local custom_mounts="$(mktemp /tmp/custom_mounts-XXXXXX.list)" + get_custom_mounts ${custom_mounts} ${volumes} + while read device source dest options # < ${custom_mounts} + do + if [ "${options}" != linkfiles ] + then + umount ${dest} 2> /dev/null + fi + done < ${custom_mounts} + rm -f ${custom_mounts} 2> /dev/null + for vol in ${volumes} + do + local backing=$(where_is_mounted ${vol}) + umount ${backing} + done +} + +main () +{ + # tracing get's activated by Arguments() if "debug" is in /proc/cmdline + # which may be something we don't want to flood stderr + exec 3<>"/dev/null" + BASH_XTRACEFD="3" + + # parse the kernel cmdline for live-boot's configuration as defaults + Cmdline_old + + # note that this is not enough for disabling tracing. we need to do the + # $BASH_XTRACEFD stuff above to avoid tracing until this point. + set +x + + export PERSISTENCE="true" + export NOPERSISTENCE="" + + # Should be set empty since live-boot already changed root for us + export rootmnt="" + + while echo "${1}" | grep -qe "^--[^ ]\+\>" + do + case "${1}" in + --encryption=*) + export PERSISTENCE_ENCRYPTION="${1#*=}" + ;; + --help) + usage + exit 0 + ;; + --log-file=*) + local log_file="${1#*=}" + [ -e "${log_file}" ] && rm -f "${log_file}" + exec 3<>"${log_file}" + set -x + ;; + --media=*) + export PERSISTENCE_MEDIA="${1#*=}" + ;; + --read-only) + export PERSISTENCE_READONLY="true" + ;; + --read-write) + export PERSISTENCE_READONLY="" + ;; + --union=*) + export UNIONTYPE="${1#*=}" + ;; + *) + error "unrecognized option: ${1}" + ;; + esac + shift + done + + local action="${1}" + shift + case "${action}" in + list) + local labels=${@} + if ! echo ${labels} | grep -qe "[^[:space:]]" + then + # use default from live-helpers + labels=${custom_overlay_label} + fi + list_gpt_volumes ${labels} + ;; + activate|close) + if ! echo ${@} | grep -qe "[^[:space:]]" + then + error "you must specify at least one volume" + fi + ${action}_volumes "${@}" + ;; + "") + error "no action specified" + ;; + *) + error "unrecognized action: ${action}" + ;; + esac +} + +main ${@} diff --git a/config/chroot_local-includes/usr/local/sbin/nautilus b/config/chroot_local-includes/usr/local/sbin/nautilus new file mode 100755 index 0000000000000000000000000000000000000000..682b9e026e51758d59199217765ff8f6e29c23f3 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/nautilus @@ -0,0 +1,10 @@ +#!/bin/sh + +# Without this wrapper, after closing Nautilus, one gets the prompt back +# only after 5-15 seconds, which confuses users and makes our doc more +# complicated than it should (#12034, #10391). So let's start Nautilus +# silently in the background instead. + +set -eu + +exec /usr/bin/nautilus "$@" 2>/dev/null & diff --git a/config/chroot_local-includes/usr/local/sbin/restart-tor b/config/chroot_local-includes/usr/local/sbin/restart-tor new file mode 100755 index 0000000000000000000000000000000000000000..895b12c2676e670529b68134ec105d808bd5ff20 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/restart-tor @@ -0,0 +1,43 @@ +#! /usr/bin/env python3 + +import logging +import time +import sys + +import sh + +from tailslib.tor import tor_has_bootstrapped +from tailslib.exceptions import TorFailedToBoostrapError + + +logger = logging.getLogger(__name__) + +TIMEOUT = 270 + + +def main(): + restart_tor() + + +def restart_tor(): + """ Restart the Tor systemd service + + >>> restart_tor() + """ + sh.systemctl('restart', 'tor@default.service') + + for i in range(TIMEOUT): + if tor_has_bootstrapped(): + logger.info("Tor has successfully bootstrapped") + return + time.sleep(1) + + raise TorFailedToBoostrapError("Tor failed to bootstrap within %s seconds" % TIMEOUT) + + +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == 'doctest': + import doctest + doctest.testmod() + else: + main() diff --git a/config/chroot_local-includes/usr/local/sbin/tails-additional-software b/config/chroot_local-includes/usr/local/sbin/tails-additional-software new file mode 100755 index 0000000000000000000000000000000000000000..4c3379e92ae43f0f34ce9e7ca1a4a4b0bd1c2230 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tails-additional-software @@ -0,0 +1,679 @@ +#!/usr/bin/env python3 + +import gettext +import json +import logging +import logging.handlers +import os +import os.path +import pwd +import shutil +import subprocess +import sys + +import apt.cache + +from tailslib import LIVE_USERNAME + +from tailslib.additionalsoftware import ( + ASPDataError, + add_additional_packages, + filter_package_details, + get_additional_packages, + get_packages_list_path, + remove_additional_packages) + +from tailslib.persistence import ( + has_unlocked_persistence, + has_persistence, + is_tails_media_writable, + launch_persistence_setup, + PERSISTENCE_DIR) + +from tailslib.utils import launch_x_application + +_ = gettext.gettext + +ASP_STATE_DIR = "/run/live-additional-software" +ASP_STATE_PACKAGES = os.path.join(ASP_STATE_DIR, "packages") +ASP_STATE_INSTALLER_ASKED = os.path.join(ASP_STATE_DIR, "installer-asked") +ASP_LOG_FILE = os.path.join(ASP_STATE_DIR, "log") +OLD_APT_LISTS_DIR = os.path.join(PERSISTENCE_DIR, 'apt', 'lists.old') +APT_ARCHIVES_DIR = "/var/cache/apt/archives" +APT_LISTS_DIR = "/var/lib/apt/lists" + + +def _exit_if_in_live_build(): + """Exits with success if running inside live-build.""" + if "SOURCE_DATE_EPOCH" in os.environ: + sys.exit(0) + + +def _launch_apt_get(specific_args): + """Launch apt-get with given arguments. + + Launch apt-get with given arguments list, log its standard and error output + and return its returncode.""" + apt_get_env = os.environ.copy() + # The environnment provided in GDM PostLogin hooks doesn't contain /sbin/ + # which is required by dpkg. Let's use the default path for root in Tails. + apt_get_env['PATH'] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:" \ + "/usr/bin:/sbin:/bin" + # We will log the output and want it in English when included in bug + # reports + apt_get_env['LANG'] = "C" + apt_get_env['DEBIAN_PRIORITY'] = "critical" + args = ["apt-get", "--quiet", "--yes"] + args.extend(specific_args) + apt_get = subprocess.Popen(args, + env=apt_get_env, + universal_newlines=True, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE) + for line in iter(apt_get.stdout.readline, ''): + if not line.startswith('('): + logging.info(line.rstrip()) + apt_get.wait() + if apt_get.returncode: + logging.warning("apt-get exited with returncode %i" + % apt_get.returncode) + return apt_get.returncode + + +def _notify(title, body="", accept_label="", deny_label="", + documentation_target="", urgent=False, return_id=False): + """Display a notification to the user of the live system. + + The notification will show title and body. + + If accept_label or deny_label are set, they will be shown on action buttons + and the method will wait for user input and return 1 if the button with + accept_label was clicked or 0 if the button with deny_label was + clicked. + + If documentation_target is set, a "Documentation" action button will open + corresponding tails documentation when clicked. + + If return_id is true, returns the notification ID, which may be used to + close the notification. + + Else, return None. + """ + + cmd = "/usr/local/lib/tails-additional-software-notify" + if urgent: + urgent = "urgent" + else: + urgent = "" + + try: + completed_process = subprocess.run( + [ + "sudo", "-u", LIVE_USERNAME, + cmd, title, body, accept_label, deny_label, + documentation_target, urgent + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True + ) + if completed_process.returncode == 1: + # sudo failed to execute the command + raise OSError(completed_process.stderr) + except OSError as e: + logging.warning("Warning: unable to notify the user. %s" % e) + logging.warning("The notification was: %s %s" % (title, body)) + return None + + if return_id: + for line in completed_process.stdout.splitlines(): + if line.startswith("id="): + return line[3:] + else: + if completed_process.returncode == 0: + return 1 + elif completed_process.returncode == 3: + return 0 + else: + return None + + +def _notify_failure(summary, details=None): + """Display a failure notification to the user of the live system. + + The user has the option to edit the configuration or to view the system + log. + """ + if details: + # Translators: Don't translate {details}, it's a placeholder and will + # be replaced. + details = _("{details} Please check your list of additional " + "software or read the system log to " + "understand the problem.").format(details=details) + + else: + details = _("Please check your list of additional " + "software or read the system log to " + "understand the problem.") + + action_clicked = _notify(summary, details, _("Show Log"), _("Configure"), + urgent=True) + if action_clicked == 1: + show_system_log() + elif action_clicked == 0: + show_configuration_window() + + +def _close_notification(notification_id): + """Close a notification shown to the user of the live system.""" + subprocess.run( + ["sudo", "-u", LIVE_USERNAME, + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/{uid}/bus".format( + uid=pwd.getpwnam(LIVE_USERNAME).pw_uid), + "gdbus", "call", + "--session", + "--dest", "org.freedesktop.Notifications", + "--object-path", "/org/freedesktop/Notifications", + "--method", "org.freedesktop.Notifications.CloseNotification", + str(notification_id)], + stdout=subprocess.DEVNULL) + + +def _spawn_daemon(func): + """Spawn func after double-forking. + + Do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177). + + From https://stackoverflow.com/questions/6011235/run-a-program-from- + python-and-have-it-continue-to-run-after-the-script-is-kille + """ + try: + pid = os.fork() + if pid > 0: + # parent process, return and keep running + return + except OSError as e: + logging.error("fork #1 failed: %d (%s)" % (e.errno, e.strerror)) + sys.exit(1) + + os.setsid() + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError as e: + logging.error("fork #2 failed: %d (%s)" % (e.errno, e.strerror)) + sys.exit(1) + + # do stuff + func() + + +def _format_iterable(iterable): + """Return a nice formatted string with the elements of iterable.""" + iterable = sorted(iterable) + + if len(iterable) == 1: + return iterable[0] + elif len(iterable) > 1: + # Translators: Don't translate {beginning} or {last}, they are + # placeholders and will be replaced. + return _("{beginning} and {last}").format( + beginning=_(", ").join(iterable[:-1]), last=iterable[-1]) + else: + return str(iterable) + + +def has_additional_packages_list(search_new_persistence=False): + """Return true iff a packages list file is found in a persistence. + + Log warnings in syslog. + The search_new_persistence argument is passed to get_persistence_path. + """ + try: + packages_list_path = get_packages_list_path(search_new_persistence) + except FileNotFoundError as e: + logging.warning("Warning: {}".format(e)) + return False + if os.path.isfile(packages_list_path): + logging.info("Found additional packages list.") + return True + else: + logging.warning("Warning: no configuration file found.") + return False + + +def delete_old_apt_lists(old_apt_lists_dir=OLD_APT_LISTS_DIR): + """Delete the copy of the old APT lists, if any.""" + shutil.rmtree(old_apt_lists_dir) + + +def save_old_apt_lists(srcdir=APT_LISTS_DIR, destdir=OLD_APT_LISTS_DIR): + """Save a copy of the APT lists""" + if os.path.exists(destdir): + logging.warning("Warning: a copy of the APT lists already exists, " + "which should never happen. Removing it.") + delete_old_apt_lists(destdir) + shutil.copytree(srcdir, destdir, symlinks=True) + + +# Note: we can't do nicer delete + move operations because the directory +# we want to replace is bind-mounted. So we have to delete the content +# we want to replace, and then move the content we want to restore. +def restore_old_apt_lists(srcdir=OLD_APT_LISTS_DIR, dstdir=APT_LISTS_DIR): + """Restore the copy of the old APT lists.""" + # Empty dstdir + for basename in os.listdir(dstdir): + path = os.path.join(dstdir, basename) + if os.path.isfile(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + # Move the content of srcdir to dstdir + for basename in os.listdir(srcdir): + path = os.path.join(srcdir, basename) + shutil.move(path, dstdir) + + +def handle_installed_packages(packages): + """Configure packages as additional software packages if the user wants to. + + Ask the user if packages should be added to additional software, and + actually add them if requested. + """ + logging.info("New packages manually installed: %s" % packages) + if has_unlocked_persistence(search_new_persistence=True): + # Translators: Don't translate {packages}, it's a placeholder and will + # be replaced. + if _notify(_("Add {packages} to your additional software?").format( + packages=_format_iterable(packages)), + _("To install it automatically from your persistent " + "storage when starting Tails."), + _("Install Every Time"), + _("Install Only Once"), + urgent=True): + try: + setup_additional_packages() + add_additional_packages(packages, search_new_persistence=True) + except Exception as e: + _notify_failure(_("The configuration of your additional " + "software failed.")) + raise e + elif has_persistence(): + # When a package is installed with a persistent storage locked, don't + # show any notification. + # + # People who have a persistent storage but don't unlock it, probably do + # this only sometimes and for a reason. They probably otherwise unlock + # their persistent storage most of the time. + # + # If they install packages with their persistent storage locked, they + # probably do it with their persistent storage unlock as well and would + # learn about this feature when it's most relevant for them. + logging.warning("Warning: persistence storage is locked, can't add " + "additional software.") + elif is_tails_media_writable(): + # Translators: Don't translate {packages}, it's a placeholder and will + # be replaced. + if _notify(_("Add {packages} to your additional software?").format( + packages=_format_iterable(packages)), + _("To install it automatically when starting Tails, you " + "can create a persistent storage and activate the " + "Additional Software feature."), + _("Create Persistent Storage"), + _("Install Only Once"), + urgent=True): + try: + create_persistence_and_setup_additional_packages(packages) + except Exception as e: + _notify_failure(_("The configuration of your additional " + "software failed."), + _("Creating your persistent storage " + "failed.")) + raise e + else: # It's impossible to have a persistent storage + logging.warning("Cannot create persistent storage on this media.") + if not os.path.isfile(ASP_STATE_INSTALLER_ASKED): + open(ASP_STATE_INSTALLER_ASKED, 'a').close() + # Translators: Don't translate {packages}, it's a placeholder and + # will be replaced. + _notify(_("You could install {packages} automatically when " + "starting Tails").format( + packages=_format_iterable(packages)), + _("To do so, you need to run Tails from a USB stick " + "installed using Tails Installer."), + documentation_target="install/clone", + urgent=True) + + +def handle_removed_packages(packages): + """Removes packages from additional software packages if the user wants to. + + Ask the user if packages should be removed from additional software, and + actually remove them if requested. + """ + logging.info("Additional packages removed: %s" % packages) + # Translators: Don't translate {packages}, it's a placeholder and will be + # replaced. + if _notify(_("Remove {packages} from your additional software?").format( + packages=_format_iterable(packages)), + # Translators: Don't translate {packages}, it's a placeholder + # and will be replaced. + _("This will stop installing {packages} automatically.").format( + packages=_format_iterable(packages)), + _("Remove"), + _("Cancel"), + urgent=True): + try: + remove_additional_packages(packages, search_new_persistence=True) + except Exception as e: + _notify_failure(_("The configuration of your additional " + "software failed.")) + raise e + + +def setup_additional_packages(): + """Enable additional software in persistence.""" + launch_persistence_setup("--no-gui", + "--no-display-finished-message", + "--force-enable-preset", "AdditionalSoftware") + + +def create_persistence_and_setup_additional_packages(packages): + """Create persistence and add packages to its configuration. + + Create a new persistence with additional packages enabled. + Then add the packages to additional packages configuration. + + packages should be a list of packages names. + """ + logging.info("Creating new persistent volume") + launch_persistence_setup("--step", "bootstrap", + "--no-display-finished-message", + "--force-enable-preset", "AdditionalSoftware") + add_additional_packages(packages, search_new_persistence=True) + # show persistence configuration + launch_persistence_setup() + # APT lists and APT archive cache will be synchronized at shutdown by + # tails-synchronize-data-to-new-persistent-volume-on-shutdown.service + + +def show_configuration_window(): + """Show additional packages configuration window.""" + launch_x_application(LIVE_USERNAME, + "/usr/local/bin/tails-additional-software-config") + + +def show_system_log(): + """Show additional packages configuration window.""" + launch_x_application(LIVE_USERNAME, + "/usr/bin/gedit", + ASP_LOG_FILE) + + +def apt_hook_pre(): + """Subcommand to handle Dpkg::Pre-Install-Pkgs.""" + _exit_if_in_live_build() + logging.info("Saving package changes") + + apt_cache = apt.cache.Cache() + + installed_packages = [] + removed_packages = [] + + line = sys.stdin.readline() + if not line.startswith("VERSION 3"): + raise ASPDataError("APT data is not version 3") + line = sys.stdin.readline() + # Ignore configuration space, which ends with an empty line + while line != "\n": + line = sys.stdin.readline() + # Package action lines + for line in sys.stdin: + # Package action lines consist of five fields in Version 2: package + # name (without architecture qualification even if foreign), old + # version, direction of version change (< for upgrades, > for + # downgrades, = for no change), new version, action. The version + # fields are "-" for no version at all (for example when installing + # a package for the first time; no version is treated as earlier + # than any real version, so that is an upgrade, indicated as - < + # 1.23.4). The action field is "**CONFIGURE**" if the package is + # being configured, "**REMOVE**" if it is being removed, or the + # filename of a .deb file if it is being unpacked. + # + # In Version 3 after each version field follows the architecture of + # this version, which is "-" if there is no version, and a field + # showing the MultiArch type "same", "foreign", "allowed" or "none". + # Note that "none" is an incorrect typename which is just kept to + # remain compatible, it should be read as "no" and users are + # encouraged to support both. + # + # Example: + # + # colordif - - none < 1.0.16-1 all none **CONFIGURE** + package_name, old_version, old_arch, old_multiarch, direction, \ + new_version, new_arch, new_multiarch, action = line.split() + if action.endswith(".deb"): + # Filter packages that will only be upgraded + if not apt_cache[package_name].is_installed: + installed_packages.append(package_name) + elif action.endswith("**REMOVE**"): + removed_packages.append(package_name) + + result = {"installed": installed_packages, "removed": removed_packages} + with open(ASP_STATE_PACKAGES, 'w') as f: + json.dump(result, f) + + +def apt_hook_post(): + """Subcommand to handle Dpkg::Post-Invoke. + + Retrieve the list of packages saved by apt_hook_pre, filter packages not + interesting and pass the resulting list to the appropriate method. + """ + _exit_if_in_live_build() + logging.info("Examining package changes") + + with open(ASP_STATE_PACKAGES) as f: + packages = json.load(f) + os.remove(ASP_STATE_PACKAGES) + + additional_packages_names = { + filter_package_details(pkg) for pkg in + get_additional_packages(search_new_persistence=True) + } + + apt_cache = apt.cache.Cache() + # Filter automatically installed packages and packages already configured + # as additional software + new_manually_installed_packages = { + pkg for pkg in packages["installed"] if ( + not apt_cache[pkg].is_auto_installed and + pkg not in additional_packages_names) + } + + if new_manually_installed_packages: + handle_installed_packages(new_manually_installed_packages) + + # Filter non-additional software packages + additional_packages_removed = set(packages["removed"]).intersection( + additional_packages_names) + if additional_packages_removed: + handle_removed_packages(additional_packages_removed) + + +def install_additional_packages(upgrade_mode=False): + """Subcommand which activates and installs all additional packages. + + If upgrade_mode is True, don't attempt to restore old apt lists and don't + notify the user using desktop notifications.""" + logging.info("Starting to install additional software...") + + if not has_additional_packages_list(): + return True + + # If a copy of old APT lists is found, then the previous upgrade + # attempt has not completed successfully (it may have failed e.g. + # due to network problems, or it may have been interrupted). + # In many of these cases, the APT package cache lacks some + # packages the new APT lists reference, so the (offline) + # installation step below in this function will fail. To avoid + # that, we restore the old APT lists: there are greater chances + # that the APT packages cache still has the corresponding packages. + if os.path.isdir(OLD_APT_LISTS_DIR) and not upgrade_mode: + logging.warning("Found a copy of old APT lists, restoring it.") + try: + restore_old_apt_lists() + except Exception as e: + logging.warning("Restoring old APT lists failed with %r, " + "deleting them and proceeding anyway." % e) + # In all cases, delete the old APT lists: if they could be + # restored we don't need them anymore (and we don't want to + # restore them again next time); if they could not be + # restored, chances are restoration will fail next time + # as well. + delete_old_apt_lists() + + packages = get_additional_packages() + if not packages: + logging.warning("Warning: no packages to install, exiting") + return True + if not upgrade_mode: + installing_notification_id = _notify( + _("Installing your additional software from persistent " + "storage..."), + _("This can take several minutes."), + return_id=True) + logging.info("Will install the following packages: %s" + % " ".join(packages)) + apt_get_returncode = _launch_apt_get( + ["--no-remove", + "--option", "DPkg::Options::=--force-confold", + "install"] + list(packages)) + if apt_get_returncode: + logging.warning("Warning: installation of %s failed" + % " ".join(packages)) + if not upgrade_mode: + _close_notification(installing_notification_id) + _notify_failure(_("The installation of your additional software " + "failed")) + return False + else: + logging.info("Installation completed successfully.") + if not upgrade_mode: + _close_notification(installing_notification_id) + # XXX: there should be a "Configure" button in this notification. + # However, the easy way to implement it makes this process not + # return until the notification is clicked. The notification + # process could be detached, and handle the "configure" action + # itself. + # if _notify(_("Additional software installed successfully"), + # accept_label=_("Configure")): + # show_configuration_window() + _notify(_("Additional software installed successfully")) + return True + + +def upgrade_additional_packages(): + """Subcommand which upgrades all additional packages.""" + logging.info("Starting to upgrade additional software...") + + if not has_additional_packages_list(): + return True + + # Save a copy of APT lists that we'll delete only once the upgrade + # has succeeded, to ensure that the APT packages cache is up-to-date + # wrt. the APT lists. + logging.info("Saving old APT lists...") + save_old_apt_lists() + + apt_get_returncode = _launch_apt_get(["update"]) + if apt_get_returncode: + logging.warning("Warning: the update failed.") + _notify_failure(_("The check for upgrades of your additional software " + "failed"), + _("Please check your network connection, " + "restart Tails, or read the system log to " + "understand the problem.")) + return False + if install_additional_packages(upgrade_mode=True): + logging.info("The upgrade was successful.") + else: + _notify_failure(_("The upgrade of your additional software failed"), + _("Please check your network connection, " + "restart Tails, or read the system log to " + "understand the problem.")) + return False + + # We now know that the APT packages cache is up-to-date wrt. the APT lists, + # so we can delete the copy of the old lists + delete_old_apt_lists() + + # Remove outdated packages from the local package cache. This is needed as + # we disable apt-daily.timer, which would else take care of this cleanup. + # We do this after the upgrade has succeeded so that the old packages + # remain available in the cache in case we have to restore the old lists. + # In the past we did this before upgrading in order to remove the + # i386 packages from the cache before downloading amd64 ones, but + # this does not matter anymore now that all persistent volumes + # must have been upgraded already. + apt_get_returncode = _launch_apt_get(["autoclean"]) + if apt_get_returncode: + logging.warning("Warning: autoclean failed.") + return True + + +def print_help(): + """Subcommand which displays help.""" + sys.stderr.write("Usage: %s \n" % program_name) + sys.stderr.write("""Subcommands: + install: install additional software + upgrade: upgrade additional software\n""") + + +if __name__ == "__main__": + program_name = os.path.basename(sys.argv[0]) + + # Exits with success if running inside live-build. + if "SOURCE_DATE_EPOCH" in os.environ: + sys.exit(0) + + # Set loglevel if debug is found in kernel command line. + with open('/proc/cmdline') as cmdline_fd: + cmdline = cmdline_fd.read() + if "DEBUG" in os.environ or "debug" in cmdline.split(): + log_level = logging.DEBUG + log_format = "[%(levelname)s] %(filename)s:%(lineno)d " \ + "%(funcName)s: %(message)s" + else: + log_level = logging.INFO + log_format = "[%(levelname)s] %(message)s" + stderr_handler = logging.StreamHandler() + file_handler = logging.FileHandler(ASP_LOG_FILE) + logging.basicConfig(format=log_format, + handlers=[stderr_handler, file_handler], + level=log_level) + + gettext.install("tails") + + if len(sys.argv) < 2: + print_help() + sys.exit(2) + + if sys.argv[1] == "install": + if not install_additional_packages(): + sys.exit(150) + elif sys.argv[1] == "upgrade": + if not upgrade_additional_packages(): + sys.exit(151) + elif sys.argv[1] == "apt-pre": + apt_hook_pre() + elif sys.argv[1] == "apt-post": + _spawn_daemon(apt_hook_post) + else: + print_help() + sys.exit(2) diff --git a/config/chroot_local-includes/usr/local/sbin/tails-additional-software-remove b/config/chroot_local-includes/usr/local/sbin/tails-additional-software-remove new file mode 100755 index 0000000000000000000000000000000000000000..4ee6a2b4e728b344a1abedf52ac11192ab1c3358 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tails-additional-software-remove @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +from tailslib.additionalsoftware import ( + remove_additional_packages, + get_additional_packages) + +if len(sys.argv) != 2: + sys.exit(2) + +old_package = str(sys.argv[1]) + +additional_packages = get_additional_packages(search_new_persistence=True) +if old_package in additional_packages: + remove_additional_packages({old_package}, search_new_persistence=True) +else: + sys.exit(1) diff --git a/config/chroot_local-includes/usr/local/sbin/tails-debugging-info b/config/chroot_local-includes/usr/local/sbin/tails-debugging-info new file mode 100755 index 0000000000000000000000000000000000000000..a0babdef1a50ae4029b867105877293ed14fceb9 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tails-debugging-info @@ -0,0 +1,160 @@ +#! /usr/bin/env python3 +""" +Debug Tails. + +Test with "python3 tails-debugging-info.py doctest" as root. + +goodcrypto.com converted from bash to python and added basic tests. + +*** WARNING about debug_file and debug_directory ********************* + +Great attention must be given to the ownership situation of these +files and their parent directories in order to avoid a symlink-based +attack that could read the contents of any file and make it +accessible to the user running this script (typically the live +user). Therefore, when adding a new file, give as the first argument +'root' only if the complete path to it (including the file itself) +is owned by root and already exists before the system is connected to +the network (that is, before GDM's PostLogin script is run). +If not, the following rules must be followed strictly: + +* only one non-root user is involved in the ownership situation (the + file, its dir and the parent dirs). From now on let's assume it is + the case and call it $USER. + +* if any non-root group has write access, it must not have any + members. + +If any of these rules does not apply, the file cannot be added here +safely and something is probably quite wrong and should be +investigated carefully. + +>>> # run script +>>> import sh +>>> this_command = sh.Command(sys.argv[0]) +>>> this_command() + +... +""" + +import json +import os +import sys +import subprocess +from pwd import getpwuid + + +# AppArmor Ux rules don't sanitize PATH, which can lead to an +# exploited application (that's allowed to run this script unconfined) +# having this script run arbitrary code, violating that application's +# confinement. Let's prevent that by setting PATH to a list of +# directories where only root can write. +os.environ['PATH'] = '/usr/local/bin:/usr/bin:/bin' + + +def main(): + """Print debug information serialized as json. + + >>> main() + + ... + """ + + config = None + with open('/etc/whisperback/debugging-info.json', 'r') as conf_file: + config = json.load(conf_file) + + info = [] + for _type, _args in config: + if _type == 'command': + info.append(debug_command(_args['args'][0], *_args['args'][1:])) + elif _type == 'directory': + info.append(debug_directory(_args['user'], _args['path'])) + else: + info.append(debug_file(_args['user'], _args['path'])) + print() + print(json.dumps(info, indent=4)) + + +def debug_command(command, *args): + """Return the command and it's standard output as dict. + + >>> debug_command('echo', 'foo') + {...'key': 'echo foo'...} + """ + command_output = subprocess.check_output([command, *args]) + command_output = command_output.decode('UTF-8').strip().split('\n') + return {'key': '{}'.format(' '.join((command,) + args)), 'content': command_output} + + +def debug_file(user, filename): + """Return the filename and the file content as dict. + + >>> import tempfile, getpass + >>> with tempfile.NamedTemporaryFile('w') as f: + ... _ = f.write("foo\\nbar") + ... _ = f.seek(0) + ... debug_file(getpass.getuser(), f.name) + {...'content': ['foo', 'bar']...} + """ + if not os.path.isfile(filename): + return {'key': filename, 'content': 'Not found'} + + # This check is not sufficient, see the comment at the top of the file + # for the complete requirements required for security + owner = getpwuid(os.stat(filename).st_uid).pw_name + if owner != user: + return {'key': filename, 'content': '''WARNING: not opening file {}, because it is ''' + '''owned by {} instead of {}'''.format(filename, owner, user)} + + file_content = [] + with open(filename) as f: + for l in f: + file_content.append(l.replace('\n', '')) + return {'key': filename, 'content': file_content} + + +def debug_directory(user, dir_name): + """Return a dict with the dir_name and dicts with + the content of all contained files (non-recursively). + + >>> import os, getpass + >>> tmpdir = '/tmp/mytempdir' + >>> os.makedirs(tmpdir) + >>> with open(os.path.join(tmpdir, 'foo'), 'w') as f: + ... _ = f.write("foobar\\nbar") + ... _ = f.seek(0) + ... result = debug_directory(getpass.getuser(), tmpdir) + >>> os.remove(os.path.join(tmpdir, 'foo')) + >>> os.rmdir(tmpdir) + >>> result + {...[{...['foobar', 'bar']...}]} + """ + if not os.path.isdir(dir_name): + return {'key': dir_name, 'content': 'Not found'} + + # This check is not sufficient, see the comment at the top of the file + # for the complete requirements required for security + owner = getpwuid(os.stat(dir_name).st_uid).pw_name + if owner != user: + return {'key': dir_name, 'content': '''WARNING: not opening directory {}, because ''' + '''it is owned by {} instead of {}'''.format(dir_name, owner, user)} + + files = os.listdir(dir_name) + + listing = [] + + for f in files: + listing.append(debug_file(user, os.path.join(dir_name, f))) + return {'key': dir_name, 'content': listing} + + +if __name__ == '__main__': + if sys.argv and len(sys.argv) > 1: + if sys.argv[1] == 'doctest': + import doctest + doctest.testmod(optionflags=doctest.ELLIPSIS) + else: + main() + else: + main() diff --git a/config/chroot_local-includes/usr/local/sbin/tails-notify-user b/config/chroot_local-includes/usr/local/sbin/tails-notify-user new file mode 100755 index 0000000000000000000000000000000000000000..6c89d67ba8b10c964f927e52e5657814c9d77d79 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tails-notify-user @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +# Import export_gnome_env(). +. /usr/local/lib/tails-shell-library/gnome.sh + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +if [ $# -ne 2 ] && [ $# -ne 3 ]; then + echo "Usage: $0 SUMMARY BODY [TIMEOUT]" >&2 + exit 16 +fi + +# Notify the desktop user +summary="$1" +body="$2" + +if [ -n "$3" ]; then + timeout_args="--expire-time=$3" +fi +( + export_gnome_env + exec /bin/su -c "notify-send ${timeout_args} \"${summary}\" \"${body}\"" "${LIVE_USERNAME}" & +) diff --git a/config/chroot_local-includes/usr/local/sbin/tails-tor-launcher b/config/chroot_local-includes/usr/local/sbin/tails-tor-launcher new file mode 100755 index 0000000000000000000000000000000000000000..761270b4666a5df72488d030b77506c1cc84aa4e --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tails-tor-launcher @@ -0,0 +1,33 @@ +#!/bin/sh + +set -e + +# Import export_gnome_env(). +. /usr/local/lib/tails-shell-library/gnome.sh + +# Get LIVE_USERNAME +. /etc/live/config.d/username.conf + +# Get LANG +. /etc/default/locale + +# The Tor Browser hardcodes the default profile dir to inside +# ../TorBrowser/Data/Browser/ from the folder storing the +# application.ini file supplied via -app. We can use -profile to load +# it from a different place, but then the Caches directory +# must still exist and be accessible in the above folder. +mkdir -p /usr/local/lib/TorBrowser/Data/Browser/Caches +chmod -R a+rX /usr/local/lib/TorBrowser + +until pgrep -u "${LIVE_USERNAME}" '^ibus-daemon' >/dev/null ; do + sleep 5 +done + +export LANG +export_gnome_env +sudo -u ${LIVE_USERNAME} xhost +SI:localuser:tor-launcher +pkexec -u tor-launcher /usr/local/bin/tor-launcher -- "$@" +RET=${?} +sudo -u ${LIVE_USERNAME} xhost -SI:localuser:tor-launcher + +exit ${RET} diff --git a/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped b/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped new file mode 100755 index 0000000000000000000000000000000000000000..326e09a6d8e4e67db711ff1e68a15ba8d5493485 --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped @@ -0,0 +1,4 @@ +#!/bin/sh + +/bin/systemctl --quiet is-active tor@default.service || exit 1 +/bin/systemctl --quiet is-active tails-tor-has-bootstrapped.target diff --git a/config/chroot_local-includes/usr/local/sbin/unsafe-browser b/config/chroot_local-includes/usr/local/sbin/unsafe-browser new file mode 100755 index 0000000000000000000000000000000000000000..24eb30e0ab9ae8efb6be812c59cb5e7fa615571c --- /dev/null +++ b/config/chroot_local-includes/usr/local/sbin/unsafe-browser @@ -0,0 +1,127 @@ +#!/bin/sh + +set -e +set -u + +. gettext.sh +TEXTDOMAIN="tails" +export TEXTDOMAIN + +# Import tor_is_working() +. /usr/local/lib/tails-shell-library/tor.sh + +# Import the TBB_EXT variable, and guess_best_tor_browser_locale(). +. /usr/local/lib/tails-shell-library/tor-browser.sh + +# Import localized_tails_doc_page(). +. /usr/local/lib/tails-shell-library/localization.sh + +# Import try_cleanup_browser_chroot(), setup_browser_chroot(), +# configure_chroot_dns_servers(), configure_chroot_browser(), +# configure_chroot_browser(), set_chroot_browser_locale() +# set_chroot_browser_name(), set_chroot_browser_permissions() +# and run_browser_in_chroot(). +. /usr/local/lib/tails-shell-library/chroot-browser.sh + +error () { + local cli_text="${CMD}: `gettext \"error:\"` ${@}" + local dialog_text="`gettext \"Error\"` + +${@}" + echo "${cli_text}" >&2 + sudo -u "${SUDO_USER}" zenity --error --title "" --text "${dialog_text}" + exit 1 +} + +verify_start () { + # Make sure the user really wants to start the browser + local dialog_msg="`gettext \"Do you really want to launch the Unsafe Browser?\"` + +`gettext \"Network activity within the Unsafe Browser is not anonymous.\\nOnly use the Unsafe Browser if necessary, for example\\nif you have to login or register to activate your Internet connection.\"`" + local launch="`gettext \"_Launch\"`" + local exit="`gettext \"_Exit\"`" + if ! sudo -u "${SUDO_USER}" \ + zenity --question --title "" --text "${dialog_msg}" --default-cancel \ + --ok-label "${launch}" --cancel-label "${exit}"; then + exit 0 + fi +} + +show_start_notification () { + local title="`gettext \"Starting the Unsafe Browser...\"`" + local body="`gettext \"This may take a while, so please be patient.\"`" + tails-notify-user "${title}" "${body}" 10000 +} + +show_shutdown_notification () { + local title="`gettext \"Shutting down the Unsafe Browser...\"`" + local body="`gettext \"This may take a while, and you may not restart the Unsafe Browser until it is properly shut down.\"`" + tails-notify-user "${title}" "${body}" 10000 +} + +maybe_restart_tor () { + # Restart Tor if it's not working (a captive portal may have prevented + # Tor from bootstrapping, and a restart is the fastest way to get + # wheels turning) + if ! tor_is_working; then + echo "* Restarting Tor" + restart-tor + if ! systemctl --quiet is-active tor@default.service; then + error "`gettext \"Failed to restart Tor.\"`" + fi + fi +} + +# Main script: + +CMD="$(basename "${0}")" +LOCK="/var/lock/${CMD}" +CONF_DIR="/var/lib/unsafe-browser" +COW="${CONF_DIR}/cow" +CHROOT="${CONF_DIR}/chroot" +BROWSER_NAME="unsafe-browser" +BROWSER_USER="clearnet" +HUMAN_READABLE_NAME="`gettext \"Unsafe Browser\"`" +WARNING_PAGE='/usr/share/doc/tails/website/misc/unsafe_browser_warning' +HOME_PAGE="$(localized_tails_doc_page "${WARNING_PAGE}")" + +# Prevent multiple instances of the script. +exec 9>"${LOCK}" +if ! flock -x -n 9; then + error "`gettext \"Another Unsafe Browser is currently running, or being cleaned up. Please retry in a while.\"`" +fi + +verify_start +show_start_notification + +echo "* Setting up chroot" +setup_chroot_for_browser "${CHROOT}" "${COW}" "${BROWSER_USER}" || \ + error "`gettext \"Failed to setup chroot.\"`" + +echo "* Configuring chroot" +configure_chroot_browser "${CHROOT}" "${BROWSER_USER}" "${BROWSER_NAME}" \ + "${HUMAN_READABLE_NAME}" "${HOME_PAGE}" "${TBB_EXT}"/langpack-*.xpi || \ + error "`gettext \"Failed to configure browser.\"`" +# If /etc/resolv-over-clearnet.conf file is empty or doesn't exist, we +# have no clearnet DNS server. +if [ "$(stat --format=%s /etc/resolv-over-clearnet.conf || echo 0)" -gt 0 ]; then + mount --bind /etc/resolv-over-clearnet.conf "${CHROOT}"/etc/resolv.conf +else + error "`gettext \"No DNS server was obtained through DHCP or manually configured in NetworkManager.\"`" +fi + +echo "* Starting Unsafe Browser" +# Do not localize the 5th argument: it becomes WM_CLASS and then GNOME +# displays the localized app name found in the matching .desktop file; +# if WM_CLASS were localized then not only string encoding problems +# would happen, but GNOME would pick the wrong icon. +run_browser_in_chroot "${CHROOT}" "${BROWSER_NAME}" "${BROWSER_USER}" \ + "${SUDO_USER}" \ + 'Unsafe Browser' || \ + error "`gettext \"Failed to run browser.\"`" + +echo "* Exiting the Unsafe Browser" +show_shutdown_notification +maybe_restart_tor + +exit 0 diff --git a/config/chroot_local-includes/usr/local/share/mime/packages/unlock-veracrypt-volumes.xml.in b/config/chroot_local-includes/usr/local/share/mime/packages/unlock-veracrypt-volumes.xml.in new file mode 100644 index 0000000000000000000000000000000000000000..58f26152922d33fbd80a323b44001948448b2641 --- /dev/null +++ b/config/chroot_local-includes/usr/local/share/mime/packages/unlock-veracrypt-volumes.xml.in @@ -0,0 +1,9 @@ + + + + <_comment>TrueCrypt/VeraCrypt container + + + + + diff --git a/config/chroot_local-includes/usr/share/X11/xorg.conf.d/90-tails.conf b/config/chroot_local-includes/usr/share/X11/xorg.conf.d/90-tails.conf new file mode 100644 index 0000000000000000000000000000000000000000..f2e6c46afae19c6077fb40eaf43950f7d609802a --- /dev/null +++ b/config/chroot_local-includes/usr/share/X11/xorg.conf.d/90-tails.conf @@ -0,0 +1,6 @@ +Section "InputClass" + Identifier "Tails-touchpad-configuration" + MatchIsTouchpad "on" + Option "TapButton1" "1" + Option "VertTwoFingerScroll" "1" +EndSection diff --git a/config/chroot_local-includes/usr/share/applications/org.boum.tails.additional-software-config.desktop.in b/config/chroot_local-includes/usr/share/applications/org.boum.tails.additional-software-config.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..b043305301412401c3bb06ac8f5a28355b8b17ac --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/org.boum.tails.additional-software-config.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +_Name=Additional Software +_Comment=Configure the additional software installed from your persistent storage when starting Tails +Exec=tails-additional-software-config +Icon=package-x-generic +Terminal=false +Categories=System;Tails; +StartupNotify=true +StartupWMClass=tails-additional-software-config diff --git a/config/chroot_local-includes/usr/share/applications/tails-about.desktop.in b/config/chroot_local-includes/usr/share/applications/tails-about.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..078514871a040e49c4833c1813c17c6d3c44d994 --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/tails-about.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +_Name=About Tails +_Comment=Learn more about Tails +Exec=tails-about +Icon=gtk-about +Terminal=false +Categories=Utilities;Tails; +StartupNotify=true diff --git a/config/chroot_local-includes/usr/share/applications/tails-documentation.desktop.in b/config/chroot_local-includes/usr/share/applications/tails-documentation.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..d7bd7732b7a78f02732889933cc491660674e14e --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/tails-documentation.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +_Name=Tails documentation +_Comment=Learn how to use Tails +Categories=Documentation;Tails; +Type=Application +Terminal=false +Exec=/usr/local/bin/tails-documentation doc +Icon=/usr/share/icons/gnome/48x48/categories/system-help.png +StartupNotify=true diff --git a/config/chroot_local-includes/usr/share/applications/tor-browser.desktop.in b/config/chroot_local-includes/usr/share/applications/tor-browser.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..c73e587780646835a899e4f6d85ce97b6ffaaf27 --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/tor-browser.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +_Name=Tor Browser +_Comment=Anonymous Web Browser +_GenericName=Anonymous Web Browser +Categories=Network; +Icon=/usr/local/lib/tor-browser/browser/chrome/icons/default/default128.png +Terminal=false +Type=Application +Exec=/usr/local/bin/tor-browser %u +StartupNotify=true +StartupWMClass=Tor Browser diff --git a/config/chroot_local-includes/usr/share/applications/unlock-veracrypt-volumes.desktop.in b/config/chroot_local-includes/usr/share/applications/unlock-veracrypt-volumes.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..68727ebb491aef0588d6f559e84dcd8bb60fe9ac --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/unlock-veracrypt-volumes.desktop.in @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +_Name=Unlock VeraCrypt Volumes +_Comment=Mount VeraCrypt encrypted file containers and devices +Icon=unlock-veracrypt-volumes.png +Exec=unlock-veracrypt-volumes %U +MimeType=application/x-tcrypt-container +Terminal=false +Categories=GTK;Encryption;Utility;X-GNOME-Utilities; +Keywords=VeraCrypt;TrueCrypt;Encryption;Volume;Container;Device;Mount;Unlock;Decrypt +StartupNotify=true +StartupWMClass=unlock-veracrypt-volumes diff --git a/config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in b/config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in new file mode 100644 index 0000000000000000000000000000000000000000..7abce9e9d77d6654d5e236c3c8cf112e1d35d63d --- /dev/null +++ b/config/chroot_local-includes/usr/share/applications/unsafe-browser.desktop.in @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +_Name=Unsafe Browser +_Comment=Browse the World Wide Web without anonymity +_GenericName=Uns