2025-06-26-13-33-49: Cronjob

This commit is contained in:
lmn-client 2025-06-26 13:33:49 +02:00
commit 29049c8da1
127 changed files with 7089 additions and 0 deletions

232
LICENSE Normal file
View file

@ -0,0 +1,232 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
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.
lmn-client
Copyright (C) 2024 DigitalSouveraeneSchule
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 <https://www.gnu.org/licenses/>.
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:
lmn-client Copyright (C) 2024 DigitalSouveraeneSchule
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 <https://www.gnu.org/licenses/>.
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 <https://www.gnu.org/philosophy/why-not-lgpl.html>.

42
README.md Normal file
View file

@ -0,0 +1,42 @@
# lmn-client
Ansible playbooks and roles to deploy Debian clients for LinuxMuster.
## Default tasks
* **Install/Update Debian**
* **Install KDE-Plasma Desktop**
* **Join domain**
* **Activate kerberos-support**
* **Mount homes from server**
* **Install printer**
Installs local cups (printserver) and configures/installs all subscribed printers on login. Printers can be subscribed by user or by machine
## Following optional modules are available:
* [custom_roles](doc/custom_roles.md)
Runs own ansible roles.
* [exam_mode](doc/exam_mode.md)
Starts local firewall and removes local directories of exam users the day after.
* [localhome](doc/localhome.md)
Sometimes a local home directory makes more sense than the home on a network share.
* [localproxy](doc/localproxy.md)
Creates a http-proxy running in user context and authentication on parent with users krb5-ticket.
* [localuser](doc/localuser.md)
Creates a local guest user with home on tmpfs.
* [misc_clonescreen](doc/misc_clonescreen.md)
CloneScreen on presenter PCs
* [vm_support](doc/vm_support.md)
VMs based on Qemu/KVM in school network.
* [vpn](doc/vpn.md)
Provides VPN access to school network.
* [wlan](doc/wlan.md)
Provides WLAN access via WPA Personal/Enterprise.
## Installation
Following possibilities:
* [Install client via PXE-Boot](doc/install_pxe.md)
* [Run playbook on existing client](doc/install_ontop.md)
* Install client via USB-Stick including ansible-playbook

50
doc/custom_roles.md Normal file
View file

@ -0,0 +1,50 @@
# Custom roles
- Custom ansible roles can be stored in `roles/custom`
- To include custom roles, you can list them in `custom_roles`.
## Configuration / Variables
* **custom_roles**
List of roles which will be applied
Type: *List of Strings*
Default: []
## Example
All hosts (e.g. 10.0.2.14) will get `role_a` and `role_c`,
but hosts in group laptop (e.g. 10.0.32.14) will get `role_a` and `role_b`
```
roles/custom/
├── role_a
│   └── tasks
│   └── main.yml
├── role_b
│   └── tasks
│   └── main.yml
└── role_c
└── tasks
└── main.yml
```
inventory.yml
```yaml
all:
vars:
custom_roles:
- role_a
- role c
desktops:
hosts:
10.0.2.[1:128]:
laptops:
hosts:
10.0.32.[1:50]:
vars:
custom_roles:
- role_a
- role_b
```

27
doc/exam_mode.md Normal file
View file

@ -0,0 +1,27 @@
# exam_mode
## Description / use cases
Activating exam_mode provides following functionalities:
* when -exam user logs in, firewalld.service will start and prevent communication between devices in the same local network
* home- and media-directory of -exam users will be renamed (on the next day) and removed (after some days).
This is important due the fact, that -exam user will be new created (with new user-id) on exam-mode initialisation.
Without renaming/deleting the home- and media-directory, the -exam user couldn't log in twice on the same pc.
Particularly important on machines with localhome
## Requirements
none
## Example
Per default, all hosts will get exam_mode. But we don't want exam_mode on teacher devices
inventory.yml
```
teacherdevices:
hosts:
10.0.14.[1..75]
vars:
exam_mode: false
```

61
doc/install_ontop.md Normal file
View file

@ -0,0 +1,61 @@
# Installation on existing client
A straightforward way to test the lmn-client is to manually run the playbook on a freshly installed client.
This can be done in the following ways:
On the client using ansible-pull
On the client by checking out the lmn-client repository and running the playbook locally
On a target device by checking out the lmn-client repository locally and executing the playbook against the target device
## Direct call via ansible-pull
With two simple commands you can install the lmn-client with default configuration.
Steps:
* Install debian on client (via USB or PXE)
* Install additional packages: ansible
`sudo apt install ansible`
* Run Playbook
`sudo ansible-pull --verbose -i inventory-sample.yml -l localhost --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C main lmn-client.yml`
## Checkout git and run ansible locally
When checking out the repository you can customize the installation by editing the inventory before run the playbook.
You can repeat the process as often as you like and gradually adapt your inventory settings to your needs.
Steps:
* Install debian on client (via USB or PXE)
* Install additional packages: ansible, git
`sudo apt install ansible git`
* Checkout Repository
`git clone https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git`
* Change into repository directory
`cd lmn-client`
* Create inventory
`cp inventory-sample.yml inventory-myschool.yml`
* Edit inventory-myschool.yml
e.g.: `nano inventory-myschool.yml`
* Run Playbook
`ansible-playbook -i inventory-myschool.yml -l localhost lmn-client.yml`
## Run with other target device
If you want to run the play on an other target pc:
* You have to add the target IP or hostname in the inventory.
* SSH access on target must be configured (deploy ssh public-key on target host)
`ansible-playbook -i inventory-myschool.yml -l target lmn-client.yml`
## Upload changes to your own remote repository
If you are satisfied with your changes, you can upload the changes to your own remote repository.
* Create new git repository on your git service (e.g. https://codeberg.org)
* Add new remote origin
`git remote add myorigin git@codeberg.org:myname/mylmn-client.git`
* Push the repository to the new remote
`push -u myorigin main`

114
doc/install_pxe.md Normal file
View file

@ -0,0 +1,114 @@
# Installation via PXE/Grub
* **Using DigitalSouveraeneSchule repository and LinuxMuster.Net tftp**
Simplest solution. Playbook and default inventory from DigitalSouveraeneSchule codeberg repository.
Linux kernel and initial Ramdisk from debian repository.
Client must have access to the internet (noproxy group).
* **Using your own repository and LinuxMuster.Net tftp**
Here you can use your own inventory and make many custom settings.
Linux kernel and initial Ramdisk from debian repository.
Client must have access to the internet (noproxy group).
* **Using your own repository and livebox tftp**
Additional kernel and Ramdisk from your own infrastrukture.
Client does not need direct internet access.
## Using codeberg repository and LinuxMuster.Net tftp
### Requirements / firewall settings
The computer on which the linuxclient is to be installed must have access to the Internet (add host to noproxy group)
The following resources are downloaded from the internet:
* The repository is provided by codeberg.org
* the Linux kernel, the initial ramdisk and the installation files are loaded from debian.org.
* mscorefonts from Microsoft
### Modification LinuxMuster.Net server
Create grub config for device group `lmnclient` on your schools server:
/srv/linbo/boot/grub/lmnclient.cfg
```
# ### NOT managed by linuxmuster.net ###
# edit to your needs
set default=1
menuentry 'Installer Debian bookworm (amd64) + preseed + ansible inventory' {
echo -n "Enter domain join password: "
read adpw
set vaultpw="dummy"
# echo -n "Enter vault password"
# read vaultpw
linux (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux auto=true priority=high \
url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client/raw/branch/main/misc/preseed.cfg interface=auto \
playbook=lmn-client.yml adpw="${adpw}" vaultpw="${vaultpw}" ---
initrd (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz
}
```
Insert host in devices.csv and set device group to `lmnclient`:
devices.csv
```
classroom;mypc01;lmnclient;F2:81:6B:C9:E3:EF;10.0.5.51;;;;classroom-studentcomputer;;1;;;;;
```
### On client PC
* In BIOS-Setting: Set boot to UEFI
* Start via PXE
* When asked for domain-join-password: Enter password of `global-admin`
* confirm `hostname` and `domain` (you will be asked in network setup)
* ... Get a cup of coffee ... wait until reboot ... login (Logging in may take a few minutes after installation)
## Using your own repository and LinuxMuster.Net tftp
If you fork the lmn-client repository, you can customize the preseeding and inventory to your needs.
Use the instructions in the previous section and customize the repository in `/srv/linbo/boot/grub/lmnclient.cfg`.
It makes sense to encrypt your inventory via `ansible-vault`.
When using encrypted inventories you have to provide the vault password by commenting in the two lines in the `/srv/linbo/boot/grub/lmnclient.cfg`.
## Using your own repository and livebox tftp
The next improvement will be to use your own livebox with following functionalities:
* Providing linux kernel and initial ramdisk for installer
* Can be used as cache for debian packages (aptcacher)
* Can provide mscorefonts and libdvdcss (multimedia codecs)
* Can be used to boot live systems (netboot) via pxe
### Installing the livebox server
* Install debian VM and configure network
* Install additional packages: ansible
`sudo apt install ansible`
* Run livebox playbook
`ansible-pull -i localhost, --url=https://salsa.debian.org/andi/debian-lan-ansible.git -C master livebox.yml`
* Set DNS entry for your new livebox server
### Modification LinuxMuster.Net server
The file `/srv/linbo/boot/grub/lmnclient.cfg` might look like this:
```
# ### NOT managed by linuxmuster.net ###
# edit to your needs
set default=1
menuentry 'Installer Debian bookworm (amd64) + preseed + ansible inventory' {
echo -n "Enter domain join password: "
read adpw
set vaultpw="dummy"
# echo -n "Enter vault password"
# read vaultpw
linux (http,livebox.example.com)/d-i/n-pkg/images/12/amd64/text/debian-installer/amd64/linux auto=true priority=high \
url=https://codeberg.org/MySchool/lmn-client/raw/branch/main/misc/preseed-myschool.cfg interface=auto \
playbook=lmn-client.yml adpw="${adpw}" vaultpw="${vaultpw}" ---
initrd (http,livebox.example.com)/d-i/n-pkg/images/12/amd64/text/debian-installer/amd64/initrd.gz
}
```

64
doc/localhome.md Normal file
View file

@ -0,0 +1,64 @@
# localhome
## Description / Use cases
Sometimes a local home directory makes more sense than the home on a network share.
For example, with:
* Laptops with Wi-Fi connectivity
* Laptops that are also used outside the school network (e.g., teacher devices)
* Devices assigned to a specific user who synchronizes data using a sync client
## Requirements
Nothing
## Activation / Default
To enable the local home directory, set the variable `localhome` to `true` (default: false).
## Configuration / Variables
* **localhome**
This flag indicates whether to use home on local disk.
If set to `true` local user's home will be on local disk.
Type: *Boolean*
Values:
* `false` <-- (default)
* `true`
* **localhome_logout_missing_serverhome**
If this flag is set to `true`, the user will be logged out if mounting the serverhome failed.
Sometimes mounting the server homes fails, but the user still logs in.
For laptops used in schools, it's better to force the server home.
For teacher devices that can also be used outside of school, this flag must not be set.
Type:: *Boolean*
Values:
* `false`
* `true` <-- (default)
## Example
* Hosts in group `laptops` will get the localhome. Teacherlaptops will be part of the `laptop` group (children-entry).
* All computers in the desktop group, except the PC with IP address 10.0.2.33, will have their home directory on the network (default).\
The PC with IP address 10.0.2.33 also has a local home directory.
* Hosts in group `desktop` will have home on net (default).
* If mounting the server home fails on a local home device (except for teacher devices), the user is automatically logged out.
inventory.yml
```
laptops:
hosts:
10.0.1.[1-64]:
children:
teacherlaptops
vars:
localhome: true
teacherlaptops:
hosts:
10.0.3.[1-32]:
vars:
localhome_logout_missing_serverhome: false
desktops:
hosts:
10.0.2.[1-32]:
10.0.2.33:
localhome: true
10.0.2.[34-64]:
```

44
doc/localproxy.md Normal file
View file

@ -0,0 +1,44 @@
# Local http proxy
Some clients encounter difficulties with Kerberos authentication on the HTTP proxy server. To address this issue, we propose setting up a local Squid HTTP proxy that operates as a systemd process in user kontext. This local proxy will authenticate with the parent proxy using the user's Kerberos ticket. Additionally, this setup is ideal for accessing the parent proxy from virtual machines as anonymous user.
The decision to install the local proxy is contingent upon the value of the variable `localproxy`.
Choices:
* `false` <- (default)
* `true`
The parent proxy can be set with the variable `localproxy_parent`.
Default: `firewall.{{ domain }}`
## Configuration / Variables
* **localproxy**
This flag indicates whether to install the local proxy.
If set to `true` local Squid proxy will be installed.
Type: *Boolean*
Values:
* `false` <-- (default)
* "username"
* **localproxy_parent**
This variable specifies the name of the parent HTTP proxy that accepts the user's Kerberos ticket.
Default: "firewall.{{ domain }}"
Type: *String*
## Example
* Enable the local proxy on all devices.
* The parent proxy will be set to `firewall.{{ domain }}` (default).
inventory.yml
```yaml
all:
vars:
localproxy: true
classrooms:
hosts:
10.0.10.[1:80]
```

58
doc/localuser.md Normal file
View file

@ -0,0 +1,58 @@
# Local guest user
Creates a local guest user with home on tmpfs.
The decision whether a guest user is created depends on the value of the variable `localuser`.
Choices:
* `false` <- (default)
* `"username"`
The associated password can be determined using the variable `localuser_password`.
Default: `Muster!`
## Configuration / Variables
* **localuser**
Username of local guest account
If set to `false` no user will be created
Type: *String*/*Boolean*
Values:
* `false` <-- (default)
* "username"
* **localuser_password**
Password of local guest user
Default: "Muster!"
Type: *String*
* **localuser_secretsalt**
Salt for creation of password hash
Default: "4ANAxPycC3q"
Type: *String*
## Example
* Create local guest user only on devices in group laptops.
* Devices in group teacherlaptop will not get a local guest user, even though they are part of the laptop group..
* Username: guestuser
* Password: topsecret
inventory.yml
```yaml
laptops:
hosts:
10.0.14.[1:40]
children:
teacherlaptops
vars:
localuser: guestuser
localuser_password: topsecret
teacherlaptops:
hosts:
10.0.20.[1:80]
vars:
localuser: false
```

56
doc/misc_clonescreen.md Normal file
View file

@ -0,0 +1,56 @@
# CloneScreen on PresenterPCs
Presentation PCs have a habit of displaying the primary screen on the wrong device. Furthermore, the workspace is extended by default instead of mirrored.
These issues can be resolved using the 'misc_clonescreen' variable.
If the login screen appears on the wrong device, this can be corrected using the `dual_screen` variable.
Furthermore, the display devices are mirrored by default instead of extended.
If the cabling does not properly support large screen resolutions, the desired resolution and refresh rate can be set.
## Configuration / Variables
* **misc_clonescreen**
This flag indicates whether to prepare clonescreen mode.
If set to `true` clonescreen will be default.
Type: *Boolean*
Values:
* `false` <-- (default)
* "username"
* **misc_clonescreen_mode**
This variable specifies the resolution and frequency of display.
Default: "1920x1080@60"
Type: *String*
* **dual_screen**
Array with X11 and Wayland naming of desired primary display.
Type: *String*
Example: [DisplayPort-3, DP-4]
* **audio_output**
Array of audio-output device to be selected.
Example: [pci-0000_00_1f.3, analog-stereo]
## Example
* Hosts in group `classroom` will be clonescreen PCs.
* Screen will be cloned and mode 1920x1080@60 (default) will be selected.
* On host with IP 10.0.2.80 screen resolution is limited to 1024x768 at 60 Hertz
* Audio output HDMI (default) is selected.
* On host with IP 10.0.5.80 audio out is preset to analog-stereo
* On Hosts with IP 10.0.3.80 primary screen will be swapped to device with name `DisplayPort-3` (X11) / `DP-4` (Wayland)
inventory.yml
```
classroom:
hosts:
10.0.2.80:
misc_clonescreen_mode: 1024x768@60
10.0.3.80:
dual_screen: [DisplayPort-3, DP-4]
10.0.4.80:
10.0.5.80:
audio_output: [pci-0000_00_1f.3, analog-stereo]
10.0.6.80:
vars:
misc_clonescreen: true
```

44
doc/vm_support.md Normal file
View file

@ -0,0 +1,44 @@
# VM support
lmn_client provides scripts to
* create
* modify
* distribute
* run
VMs based on Qemu/KVM in school network.
## Requirements
* For distribution of VMs, you have to run a `seedbox` with aria2 server (torrent server).
Repository with ansible-playbook for seedbox install: https://codeberg.org/digitalsouveraeneschule/...
* `seedbox`-hostname must be resolvable via DNS
## Configuration / Variables
* **vm_support**
This flag indicates whether to activate VM support.
Type: *Boolean*
Values:
* `false` <-- (default)
* `true`
* **vm_torrent_serv**
Name of the torrent server.
Type: *String*
Default: `vm_torrent_serv: "seedbox.{{ domain }}"`
* **vm_uploadseed_pwd**
Password for upload-seed. Used for image upload to torrent-server.
Type: *String*
Default: `secret = "token:topsecret"`
## Example
Enable VM support on all clients.
inventory.yml
```
all:
vars:
vm_support: true
vm_torrent_serv: "myseedbox.linuxmuster.net" # default: seedbox.{{ domain }}
```

46
doc/vpn.md Normal file
View file

@ -0,0 +1,46 @@
# VPN
Provides VPN access to school network via
- Wireguard
Which vpn method is used is determined by the variable `vpn`
Choices:
* `"none"` <- (default)
* `"wg"`
## Description / use cases
* This module provides a NetworkManager Config with valid wireguard credentials.
* Private/public keys will be created and configured on wireguard-server.
* After VPN-connection is established, network shares will be connected and printers will be installed too.
## Requirements
* You need to run a wireguard server. For installation see https://codeberg....
* The user, running this playbook, must have access to the wireguard-Server via ssh.
## Example
VPN profile will be created on teacher devices
inventory.yml
```yaml
infrastructure:
hosts:
wg_server:
ansible_host: 10.0.0.16
ansible_user: ansible
teacherdevices:
hosts:
10.0.14.[1..75]
vars:
vpn: wg
wg_endpoint: "203.0.113.1:51820"
wg_allowed_ips: "10.0.0.0/16;"
wg_ip_cdr: 24
wg_dns: "9.9.9.9"
wg_dns_search: "example.com"
```

190
doc/wlan.md Normal file
View file

@ -0,0 +1,190 @@
# WLAN support
Supported modes authenticating via WLAN:
* **WPA-Personal** (WPA-PSK)
authentication via preshared key (psk)
* **WPA-Enterprise** (WPA-802.1x) with **EAP-TLS**
authentication via client certificates (eap-tls)
Which method is used is determined by the variable `wlan`
Choices:
* `"none"` <- (default)
* `"psk"`
* `"eap-tls"`
## Common Configuration / Variables
* **wlan**
Authentication mode
Type: *String*
Values:
* "none" <-- (default)
* "psk" <-- set to use WPA-Personal
* "eap-tls" <-- set to use WPA-Enterprise with EAP-TLS
* **wlan_ssid**
SSID of used WLAN
Type: *String*
* **wlan_enable_on_boot**
If set to `true` wlan will be enabled on boot
Type: *Boolean*
Default: `true`
## WPA-Personal
### Requirements
WLAN with configured WPA-Personal (WPA-PSK)
### Additional Configuration / Variables
* **wlan_password**
Password of WLAN. Only for `wlan: "psk"`
Type: *String*
### Examples
#### One class of devices with wlan access
inventory.yml
```yaml
laptop:
hosts:
10.0.13.[1-28]:
vars:
wlan: "psk"
wlan_ssid: "devicesPSK"
wlan_password: "topsecretpasswd"
```
#### Two device classes with different wlan access
inventory.yml
```yaml
laptop_students:
hosts:
10.0.13.[1-28]:
vars:
wlan: "psk"
wlan_ssid: "Students"
wlan_password: "topsecretpasswd1"
laptop_teachers:
hosts:
10.0.23.[1-82]:
vars:
wlan: "psk"
wlan_ssid: "Teachers"
wlan_password: "topsecretpasswd2"
```
## WPA-Enterprise with EAP-TLS
Authentication is based on individual certificates, which will be automaticaly created on the radius server.
Every devices gets his own certificate. When creating new certificates, the old one will be revoked.
### Requirements
* You need to run a freeradius server. For installation see https://codeberg....
* The user, running this playbook, must have access to the radius-Server via ssh.
### Additional Configuration / Variables
* **wlan_eap_ca**
CA data for certs and crl
Type: *Dictionary of Strings*Keys:
* C <-- default: "DE"
* ST <-- default: "Baden-Wuerttemberg"
* L <-- default: "Reutlingen"
* O <-- default: "Linuxschule"
* emailAddress <-- default: "admin@example.com"
* CN <-- default: "Radius Certificate Authority"
* password <-- default: "OtherVerySecurePassw0rd"
* **wlan_force_issue**
Force to issue a new certificateOnly for `wlan: "eap-tls"`
Type: *Bolean*
Values:
* true
* false <-- (default)
* **wlan_eap_ca_crl**
URL of the certificate revocation list
Type: *String*
Default: "http://radius.{{ domain }}/radius-ca.crl"
### Examples
inventory.yml:
```yaml
infrastructure:
hosts:
radius_server:
ansible_host: 10.0.0.15
ansible_user: ansible
laptop:
vars:
wlan: "eap-tls"
wlan_ssid: "devices8021x"
wlan_eap_ca:
C: "DE"
ST: "Baden-Wuerttemberg"
L: "Reutlingen"
O: "Linuxschule"
emailAddress: "admin@example.com"
CN: "Radius Certificate Authority"
password: "secret4radiusCA"
wlan_eap_ca_crl: "http://radius.example.com/radius-ca.crl"
```
## complex example with both modes
We have three groups of devices (one with psk, two with eap-tls):
inventory.yml
```yaml
all:
vars:
wlan_ssid: "WLAName" # teacher and staff are using the same ssid
wlan_eap_ca:
C: "DE"
ST: "Baden-Wuerttemberg"
L: "Reutlingen"
O: "Linuxschule"
emailAddress: "admin@example.com"
CN: "Radius Certificate Authority"
password: "secret4radiusCA"
wlan_eap_ca_crl: "http://radius.example.com/radius-ca.crl"
infrastructure:
hosts:
radius_server:
ansible_host: 10.0.0.15
ansible_user: ansible
laptop_students:
hosts:
10.0.13.[1-28]:
vars:
wlan: "psk"
wlan_ssid: "Students" # ssid "WLAN" from group "all" will be overwritten
wlan_password: "topsecretpasswd"
laptop_teachers:
hosts:
10.0.23.[1-82]:
vars:
wlan: "eap-tls"
wlan_enable_on_boot: false
laptop_staff:
hosts:
10.0.61.[1-20]:
vars:
wlan: "eap-tls"
```
## example: Force issue of new certs
The issue of certificates can be forced.
Force issue of new certs for hosts in group laptop_teacher.
If there is a valid certificate, the old one will be revoked and a new certificate will be issued.
ansible-playbook -i myinventory.yml -l laptop_teachers lmn-client.yml -e "wlan_force_issue=true"

152
inventory-sample.yml Normal file
View file

@ -0,0 +1,152 @@
---
all:
vars:
domain: "{{ ansible_domain }}"
# Comment out on productive systems when ssh key is provided
security_defaultuser_login_disable: false
## Proxy configuration (see: doc/localproxy.md)
# localproxy: true
# no_proxy: "firewall.{{ domain }},server.{{ domain }},.{{ domain }}"
# kerberize_uris: "idam.{{ domain }}, server.{{ domain }}, *.{{ domain }}"
## Configure additional apt options. E.g. Apt-cacher?
# apt_conf: "Acquire::http::Proxy \"http://aptcache.{{ domain }}:3142/\";"
## Configure NTP-Server
# ntp_serv: "server.{{ domain }}"
## NFS-Server for additional mount. Comment out or leave empty to use no additional NFS-Server:
# nfs_server: "files.{{ domain }}"
## List of print servers. The order of the print servers determines which print server the printer will be installed from:
# printservers:
# - "server.{{ domain }}"
# - "print.{{ domain }}"
## PAM mount nextcloud. Comment out or leave empty to skip:
# web_dav: "https://nc.{{ domain }}/remote.php/dav/files/%(USER)"
## Local mirror for mscorefonts. Comment out or leave empty to use no mirror:
# mirror_msfonts: "http://livebox.{{ domain }}/mscorefonts/"
## Local mirror for libdvdcss. Comment out or leave empty to use no mirror:
# mirror_dvdcss: "http://livebox.{{ domain }}/libdvdcss/"
## SSH-keys to deploy:
## passwordless login for default-user (ansible)
##
# keys2deploy:
# - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI........ admin1@example.com'
# - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI........ admin2@example.com'
## Use grub-mkpasswd-pbkdf2 to calculate the password hash:
# grub_pwd: 'grub.pbkdf2.sha512.10000.EF6E2F4F758771751EF4A8A85B1F3F25F35A3AF859DBF0BB8153D9DF6B48D27A2DCDF4ECDC0711D2A93DCBBCF2C4D6FC69D02E1179AB14B62750BDD502C81C95.442C213A064A98E5FF089F3E647C6481327750127D310ABC39596176233C0CE75311EE818EE7F77BD961BBB723A15F853DE6DDD3BF30C7273769C7AC2587CD28'
## Installs VM-support (QEMU/KVM)
## Additional infrastructure (seedbox) nedded. See: doc/vm.md
##
# vm_support: true
# vm_torrent_serv: "seedbox.{{ domain }}"
# vm_uploadseed_pwd: secret = "token:topsecret"
## Additional packages to install
##
# extra_pkgs:
# - vim
# - mc
# - tmux
## WLAN configuration (see: doc/vpn.md):
##
## WPA Personal
# wlan: psk
# wlan_ssid: devicesPSK
# wlan_password: "topsecretpasswd"
#
## WPA Enterprise with EAP-TLS
## Additional infrastructure (radius server) needed. See: doc/vpn.md
# wlan: eap-tls
# wlan_ssid: devicesEAPtls
# wlan_eap_ca:
# C: DE
# ST: Baden-Wuerttemberg
# L: Reutlingen
# O: Linuxschule
# emailAddress: admin@example.com
# CN: Radius Certificate Authority
# password: "secret4radiusCA"
# wlan_eap_ca_crl: "http://radius.{{ domain }}/radius-ca.crl"
## VPN Configuration (Wireguard)
## Additional infrastructure needed (see: doc/vpn.md)
##
# vpn: wg # only set on hosts/groups, which will get wireguard profiles
# wg_endpoint: "203.0.113.1:51820"
# wg_allowed_ips: "10.0.0.0/16;"
# wg_ip_cdr: 24
# wg_dns: "9.9.9.9"
# wg_dns_search: "{{ domain }}"
## Reporter service
## Enable automatic reports
# misc_reporter: true
## Server to which reports should be sent. If you don't want to use reporting, this can be empty:
# misc_reporter_serv: "collector.{{ domain }}"
## Additional roles to run (see: doc/custom_roles.md):
##
# custom_roles:
# - fvs
hosts:
localhost:
ansible_connection: local
laptops:
children:
teacherlaptop: # teacherlaptops will get laptop vars too
hosts:
vars:
## Activate WLAN and select authentication mode (see: doc/wlan.md)
wlan: psk # (none|psk|eap-tls)
## Use localhome on mobile devices
localhome: true
## Create local guest user
localuser: guest
localuser_password: !unsafe Muster!
teacherlaptop:
hosts:
vars:
exam_mode: false
# vpn: wg
extra_pkgs1:
- plasma-discover
- nextcloud-desktop
- dolphin-nextcloud
sudo_permissions:
"%role-teacher":
- /usr/bin/apt
- /usr/sbin/cryptsetup
polkit_rules:
"role-teacher":
- "org.freedesktop.NetworkManager.settings.modify.system"
- "org.freedesktop.packagekit.package-install"
- "org.freedesktop.packagekit.package-reinstall"
- "org.freedesktop.packagekit.system-update"
- "org.freedesktop.packagekit.upgrade-system"
- "org.freedesktop.packagekit.package-install-untrusted"
localuser: false
localhome_logout_missing_serverhome: false
wlan_enable_on_boot: false
misc_avoid_suspend: false
misc_pwroff: false
misc_pwroff_idle: false
misc_reporter: false # privacy for teachers
printer_admin_group: role-teacher
fvs_remove_discover: false # Custom role feature to give teachers package store

680
inventory.yml Normal file
View file

@ -0,0 +1,680 @@
$ANSIBLE_VAULT;1.1;AES256
31313364396663636163346533353463616663623038636364623761663537336162393732616665
3434333865326134343164643636626433613131356139610a303039373364643263376337303135
36626232643937326635393562653937383530653262313634633132643666666465393735303935
6431386665313938320a376163373263333833396234613837646431633536363863303837316139
63393639323933633665306664333339613462653135303934623233326661633666306164326635
64383533326335386232343864383439326463653733663836303038353036653032303661396635
32656664663336343264666432383164386530663636326138633166343365616135336561656237
66333736313166326532633331303237646231383863373536636439333235643531633961376233
63333833333861363130386537363836623361386134633633383534353330303163326439393466
30393663623061343561373834363038333066393163316136373636373061353932396464636330
34373364326333353530366231303833373061363930373336316635623566613033326632303833
66666231653734646336363330633537383633633333376466663539353561383735353830383738
34663332366239633738643437306539633835396131396461386364376233656561346264653330
30373339663364323236376637383938663266346530363965613462306530623166386435663833
37343833323538353933333532643937613363373031646238343365336161393432333065643235
64366638643562653862366263353238633430613330393137383764663263356439666565326265
33373534356233393630636337353734323039363835303834326438303432323731346665383139
31653538666362636232343136323661363138613933326561633033653462633132643435646338
33626661653031633634303938646436656565346163636665636532383632313766323139303936
63356130363366626630386161643566363536656530316131303663663735643434376135333236
64623164663365326563323961323134643761616435376338663539393666336662316661663565
30313731623635353135653434303832343034333538656537663663353263396231643533366634
62656663376564646630366332386434613934663938646139353133666436666538343162306337
61346462313762306563373736373838303562353330663734646136663435373938336533613262
34373432366364333833303437643063663963363031313830343333393738393336343863633432
36643030376164616564323161666136323064316665313662346439303533396639643539623432
39303139373463313730613461333361366266363533373238356336333961313239303336303639
33303637333363646331353265326265373838356361383730633938633535613832356163333534
62343936306366313265356339353361303364383863373935663437653565323335323765306634
35613361333235346162306461643033613866613561626363613131643434613838313237376339
62316335633735663961363830633130306365346431626534356564366532356531323933383663
66393136616230376439643335636166373439663264383738396632366537353466363861643463
36663735666138643362633836663933616665386638626538373533663839666533356437316266
66323162356135636361626131623865653434633666643934613335373463393962353737386438
64636266306464383730336334373433643631333466393965343861343638306431646362313531
34623933313839313930326135383230633932353933623633343436333733646136646330393235
38623034653262393231633534343231626630643730363864633464653465656235363731343138
35376563373730663639313832383831646665326332376134666135366438383765376234653336
64343431393961623331333164626333303338653461366534306664646665313630356164306566
37613633373235623335643137313139623131616262353230343135386434333363313830636632
31363762663333373734643765363366613638356132313763333538333136363537393531383937
63653731353133646235353337663562326162326464613961383862363461353863393665373531
64303161323266643636393337313363616536326536336135396533633062656361323265616438
39386563376530343330633135653037336133306635633564356137333864646262623636396337
35303731363337626635306234613333383065313962326439643834373863383133646337313532
35623237333663613833306236613564393061303864626331366363653132336635623031393838
38653439326464313863303538376536636235666630646232656365363838643538643166643035
30656437343434666335393839626565303434383462313033343430643531303933646561326439
64653734383236613139643061316333323363653930363236633038373931636334326436393931
37353536653462386361626330643236333330626363643466333838323836666237633462653265
36656262326166306463316332643538646365333865373165633330313461333666316530626138
66646136346530313662346331373962343663656363633437613564653031383337393839313833
30666532373865643639356364643636323964303436343735646666363237306630323439636164
33306136303732306537353436636239623437333664323039393030666537663136653032323036
38613763653834303062323365373130626663613862333764353234646136353033663664623265
30643737386465386631666539646366313065326237343430663734313066373731633237353266
65346666323734613039373163316566313839323135396662373839393764653832613866326464
31316332613137313765326631346433313331343561393732333238386533303666633133376538
65386262623433343034333737333364336261373361353934376236333334336631373930663334
61363230326662356131613737626261646539326431326437643235333863656261316436643533
30663364306163386431366263653362353531653564613763393164323061653261633165303433
39383931363130376334343462373566333133386433396261616662336263653364653432373265
34343936613061393062363933636264656464313738393566656162303534336537373265356130
33626237353835383666646130613138313431393630623036383635393930613135623430633737
35383138646363336437333534633464333733643132626130393532643662313762343532316330
36353664383966373034656365366162623430386162356162383235396137386239383265616539
34333835636631303938323132636130353035653834313738353931663630613332616364336438
63643961666562383864396437383530386235623537333762346234333962396464353335643563
61663164623035636639343939636565646565386364333737653734383133623738313563373935
63613530656137356439343763656136343462616139346336373632323036323664306637343366
33383137613235363465646430656230643131666637376331646262633434656235313535363234
34613130336432353535373036333931643765336534313135366238316431326462643166623337
32396135396566323963303937346530303535383136316666363466663266663331326631396461
33313064326532303638366263343936666433353235633436356562336333373332356235643031
32353136333434626234646638616436383930653961643962393165643066633137656131316139
35353432343164303964316638306664386336356263666535663937323666343434306338653364
30636663643339373833366166336331316235363236313837343864643864656665303765303462
30383332363535636338636231376136373364346263363430653733353664326262336166653363
30353335666337613762393431623262336433326563313361343133383930386365643365653361
33643961623636633833643064626263363634656330633136383165393539313139353838663263
36663530383434623263316136616464393033383137323163303135333539306338393163353832
61316162643132363534386563376432623564333732643739393733623061303436353731376365
32393362323037383035353265356530353661333863386533623834346332663935396238613639
36636537373432646162626234353036383863343264333036346362316536653331646133363330
63363432313463653362666263626366643938323766393764323831636336333965623330623232
64646333383461376465373563313361316431666566316235306434663234633261303562613765
34663064373432336362626331353438663235306335396237663639336361316634306362376463
38346363313439376361386530343833666532323562306663666434323565326430633834663530
64376432386164376538653535643961653431326439643264353236323839323637333662346431
61323731353139346664396635633436616332636536656530333939373663386334306364666465
39633364343036356431336637663035326261613331346430366331396361376236306530343739
33666337313538323733303438663133323663393035646638666135343964633730333031346334
64643161393236333533663737363538303961386265373365343434396133633638326665393065
38383062353533373861626239383935333064326638373832333332656138646133323839326435
63373463636364363130616638663136356465356661326637343336333331333266653762393431
37666166343330383535633032333962393362643831613666383662306561336338646465653633
39303239633435326663623932396437623061653530343530663239366232663166343265363662
62326333363037363266613164396133306537326633303938666432636235336136343965633138
38346332646639653063623339346234373664656362643731393732613239663135623134656661
31306136323030323737316634643835323033646637323266326333613063653865356163656138
33383561323432626665356562623731656230313565643664323963373533376661326238663865
63643434646133643663303864353132333530616234656537656233363635346234353064306533
37653861316463303834353134656636356564366565313939663735643666336263376634633662
36636335646532326330336261356362333461346339303433393030383565313164656634626133
35353632616664633432666532633934623931323535643763346164383537636132376365323262
66336539303334613261353733653461376433636633343063346363326565313132346566333638
36653862633339303636646430386562666639383638336137346463656563613863653863363033
32643239373832376335383235656333333931383261666135373564633037373764333231663432
62636165393837393936336466393234343639383138353231383731373838353737346136613164
36316261306430386234656266643531613832353036633032333431316434633538353139393765
62636231646361313464373463306434636566663163383531623735346136636134333339646261
61333564383536373165383463363461343166366139616331653234626166643636643633656662
30383965613637376532643439373365383039396530306634653061363865373737323239386431
61636135643564363936313135373466373361666463623333363739633739323061663237303365
64313633396334303735333132343563323036303936663130643232386265363166303562373665
32333464316439663737313438653537623065616336373865333362383662363033656563313632
65373937613038376634353061313762323266356530656463303339356335363666326164666439
64373037666532303334323262323834346266396431363264323536616531383561373338336466
63616135663233356234386333333761626135666130303933313234396535326530626230326138
64373139363339346334383330663565636336373964613733316235613761326132346464393831
31653236633036653839373338653332323163613463633362656139343233663633393836613131
62616531353333373764636232633230346265633461636135323832643661303730623437656633
36333665323765386265336664373966643336393033363234306139343339353066373164306539
36326638313464366561353261313466666334656231363466633666613862303635393566356364
61613463626130393361636363333630313836623238326534373733663734383632383738613163
39646237663132363064636536363834373565316433383362376338303963386532386365373638
31633766343166303031316465343638373866396436393838613166613166373166616463336439
33383062346562386465303534616463396635353235623236393835626236626236376366626366
35363732633538303966623137666461333434343938383562396235353162383036643637356136
37363134323639633961356466343162353433303438633531616465323938636130396137653130
31346232636537316363316161363531633537313034333637393364303961623534303131666130
37656638323265383135646465346331633036393134666136336633343064646364643930306163
35626635623265303263346230333938646131366336366536353534623963663030303838303036
35306165613335326134353030633036323936356237376631623566323738656139336466663831
62633731323362323333356463326262613739373863626532616564666262636164613031396531
33643834313637303034643232386139303563366261323762363331376363613434616239656566
35343635666233336563646137303265383938623864333062343662383766653164633037373031
34326234333830343630346666316337383837623865653931383436303436346139343831396139
33303937313432656130353439623166313437373164336339353339393639303234313033303233
63343537363164363164636561356635636332306562373063383136666265396334633964353262
32313137366161303032306434343438363034306630646437353036303731656238383335303737
34366435366462643333323436333037393637613962363766353361313066363630323932346162
36396566326265363365376332383161653232343337623131633538393664393234646563356537
65303163313062643233663631396165613038353733363362626631396232326437366664393639
64303635393862376532383438636362353661306165646465613837323939386434353466383061
35303065666336393936653531323939633464333033323863613031326563343335656164373264
61613932626262616363616337353163636335623633626265303564623436333965616362663438
36303030363239613237393433646139373038636335646538643536386561633564633734636538
63383835313432663433393133623365336461323861623361303062376363333630396266396363
35636238313035333333663833373533336530393135393534616564653165623339313963303666
64666134373239663032326266636431363931323633336133383264653362353666373930393265
32613265663939623034373362303965616236653831383466393266653963633637303433623364
66353933323235326636383434323664663662653665623762303030373536646366323232333265
35383765616136316139376230663330363639393038396465653966313931633430623662653830
63626364306436613037613537386433366537363463336532623333636465623638616332383962
37376631343961366539306361386337616364356534643963623766643265613364646462333336
39613432373765303362653663623561363938326665346333383865303862623734353965376238
34396335316266326639343536386430396361623938626565623236353664363736623635306139
32333261383732656531306137363934393566643566333534363532343438633961373734343762
31326139356364326264646336366332663831353632626636663661353561626566623936343431
65636432373238343336356536316162643339323439366530636130373535633136303535623732
31343035623336366237666565326636613138646561613233663738346332313730323334346336
66353963613632636538626433393937373033643338303733633962643964383434346363666533
63646466363431336137663438323532646437316161623934333563356165656234346663383032
32633063653539333730646236616539623332396531653631383133636231363661653439363638
33353632313565363731336266336362613035386138653437643131373066356439643732643964
62313335306236373739633531313233373964333462623663383131323633623337666266323665
33643666383839303366333561313566306139336564653361313265393331643731623265616165
34376234396632626137373335383463366335396661326362363134376131333333373866633639
64666130663163643536343965373166356261333330313030663664356435393035396562623531
33613733323864336433373834353436633537326132313732616436623432656664373566613436
39646566323335333536323636643765306366343633363236336535323632303433323664333634
39643830366238303830323666386431323830616336396163663632333232396530353233636533
32633764643064396463376363623638306133376664663966336636356263356235313936363436
31363338633634393633386538336535633939323661643161393638346438393164393832653239
31613031616564323361333934343437366364343661623966393637636438653536313032653030
38323232393337323332636661663233653530373234643237333061343861336165646364343663
38633263396562666433336162363336313464303666303934653034656231333030626536303763
32633636663061666361313730353738353163323839323265316430333563646639343737633066
37633337616563663637623133393338323033316139346265336634383164653361613835616561
37383161316461383436653231343434666134636462393462313932653937323031313635376165
65373939613235383866306138333033306134386636326562383230373539316661623436303335
30323562633237326237393463613662623163316532646163646630353131626362306333396139
39326334326233623165383135326132666266383664306433636630376165326566323239613835
35346263353534616463383133386365633766303434383163343163613337613565643863323565
63343031363962316136633166653761396666613633356365333133386137366264653039396231
34393731633564393135306664643034306136343862363636643165373863393363643336636663
62363164653730373738313965313737376364343064393565356439366539333335313837393936
66373336333662386166663534663462396365616566636635626562336239613434326132386335
61376366303633666532633835346161356134316266313735613739313562316536333135376632
64313235313663393964386565633831616331313739656331313464393239376439363730643863
61343938646634353135326334373663383738373733343439303964353765616663316238623430
36366336376436366364626636363265363630303232363335666431306432373962376564363461
37323233353131633136376632613439363466316661333666643762353036623164636437366232
62363631643266646633643538316164346134366265333461346365636238626461306339306133
61333130316561303032393134386530323038616238376663356235366431633164353830623530
30393638613064363963383966373838313539663931633831396331383036656565373437303431
34306165663566346261356635653663356132646165396464326231653630613234366139376132
34353765613032333339643265313134643461646664663436633135383332306262343862396165
61613665363930656438633835313264303361393535386533356230323131313963373363656531
62373538663435616338343838333166313161373837323535383239633063303835393736323666
32316364383830326437393133663064316438333062633438656561373330376232333232323232
63396634393132306665663361313937306433653562646561653537653934353366323133303833
33663765626533376331333634306433356636313337356138656463646638333563346635336536
64316166353264353834666537663661336165383032366235623665326664313737396464363836
61653362363436303361386136393562626434626165336362383764393234323138323832653761
31623166376261613464313565663738366230346564656236633865663831383034666666376132
30363437623263303366656565353665646265393331396433616461623536623564633336363638
65343265636533333339356630316366343634663533623430633563313130653163363663373565
34366237623833363863303837336565396461646634366136303465343130386436373033343834
32323762393961663761303538666439323264363231663263653665393635376362326336623565
66613862626436306466333564356331386364323134333230633936376131623034653432363761
66343530316335386233353537343431363336386138353838633837626436653966386361393763
66636666623037643036313034633537646466313930373230346134663032323434386565306131
35393463666536663364396166393534323761386130383066663833373961313237336564306630
34363939363431303366646230653435303437313636373466353930646565316336376264306165
39663461343634373638656431656232363266383334653664616561396637666339386337356131
31356333316363333336353963356633636162646462313131306132383138303733313032643466
35316665343231643733363232306336373033383663633334346162336636633162346535616536
32363735633963363037323439316266323535643832383335343131616431663561623736356637
39663465373132633363623565363235653833383532356339616266653661333264316435323962
65633462356438616161353436353831613332303233663335343538316266303433343537306130
66613263373337646563353566616438656566303332396230306265623239353134656534376639
31643064386131633430316262663431646661663963643736373965303032346563396566666465
62336538313035626263666332386330356230633834306337346131306235663863376239326438
33383137623265396432653134363161383031663062306462346433346135653566633862323437
38663430346239303732623635353738303864623634663163393166666439396135356631333961
37306431353836386138663334303235313731393131653262613936653936363739373637646230
37343434393639343862363836633739326164643932666432613764373635393465383630303462
63353631343338366133663432643637313366653765663439306162643966643365326566346561
63306331386133393634303035393663613761333462363832323866336465316533323832613236
66353934646136373438333463373638393561343130336138633731303161376139376232323439
30396337613163663535396531633539393765316439323734353533303036303861326335343764
66393333386465313038343536663437376138663035333061646261366266333134343863633636
64366538333436396135653237313766633631386531336135623331653265383462376463313263
36613335396661613236366632306637303434396136386633666132373061326134346232343132
61353530663965373961663137353465646265356534313336383930666364623361636332373139
39623933323835363537353839396538303238343633393863393832393464356364336466366536
65616366343234316663346362363639303136313438643432646631343166333262633533636538
65386164666366616662663234363239396462663666643534643365633962633139343037303766
62663162653062373835613564366161343030333363626538663134313366356366373863343531
64366430353038656464326561383439303564616531363265313231653866343838393432383563
32313238666261393263653864643034643233653362303866613737616462313635666439306334
31393263386439653434303962386633386463316231613261333837643539643461363761373261
65313262623865623639636338666434616632363765646133303031666364646461326330383934
33363837653962626135373730626162336365303665636131313564306532343062396435383932
62633037363166656234303363396531653032616264346631353737636164303461316230613536
65663934636131383839366565663130386333643465666366343831643562336234646430343565
39363865326535383466643239353835366131306234383034626666316631366638393834633662
65336632613636323737316165303937323734666365303635353665656636323336616662343466
34316664366232663437333336656532323166346363386338323664666233363264316661666365
32393861383834336631353365313832363330623364396562343564613862393538623131613339
63303563383532306163376637626531646630333630643534303431306439356538353231313635
32376563396332333136626533373231316661313836376532643039386237373066633263636531
63356634646664303762343537303564343363363864336461633566333638303635376561363937
64316265623439396661623862393639326631346366363561336561643161303966376135306631
66323163363834373530363134393464663866303330623530383839613566376162613738363433
32633633626137363234613061306137356237393566356264396366666566383231613332306237
33343861646361373634656563666531396137363531636230343936653462383632363732643130
35376532316135306464636261636462656464363061636165333835346538303564623631303539
35373437396635363337356531316138353961343134303336653038306132613032373263636665
33613931363066326230366564353339396336656239366539373737376134616362663963366264
36343266326239343836343136626130376663353930653132646366343032613231643839626163
38313938626535353735383939626666646439616138333465616239346361373437626139383166
31323033636136376537373661643965343033363861643065303330313864363235316134366436
61383930333531633130623033353532616131643935306635663962313633383932633430646238
64653266313335613731373137613332643436386236333236666561313965386432303731656238
34346662326437313333313939303533333339386135653161363366336335313261323136313539
30313333326165326637376666373835626531633964626361383336623066363066313934636438
64333462376637623130316363633133643337646266363736363839383633303365366334363436
61313765343433666238333363386434373539393539326662383261663834363337666334373466
38336461303763656562343133353139633033656130376266306538626334366564646332323333
30373136373137353765336138393138306331643539346463393162363134353963366434333734
61303062303032663661616465376461663832626335393465376130373466353636303033383733
62303735383964363230333661356237383937616634633166663538323363633535323634616532
36313337663663383938643331616639613732633630323037383339396332623231313531333331
32343037653030663661366533333536336633373563383536656235316162663537323733636263
32663939396463613732616565346166633238653838336365373838663637323439306236376535
31626636656632346664613464373636333233656535346635353362363237626231303537306331
37353365393534643730323937373636333135336539623262396661393530353330366564373662
38333162313965653833313336656431326635333765626632653633663963333439343038323062
31343939663161613338633036323836653436336532376266383230653137636432393761613335
66356664373830613934666266333131393436623165373938323265656564306462663037303630
36653433616233386535366531353733643130346265626433653563353565653565313166343466
65633463623062373934383065366334663634633561343866386530373461636232313661323361
61333263643433373834306164653832383337363236383363383137333232613862663761316239
35363236363031323636623739646331333435306235323365323866366538646261613461336233
64373936363463303662316535303066363864616435383461363164636639343965363132323561
61613566316432326266633131653534386565343332303061323033643933316437643939376530
36366431353432633834313964616264636536383632386330356335323733663166373334386164
37653466393865666563346332633739643063636538323761323139363663323734323738343533
62343362306432656237343836383530303630636230383665366532303136666635323565306364
35646561393462663565343362376136646634373530393936373633653137616163663666363537
64363465346564303965333561396536653234303632633766353362323030653334326230316465
30353434356138623439356432303131623131633763396337363530623463636133356639656535
33613264303439653164373430356536656331393161386534343635656534663862326564306561
39343865393562363561306533616231666330616166306166303163353766393033323663633961
62323864373636613139613835396138623163393466396136303437613738666638643335343935
35663234333630613861383532613830663335653534623537623139656562326435373632366637
39373638653665323137666361613030616132313039353535363330633264653439313432656236
37343965353033363432613961623063363436386433383663353062626432373534626366393633
34383535356365643430353563663864366464666430656339363030333431633133336265303332
39343865323338356563613530656638383537386633653530396638393365613435666333393938
63393961646632336566306437323236623730323737333536376531633462613263343565336136
37356534326334313634636362343439663965336166383832326331396330343531616433643732
65396336623163343037393234373038613932666265306130643064393864373166353339333164
62623962653333613137363635336133613431303738333764383661363964343366303638396230
33383237366161376634613836386239653036643766663466636333623861336464333133323364
34663535393361376564396665323966343963343137613339626639666433316433656362383735
33393862396362626138373637353761623939393736363133323734376232653232393864623865
31396439623264653362326536356131393332646361333364396665363838316139363939353433
39393031396565373637646236313531386632646665356565633034613832306130363635323639
64633439373637623064366436663238633138653539376238663834636565313564363562646639
37616137373437633031386137323361313638663330663561303533616537326631633232623538
33393333353733376130366235616134623431326361363837386164336465373161663234623939
33303834313238366434393835306232613963316666396136343735636238396433336261336363
32366332383666663234393632303461383436383863646535616265616234376137656265646537
34323164323662323638623031643036376533316364333835303337353461636636366134333763
36613232396265626530363963333335623366343232663031663632646633386364393832353062
62616431653435393762353433356337323939373536323239393566393234326537656466343335
38366661373937626632616635656134386136336663633331336239303439343265336164313139
35363965356235303664316332326236376536363932663562666430613563326564353530616233
66376139626633366332356538356434393063383766623066653031353866393065303836616663
66626636376331626138333965356436613839613037623863393336636533353037646632386461
37363761366338633637656131333631376562393064346536653135313932623933623066303537
64643937376163386565353637313966663461306161656433393135333861323035313235306431
34303064653336656231613030323736346438636561383237396266373563653765336164376465
33663838616663646433303664383036663361363333363064623131666331633031356636653031
64643963626638303132333937643433646439386635643238643439393239653637656562373163
39653432356162613566336434643238363938383039303165346237376630623766343165366162
39346564616439613365623937303638666266626434656662376465656463643261356636356232
37366430363339633939643539363934653336643266663537613336333137353731646635643330
37363933363664656336613164623265316437316332333366663338303665383135366163396237
39313634353630356161636536376132303933363437653161303833353963363432393730363935
61353038386339336639326437353366313230333339393831303062333533623039306631346262
36353632626364613464373363313465353932633562616335343133393362613836396634346630
64666535346130343937633830306130313462323734316238386362363636376264643235353632
64663662303532646331653061633333393539656331633236623235613434363662333435616234
37386532633234646539633638343061336566613161373936636265316235636165653362353764
33343039386136666335396635303139343138316233656139666437343336323838353637636265
39636431353336643335616664323637626539326636356531373036633866333831393261653032
30663234646330353362316531613364663733333237316161323534656365656231393230613639
63366335353066646462303264373562363666396632373364653231323366383731656330643563
37616435366364613133373664616239316435353031343939653462666539373639326162623730
61333863623237316430666365363363656332303466303638633865303264653237376365313735
39656531306538353361383136323666326232623838326264363939663837376632353236656164
37326462303333326466393831383063316630356133396465613533373436376138343263376132
66303436366538353965636465323363353831363838393136346435353939323831376539323436
31386632633963383834366433663838376333386265623232376264653862653762363435393464
37323033313861363738663331663462343032623035633536316235306566366133336163313639
34393533646530623532343763306239363635303665373837313433356365633163646661656531
62643035366262653534356139323238333637323761623636646131613938396634383465353437
33336365363465386234633430333535373333363338333061396463313463396238643064313533
36343564633265323530383930646433376439633335323836616266633066656130646632346338
63626535376339373564656534643565623463663632643533333565623033363861626337336230
37616465623538326665613865366264316363363435326636396366313465663361626236636266
30303937376133653930383133656135326434653033373862346239666365393666356339646163
34333636653765643833306630326533386436303632303861366161323062373530613763633439
64393966636533303831396165613439666130373664323035666132333731643533636431353566
38393766363766396631643834326534626338303163376431616334616461393135323135316630
63343630363930383933363238663836653363363237663931323835326535323461636632326465
33646138373430363361333730316430316339366131613430656363383935616661376465656430
30653262366634346666616633306666396166343437666664626537616431636139643161393162
65666435386333306634613436336337666164646261613831353830666662356265386661386439
64393238653435313337363661366331386331386435643164633264373161656338626131666334
38376535333230306633333532303862383633656364613135333233643638643830313565643133
38323831323861623164353434393466346339303530653263386233343131623365356165346637
37343233383138383066653365333538313233316430313332313864356531656466373737396162
34373134636536396366663836393962303034656162333336666637373030623961316631326337
63386433623933313135646438623339653437613232373961356262663934343064363566616363
30326637376438666335323531343532383530623763363930313332323532383837333566663130
36393763343966653766313631616432353165663730316166383931376462336636643762373533
37373463646536366532646465656535316164333032343134356632613237303435336463363031
37643764643034356430323938373966636361623632633333636335323335326662373538303838
30373233383831373833643963636236363766643164346632643333323062613964373966386636
38623934383733366331616166336461383230356563303431333561303132373363376266383330
65653931316635303166646238613137363339633734386266643065643263623463656634316439
65396330663732366465376166323566643636366165613630346636613064663534393835396631
61613465313333623931353065373732393766396461306432663833396537363732353663613464
39383665626635613438646631313661393931303263353034323534633565333136326438343834
63663638363437646638663835613232616335313133386630336162343333303737356337303733
32323932356433383761646539313936396165326536326663613235613937366661336233376463
30656133393163306438323635323830323532316162393564646333373534616262633135373136
30343633373533313831626137313436656134333234396136306465666234613036343164653239
63623830323338623336373435366534343630373432353030396365306131353462383631393463
61643132346463383235663662623266656534313434666631333766613234313337343436613338
37373266303637363933376638316135343833303632336630353638306537636261626466373732
33663738363935356331303733343939376235343766653237613531373662623366333136336333
33616237623862316164306232363931353438336135336564636239363238623739636361353030
34653234376133313037373532666437313539333866303432356163363837633462626266633837
37303433336432656362653131356230356330633732386130623031346666383839383036623339
34353035323662383839376130626338366539643532333037636563313532363562633238373564
64366163373934396366656338643039323033383932393232333262393365363065323735353465
36316632363930626337346565656531366134666465316239363564363565373766626566326263
61386461316439623536383136333238643163346238373532363730306438636565376133653361
64616432376564316435353837373835653730663363366631646133326132333961316336626132
35346537303434633664336234626161616236653130633239653631636133353032336630626265
39393766613432633035383533303735396634633336396664616266373966656137616365663063
30633938653031356638373132306562313165663538613439393465316537343635333434333734
37646561366164633464346465373063303262663330366136616565356430333239363862613563
65633234383431393936373637386165623864333263646237663336313161646536366237666633
62396437636435643338613930623135353663303634373036363730626262383231613665303961
66666531333831303964636337373638336136656164363336373661326438353163316238313636
63303363623864643538653433623333386362643839623462336239643533636135393232393936
30303630383533643461393166636138376531616262656631323639616437313164396663306436
38386533333666666338316662623033616331373763393966313062623866316438666437663365
39663736656365633838313433303564653664356134376430636436363835303364383134653535
62343138333631653561323130376635313539653239366130396262303264386531333465613065
65653262336366613139616364626232313166636665633266346662643337363862363431616334
36353431316431366437326537633161313761346532643865353663383763336462393438323762
35323462666130613661393463643838356133643264303234353866343830393130306232653862
33333066363236613339616333653964303562396430643637396430373532653463613665333032
65303364353733626430353661383634313638633565333535643262333663343132393464653030
61663164366535346666626330366430663363363631663265636637313431613635376666613038
65623863393734626538646362616361323630323566663531633535363334346434313132386564
39613763316563613639353162303637643939303539643934656532366336616330656461353336
61336233396630656431363262623536393332616664386530353037323461346630613338646635
38336362616433656362656236356638666136333231663766316534623061643135353132666236
61346466636237316439306434343937363230636538306466646566623363376134326630323037
33336561616134366437373430383762323065343638653535323764666461396139353462333732
36383232376531396566616236393562393461383566366336323831393163623738386566373364
33383563643566643737636535653861363532316161373730656633323032653535386238386362
65653633313331656135646637323762633732353532623735643833633633313865623135316637
65613565616338313563666363333463323761336337656537376532653466356232313937313964
64316138386632613738306261613233373234306435623131643533646161656431626438663936
63393561643235626439343062653761376336363235343032393030643166313066333562363962
63373562656636353031636136376366396337353463633433326165326530323562363432356363
35333732343335373534373230613935313862623233653632353066656363656232653662623830
62623238613838666366316463656134613634623365353463306365396231653761653432353731
63333739383931383162343761323463396638633231396333316536666536626131313266356233
62306234623334393333323736363838376632356663353164393362613832643234393265313537
33383164613537613665633866303735323436626564636139356664663463326332326166383033
37366364633163366234626434653634616532643766646134633532646263316561356566306230
63323138653032663138346432333338633763353164653961383162626330633334386263363465
32323237366537376665633863346430346333643363376264323835306161653437663138643336
31306263336330626433343733333931343231343662333937363038373561303965383736646564
62663438643339663831623030346130306233623938363737336663333036396638383563393037
65306266616438613034313932336536396564616162383566643531613237616539613632363463
66333163346566663439663262613934623133643163313639363335303462656463613564643464
61626639306231653534343334323732653936623839323565656137666338303338326338346537
66326236613662663731353366623862653063303130663034346137323564343836666537343930
63366239613862626134323837376638326234643634353436383461313732383636303764353135
37326232653136663335643061663139356461313930383762333538636232623730316362383966
34623465323834333431656539663763346662613764393139653533303864373336336262653436
37363433666462323138323063306162666135343766623562373565623664353163356333636430
66623937326633363465643737653435393439666235393166366533313835316662663461373164
36646662383661333039626533376130343039306231643465333737336163373365653231613838
32346666613736383632343566313130363236303739363635393462663934666163356633616162
62313666303637653137633461346439666363636631326462353930373231316163613537383165
30626332366563386437346338353330383830303834613762373938663831333434633937663936
30616634643030313664306533633038393331336630666435303330373932626138313330303135
63396330656530306133633764653638663761326363663865376330356131623035386239623236
39396265303637363135623365306434323739316661393435373731306438633665333864666131
34643235396463386662643837623964623332663634303430386662393262643735396334656366
33653230356365613865353932393963326262323365656561363338336632323837306432633135
65313062643536616236636565383063353662336638366530313633616538363061386663386435
62323631626463323564353939643664373534316363646465633438313464383061653831363364
32623865303637323433666665643662393438383231336335373237303638333130316231666139
31366137663766383237623465363734333739376232653863373539663337623633393434303765
38653638336563336661626338303863636263393833363062363232306661343738303264633465
66333531303432376463323466366638613864323439613136323866626433383262303234376331
30613838643565313861626235626534373831663566623364313837383631346265353562383964
30386565646537383933626432303762356530353862656461363030366639313333353336363835
38613637383633633733626638383933616566616534383466393735376565306438333461626162
36663133363439383862623838636230653236376537633863383564393964633236306637336465
30373034663831343033363464636464373633366539646531633062303663353131636465313332
66623665376534366134353330666566656438613439656636323564613564663063313331356133
35666339633264613236303737373232666333386535313638326232306434356263396535303062
62306230336531323435363638663261353264366363393731313038613661356264336166643135
63306366353463353934623039643037393966383731306430623362663038376565633231636166
66393262616635396138333561303038323633663834386261393966663533313834376535353333
36386664633932363238663766653237303432383330353763373332313237613831636532326230
63323033663730393364633363386263333766653431623538323563353235326336373663623261
64326335363364643135336533386430636139326337346437316436326231636532306338306161
32633236613433636134653965326236653062363962613732306266323834306430303639326437
31383439336664643939346165393936616339353437666534303434613365636566393435333665
33333130383036396566613834316464616264633966396138306236333665333165633032356231
66313030343530613232396562343864343637363035393939373936363936613934636666303464
31333533623365396431393466336165656237366630653763336134363536363130323337383535
32313938626433393835373939636435353633303636313733653133363261376334633764346130
34333862633433613564316261313438656339613335373237316461666462356536353735383064
32623233313862306365656365626232386439613262666563636466373830633436373832613863
65656531366165353431613335323861643961376633356136666332656634326361366464636631
64653161326633313630313431323635373831313938626638663330613562333863343235636366
38653836366536373838653231646138643536353761383136653563373333633737363263646564
62636266343237393766643965303561666463306334376665323531356430303261306435323466
30623863326431313862623765373666336639616636396530656539616335363364323939393331
64303339383565383330356130613932626234303732383731383539366237346436643138633730
61666132353437383330656333353837663964313631303331356330356539356435653264666338
63626662373962613836363237356230383939613434326635373333343234646663313965363730
37393336326539633336666666626533623531343365363563356535653331616336313335323930
33353034356337323838393864333530303366623032316665366261663638333966393337326561
39333036313035356164313566306438316331336431666336663332643664643031643030343537
36333364663331366465316634383030623165346237383336333236633062376232333939376237
38313834616638313064366438666138356336636535613534313262383066363439343933383931
65666638373938376133663839313064383966323262626330633665313462656366373563306565
33623161623838326434666365656133613864356431323432653462346133326430366236333666
34316462303164656164393465396133643061356364363135626534626565336339643637343334
38646238613531636532356466326263393238373962623238346131343737653834356535653834
33653266343730346134633831396361353334393764353733373636383631333838336331636636
64383763303766396332303830363132633361646531343261383339346537613961326231383732
32306631343739303431633639616162356461626466636336653035653332313831653364373839
63393366616438366632373231363166336465323765613632393039363765366239363031626165
36336461343665663964323738316133656530316663643831613331333133623231326661346236
34663032613733376664323938303939626238373437383233326630333634383232303264313939
63343665353435316238313736663735346237343864646334383039656362313761383832383162
39643262626533653939626364613730616233613938626566363464633530623431613865336537
62306532623061373135396639643736383536356133326230393239613937626463333831316431
63666333393237313061396637343037336436613133343039656265363739636638393236306535
31336430356538326136386633656138373637393833393631303838643736623631386261326161
38366463643734326331663465326136663335386561396235393066333834646536326562663537
66626132326635636430643561393134396435616565376134666565353038613637643165613935
35363237366165613964653461323132323163623536393031363638353136326635633462376537
34616137636162346266376237393064646461326234653763653637623630386661336561663066
61333063626132353036633464643135646632306136656331643432666336646536653736386666
38623661616435303439373230616336666537653262613234633730613331336166613434343238
34653234323932343939653164386638393537303663633132383963666362653530613138343362
33393331356338333634666463663932306432623361666534333065313764373537613963656331
39363232343264343863393431323564653232343732363161643564663933653965336632653930
63346531346235363732326435353038663361306539336632393330313030363562626666336562
36303231656334316337386230633339613533636430613739393139643061393361313937356238
66323933323934653636373239353162363034323334333030616562393832306635343166326534
61343130633665616630633838623462396266303039623031313332363631643861313230366133
32623766343363373034313732356565386637303331326133653966393738656535613064393061
38363530636236376235376431303962336231383635393163383333653963326632343931616166
32343666353966383964626561376362343265666133633161303131353438653939383536353232
32323835386431326138373239393737396664333538333934343534376431623130656437316238
36353131333966636665623139343636356436323038366132643265643835383263636264353934
37356564313036663035613834333534303839323166666138636136316631376235646463656536
31343033373839396564653966613734623265393133653932303362656534633461393238643131
30323566633862626232363439613531376561643032353365623362393939323931376562663463
33306530633639313738313662343636633931643736343664363362656466646535626533303766
37373734356535303037393666666363626661376132363934633664343864353133356262366565
37646163323835633965343932366165663831663035656437363235353535653165356631343937
62626564323137333464313762333966353666663338396566336639333133383838353739373164
64386665306164366137373265343165383036623761313339616364666232616536643837626338
35656366306438343933663133306264323962653462336336323239633061663030653537666533
31373733303763653139653432663636653837333964613538396661376235366264346663303534
35396264313936656138373865356532613563316638666165643262316465616566323535623731
33646163646330376230363165363239653464393632663062663536636463333563616462333534
37613364306533386633613436643266343132376636336361393833376161353762366235336561
33373165393733306162346535306566653935666533623237666131623735336162393334653662
39633265376530376237396563363338373434356237323034356634363265666230326533336238
35303634643339633436343838663461343834303939366263393938343461623136646661613466
39353230616331376231303936613439343965643931623330353633323736376363353031316261
31643535306534626362633436643137646232343464333562326334343639613634306262356264
62396436666131326637626364626433396262663061356635613732623061303765633065376336
37316363633034623838393635626161386162313165316564373662386333353831646439653764
66346432333337393666346334613430623739313364356434616261343739393464376362373733
34373938383561363833366337343162386635326135646532326333646133336630393663666532
62666237656662336438303230323839353031396166396462356563326332343232323466616234
36386135313564666430303262346364616261613566636230643736383532646436353066383930
35396330666166663663313739626262643533623233623566646130656166663234656165626662
66613530623365333033373338376135393231316462343933393233656162343665353661383562
31303134386637643363646363323766643533313337316666343332393133343666306132366639
66343464376633626164383866643030346135396435643130356330656335363137356361616339
64303636616633633062613265336238323133653832346438363366323836386662313063313330
33303065376131376363343839366131613231653331333262656464313737663030313531396464
31373531393739623239336135353066383265653464643731303261323638393039313832313761
63373864353935336262643133356333666563353339336163666338613264343233393066646138
38613436393066376338633334373033363638366539633736396536653533643736333431316133
37373035353330316361656166326138663031393563306461643533363736616365636435363632
33323132306165373436643234666561623766376432323935343361666266343563333332633137
36636337613566333663643831333935666565326166383138353064326631343135666331336435
36653038636162323939393963316335653234616362613230653730633237613935663365386437
30616232366538613161396339303636326437623031326435396366316363666338316635636132
32643934303630313563306233643862376366326561393534613761643730383038613566306336
62393335666363666233313437636365393935393364623264373534666465333337656638633438
33616665303263326134356663356133303136343834623430383932353433653766616135396263
66633535383436346265353966376261313432636339643439323630623835393765326434343437
62336332616137353938633662376366623435326539316663623364333861653464373630633236
65653133376665626337323265353438666338313238613563626562383964663237333962316237
35666262306334633862623263646666386432613633613933343637616635643862363036373464
32616564646662326166323330343562366630616232663630363231366634373037313066623866
30653433353631333634373465313737363139363737316436643138383739306265643133393036
38376563633235383764303931643936663137363339643336663039333335363565306263656462
36333431306365663138653134663837656538386366343962303764383365663336653864613763
30333734353364636464643835353261343964303166343031353065353761323061313962663062
37323738633332633330333332333537373863373437353236666538323130326137626665336539
30623963393166643030303837623462333266653833633664656130303563373862636633373938
62653465343866363234366537353734333837306464396433373535366535386634333163303461
63633630366164633162303238353137313731663833333038303235356638353336633539646161
34636238363264653634393565376164643139396166333162326236313236306563323563626633
38363836323739313666366133343865313433666234396433376230626631643539313662626538
65326664613266643466613533313934336266303131636230316430386638373334386433356662
62333738633933336366373835333939623133646633663063383131386163653332383364626664
62333335343538383662353861626462353637633432376565623766353362663234633830323433
37386236363830373261643662656639323665656235613465366131633462663433323035366264
65666630393461393762656538623238656437666135306662353338343439366530383336346661
63326365613334666266306533643036333336623261326135363039643966316361666562376461
64656562393333343766303136366235663337303561326365316664653665363033366138366662
38656238313364373561313539303933613463623261393839356265633937326435663239303662
32356536366634363064323262336530393163383263633965353238343534353230306231626464
31376336323864323461306462343766363765323537313938333665666539663735623161303866
62343061346664323138333136643263353331343462313666306131333936383630386137383136
66313430616137386539623739616531326137393966393066646463306638643330393964376563
39306635333337323234346633353138663366646561353861633438666332646634373563366361
61396139643061303962656637363961623163663565306536333963613033646133313564383333
35653962666263336364346265616633636163616263393336623766316437666165323336656662
64363561363336393936363538363966393039396333363132363938333432653235353637313134
33303732343537636433336234663262616239616334363933616636316464343562633430323865
33393566343038346436346330666164356165303039346333323761623731636138663862316434
31313331386364343738643031303539353766386337383863623163616233323665363632316664
33626531653732353632623032343161303337373135306236326365326361666535636436313934
65306566326663346136646366616636623632383537323738383237343465386430313232316432
30646535633332646639376464616266393131363962386237343663643738393365633331613465
61663138363963643933323836383434623061326231626665333362353934366264653262386538
31353433316138613038626638613133373663343864653565376433316333376436386262633639
39633964373833306565333636633535336138373533663834353862326139333230636464323165
64306564376137656130333239643132326537363932666335343730353331666464363931616536
64306265356535623466326633643161666164326131343738383866623038643763636338643062
30653263653338383962303139353337663039383434333033353966323537623632316630373437
35313831313638613961393765313135346436393833383630346432363734336465336434303762
64363564616630666230313463626532633730386339343832623735323334656330336663366466
34363463623662353163333665336566643232636432646464353561613339303066666633633266
38666438373962376263383065376266393930383838396533366432616263336431653038316533
33346231386633623265396138666166333266653038386237326133366265653263363061643433
61383962653135383939373934386539666162623163663737343539613061656630363636356331
65323362373264393930643936306565333239653337663737646665353930306331336139653432
34386431323438313165333831663062656464663162363565663438353964613835303536303937
34343038333834616665373033386466383863376130656230363638316537626666373135633438
39626130303937346165356666343733353631646533303431346231326563306461623031623930
37633938633061666663376232306234336434363533626432303539363432386532306232336664
32623037643265663465393864646163613436346165373037383665303966656565323664366436
38323764626538663235383064653937346534393333623931616234396133373930656664653630
36666165653930363966373631383931346437376164396438353139396232633734663564323735
66366665396630373932343864396437353661373565646466316563383434336532373862633837
37666433646333303439313933616261616634643739643463383466666332323962643331323637
37653266646234363964663565356430336135313765626337383933366435616261333564376365
36636462313432373663376265656330376636356232333831653964386463353336656563323235
34656563323839643565623038643939333938313862666534386539653366316432326461326531
61633437356530623462623362643739623565333165393432376238336463616339373966613933
65666336613766383331323262306161616335613462333439303763376161373264623463306531
33393131303932653861653838336439396633646465333332663637636162316662626632363731
32373032346139616238326438663237383763343735316261333335353634303964323933333361
61343263336165306235383562653734323664323133363733666630383561636637346238363038
34626239323239663439363063323030386466613365383263623266643630356336383630336465
33393539643566373762313036363436663137383865326231333631623734656535356331623239
36306431313832363037666538626438623066363137376330323361656466316637336534363931
62386334303039346561643561353662303139333564636463663461356166653336323334323033
38636430343132383038636632616564386631313663656330343761646563383039666439373861
33376138363633636135613030373961626362653436663537663663313266373031366266346634
65353839663264643263343561306362323534306632316161366137643665393135306666343662
39326638333161353462393837306332376338353137383262306164323332303061366339613961
33356335323036373332343038646163316239343564363232663137646662666263393765663661
61363330346466613634326539646135386433383433303339323536333435303631393239356339
63336662333965376366353232633665346237663835333164393035333630653861343534656261
35383665343564343132366661626463383236616231396265613531613862646164653435626433
32363136383064396433636432396532623535313664316465663837626236356336326461636235
31613731313032343634366234393736343836616538333731363734653131623664346634323535
64333961633236313737393933626339303030313265316135323837613033616332626137323938
35666332313430376637343336366236383330333865653565656230303036396637343630303834
64346461316133666365386331303366323231376465393139376566666539656238623161353639
62653233336132306134326232656233373133333834636138636531323138353430653762323034
64653632356535313866343765376465363432376535363939356431363264353139313365663734
64323732343536626232356264613136643661376363323361353731333235663431393663396334
35663963363935346333643161316538646530356164346365663466353565373763613233386536
34356666623135396431303765363138346437626439633432353633323837653132303066363861
36363338393565333131343236323833646665353834643238653831323537663664633966356133
66633837623461643362623337323931643338316438393765336538666434393930313663633665
36376264316362386661333563366137666463376237323836373963613437633633363664343031
32613963373931366163616436366339633939353534396464346232636164613138656664343230
39316539663862636663643861343136333065326136663863333631653563336562666634646339
61313537363530383935656233633535333634363838386630616561396539643061653036656339
31633833623564313036353466333538633761363034353232653234306232336661316237643737
63336633316562333130633838643034353264353331616566633935643234616565313734613063
36633334306433623965636364653735313739313963326538646633326461386437303136373336
61643934663364333838633466363466643037396563623734343839343436613537363663633235
63303433316166336432613064663139363264633963616366316664356232623664333838306335
37356534363764653439336532343363643065383366373934636262633835656232323530343933
31666638356138333564636561363731353366306163633665613538386533613830666438663731
33386464356665306263626162313965353433343832383464626265363261316537396236393661
61326538326431343037363632616237646636303563623061393666623235323662653961626335
33623362326538353636363531633839363364613837643731353961333963353836303830656339
37643938653064633766373764316233396365343265643637373133633534393238346332643231
66613337353662323663653066393165386663353634336137663039343933616436383432663064
61656634313736633630346534333234656632396463383131663363303236333966313531333666
39626438366430373038356136303162653530313031333962643538396363343830646434316531
373163643837303136633832363963303664

103
lmn-client.yml Normal file
View file

@ -0,0 +1,103 @@
## This playbook deploys a client for LinuxMuster.
#
# Use the following in the installer's preseed file:
#
# d-i preseed/late_command string \
# mkdir -p /target/home/ansible/.ssh && \
# echo "ssh-ed25519 A...YOUR.KEY...Z" >> /target/home/ansible/.ssh/authorized_keys ; \
# in-target chown -R ansible:ansible /home/ansible/.ssh/ ; \
# in-target chmod -R og= /home/ansible/.ssh/ ; \
# if [ -n "$playbook" ] ; then \
# mkdir -v /target/dev/shm ; \
# in-target mount -v -t tmpfs tmpfs /dev/shm ; \
# echo "$vaultpw" > /target/dev/shm/vaultpw ; \
# in-target ansible-pull --verbose --purge --extra-vars="run_in_installer=true" \
# --vault-password-file /dev/shm/vaultpw \
# -i localhost, --url=git://ansible.example.org/.git -C YOUR_BRANCH $playbook ; \
# fi
#
---
- name: Apply common configuration to the machines
hosts: all # desktop:laptop
remote_user: ansible
become: true
pre_tasks:
- name: Ask for global-admin AD password
ansible.builtin.pause:
prompt: "Enter global-admin AD password. Leave empty to skip domain join"
echo: false
register: adpw
no_log: true
when: "ansible_cmdline.adpw is not defined"
- name: Preseed apparmor
ansible.builtin.debconf:
name: apparmor
question: apparmor/homedirs
value: >-
/srv/samba/schools/default-school/teachers/
/srv/samba/schools/default-school/students/*/
/srv/samba/schools/default-school/examusers/
vtype: string
- name: Preseed unattended-upgrades
ansible.builtin.debconf:
name: unattended-upgrades
question: unattended-upgrades/enable_auto_updates
value: true
vtype: boolean
roles:
- lmn_network
- role: up2date_debian
tags: upgrade
- lmn_sssd
- lmn_mount
- lmn_kde
- role: lmn_vm
when: vm_support
- role: lmn_printer
when: printservers is defined
- kerberize
- lmn_misc
- role: lmn_localproxy
when: localproxy
- role: lmn_localhome
when: localhome
- role: lmn_localuser
when: localuser
- role: lmn_exam
when: exam_mode
- role: lmn_wlan
when:
- ansible_interfaces | select('search', 'wl.+') | first is defined
- wlan != 'none'
tasks:
- name: Include custom roles
ansible.builtin.include_role:
name: "custom/{{ rolename }}"
loop: "{{ custom_roles }}"
loop_control:
loop_var: rolename
when: custom_roles is defined
- name: Final tasks
ansible.builtin.include_role:
name: "{{ role }}"
loop_control:
loop_var: role
loop:
- lmn_security
- lmn_finish
- lmn_tmpfixes
- name: Apply roles that must run serial
hosts: all
remote_user: ansible
become: true
serial: 1
ignore_unreachable: true
roles:
- role: lmn_vpn
when: vpn != "none"

107
lmn-vault Normal file
View file

@ -0,0 +1,107 @@
$ANSIBLE_VAULT;1.1;AES256
30323066396237616634646638353133663731623734383863373431363930356262636162323264
3737353636623963643737353762663064663935306631320a353231326664353433633339363733
33333038346638316335333534636163333564633137663063646334333832633935323763336633
3662303830303363380a663633643139343630373838383337346631366539636333346666383434
37336232376466613665313934616537313064653566353763613161613866393139656165363835
61336131343162313566363562303464623938313036396463376463636334356561666136666161
36333131663432336238303831626137323635323636633966336639616265656637363432393436
65636338646234363863373666366131333333356166313933376331666633653132396161616661
32663932666531393066623935663462353534373666313465663034343438303331303632633863
33623534653031393431646238356135326130643362363238366666306161353237376461356338
33393738323338643764356363646530653938313633393730323036323030623236643133396366
31313837336438393035373936656662633330643933323039356539386133653764326639343938
38323863643338613564633964646432306664353163666231616135353235616233623632623564
32616636376539303132376130343966666261646434626366393262643131356230353937663530
66396235333839633461323139663431343634633634663865373564613133633465353861326430
65356163653162363237303839353930636163663136393831613964306334663863323034336333
37396265666538316630333937366234366636316233393430353334633433663461626263346666
61646532613562333663653162356533356465313764363032666166366365636465653037343734
39613730396262343039373433346237316131343832656539346365383133623964383764393832
33333138386264376161653261656563613738643563663238656562333066626137656164393036
62643938656138356134303666353332643263643238326137386264356632616138613436373331
64653730663332393964323831336332396233333031633832643564313238643334303132393536
31356633656536306237346366633461353661386530303663376133666562346565356438323036
35643266646136373132653537646138356238306130613034656539396230356633386330333933
34393435376266666361383164666266663563396466393239653362663232366164376137376166
33663634313236366563656537366535363264623861646564336466363665343433383532666562
66326332636536363836383135343361663636393138623362643636623533363931396563353261
66383565616432616361353338303038663730343566653438336661656431303837393464643466
65386436396132323261313361343164393163303830653736626637383531613432343435396630
66373831396264646464353565363633333666333361386639353165643566376430653264316432
37353163323337643461636331646561313465383032383761373665336666303535333363613862
66386132636133623263366436326131666632623238356530396361323962316463666261353137
34366266303739613462386235616337383334633234336261613231366131316535373866306133
61356438356235303335363638663861383332383931343032326238383536623437313039383639
31663632613135383037313032623064623633376663656634323534373463343932323964313464
62656134623836333835633061626331623461653565336438636431306434323638666336623862
63343835623661633534646437616134623962323139363265306462656633653463616366613232
38613830336639316139643732373938396435363966663330366335303232666563303633633463
33366663623062393262323530633163363363343930343265363430303130303436376664646431
65303263626263653865343161363064386163323636663264353539393031383639303835636461
32666462373063346431353732346330636432643534633538316638316661393866303039346333
32623637336434333836303936613066313562373834653338613139326337366664666231393863
62653333353736383431383534313164346639663037643366333931633539343137356464643236
39396561306565666262303337316532623564653632353533316235643732656336613730643361
36303761346165353561616364326430343763323966643238616630643639323639663932306139
63333733643536376132383236343937313639623763663161323835353333313838346136386533
31383065373030623231626533343333646339643231373936663336303834666639623431366336
37653361313161393433363039633139373338346230366465343261326535303331616437396264
62356533636436663532663233353938623265663139376636653532303561356130336630393432
62646331326163366336373164333839626666636335303836363766346264363931626161643039
62613139306634323162613131393739373133343034373633353532616637373666613131326337
37613437323132396132333030386132613538313339656234366435383561656331326238306563
61616133336365656662333064326233313630646633386138333533386435356262323737316335
64313862366533373235633161363139376638336331373163653762396666373536333663313963
34396134613633333631653930373965393532313038616331386332376432613032653537356334
38636362623539336134613832313065653539646366343430356431653361333662323334653663
61326561313433363561633631653039386662383766326136363266353536393063643532363038
35613866313634313434636463663138636165356432336234613032336635636263336439313061
30666639316665353733653338376162643338316533613632303433646239663138376536636330
32386234626430393833666263623135386561633230326664313137343463336631363763643931
39616139396261393366313736636265303466333533336430663439303239373963666333613537
35363138653831653435626132383135633631386462633038363966313838663236396532366163
62616165376635613164326439623563653037616638383032326339346230663935376635383263
62306532323764633631366535383233316335316439393539313565306465353365343636333462
62616231393035646235643734373764326334643366613135346433653639303864323464343034
31303161353963663839373565396466353033333165316134633936653161346436326362643534
32366665633338323130633737613934343031323766663164633134373464656132303735316337
66663361333136333839653062373133343761386439323463643336303137383932386665326136
64356531353933383235633039326266666232303764326338366462653834623736336362653233
35353963356231613539656630623334663763313837383261663163343266613463613366666430
66396534663531633261336162366436333534633461636136643230336466636265663531356336
62336565646234303765323866316562396561316464393636356262313663316437393634656238
63613530303164653264373863336238646666323938303631366162636265643161616433343232
35343638396437376337306262643161626234636338643264396362653836653337633632303166
65663133396462316466663038346565623132356631343865613462323035666537343134363436
32373539303763373134336534643930636234643338376536376666346561393731316666343364
36653561303563646233653865353736356537343938383930336130623964623866313539636335
32666536396538313032613939666632333839303062386366353639613862653134323162643533
62663131303233323666353336363461646231376163343563396463356634653532633266306433
34363930656562366563643937633862646565393930303537626338623631313436613564616530
39353663623939313235306231373537393535326238623038633232366131303730333838663838
65366437333665333364336535303434383934663532303035313639646635653833666566383163
32666334373237326266366337353636636465613963366538326362363132653466333634333534
63366537653866346133353635356332656164336632333465316363376238653563316661386132
64343063306663376430363163323161336166313762613066663061346236343731343836643731
32306365656534353733356561373561386334373661303530326332333061636536363364386233
63313035653166313164333537313662636136613565323433333738376237626263373538336266
35646633663165396366613162616338616532383437383630663061666338616131356534656636
36353036326533316339313833356466386163343065653037363038303239643361306335353262
66393361363936373630326533306164366237353161346335303136633561363265643135363165
63333833656637636635363931393965663933396265643239363939363337396666633366373233
37656630376262643836643063383762623331653761353030333736366462663964363032626536
63363136343464373230353330313830653730333438393238393232353932316337616636356138
61326638613433666131643830323565623466643333373432323330626265326363356161326538
61336537666137333166333439343535313135323438376633326535343964626136386138633038
62363432613861356134376237393436356361373839316637376234303566313164666534663837
37613763653636363231396163616236626662323761353065383535623266616561323733326437
65666662386163643232613664346432386233643534626335353336346561303032653163346234
61333164613832386631316430643537303161613161613631363534366166303834363230643839
34363233656165623236323634313566373166373565353837303162313262333035663738326637
34313435643630393738613462373034303264653964393563393739386537653836363833383534
37383937316166333533633161643463353961393737353561343933613830623061346235353263
64633839396466393361383462636635653464343239303736656561303033386465323036323964
32356536356437643436396162643334653631636339363161373437666538396430343162366139
39343564366338363965633139633338376436353230356134633163316362393032653561613763
6465303166646337336264633666363638643436333466306565

44
lmn-www-server.yml Normal file
View file

@ -0,0 +1,44 @@
## This playbook deploys a FvS web server machine.
---
- name: apply configuration to the web server
hosts: all
remote_user: ansible
become: yes
pre_tasks:
- pause:
prompt: "Enter global-admin AD password. Leave empty to skip domain join"
echo: false
register: adpw
no_log: true
when: "ansible_cmdline.adpw is not defined"
vars:
domain: "pn.steinbeis.schule"
extra_pkgs:
- vim
- apache2
- python3-flask
extra_pkgs_bpo: [ ] # [ libreoffice ]
roles:
- up2date_debian
- lmn_extrapackages
- lmn_sssd
- kerberize
tasks:
- name: Override home dir location
lineinfile:
dest: /etc/sssd/sssd.conf
line: override_homedir = /home/%u
- name: enable pam_mkhomedir.so
lineinfile:
dest: /etc/pam.d/common-session
line: "session optional pam_mkhomedir.so umask=0026"
insertbefore: "session optional pam_mount.so"
- name: enable apache mod userdir
apache2_module:
state: present
name: userdir

151
misc/preseed.cfg Normal file
View file

@ -0,0 +1,151 @@
#### Preconfiguration file
##
## The following preseeding might be used to install a basic system
## completely automatically.
##
## A user 'ansible' is set up and ssh login with public key
## authentication is configured. The idea is to allow further
## customization of the system after installation using ansible.
##
## Modify at least the public ssh key in 'authorized_keys' (see
## below).
##
## For more examples and comments consult:
## https://www.debian.org/releases/stable/example-preseed.txt
##
## To change default values:
#d-i foo/bar seen false
#d-i foo/bar string value
## Useful boot parameters:
## DEBCONF_DEBUG=5
## locale?=de_DE
## To set the hostname manually during installation, use priority=high
## as boot parameter and uncomment this line:
d-i debconf/priority string critical
## Preseeding only locale sets language, country and locale:
d-i debian-installer/locale string de_DE
d-i keyboard-configuration/xkb-keymap select de
## Use hostname assigned by DHCP:
d-i netcfg/get_hostname seen true
d-i netcfg/get_domain seen true
#d-i netcfg/get_hostname string unassigned-hostname
#d-i netcfg/get_domain string unassigned-domain
## Skip root account:
d-i passwd/root-login boolean false
# If non-free firmware is needed for the network or other hardware, you can
# configure the installer to always try to load it, without prompting. Or
# change to false to disable asking.
#d-i hw-detect/load_firmware boolean true
### Apt setup
d-i apt-setup/non-free-firmware boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/contrib boolean true
d-i mirror/country string manual
d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/directory string /debian
#d-i mirror/http/proxy string http://aptcache.pn.steinbeis.schule:3142/
d-i mirror/http/proxy string http://10.16.1.251:3142
# NTP server to use:
d-i clock-setup/ntp-server string 10.16.1.1
### Backports:
#apt-setup-udeb apt-setup/services-select multiselect security, updates, backports
apt-setup-udeb apt-setup/services-select multiselect security, updates
### Ansible User
d-i passwd/user-fullname string Ansible User
d-i passwd/username string ansible
d-i passwd/user-password password insecure
d-i passwd/user-password-again password insecure
#d-i passwd/user-password-crypted password [crypt(3) hash]
### Do not ask about support for non-efi systems:
d-i partman-efi/non_efi_system boolean true
### Leave this empty to use the only available hard drive:
d-i partman-auto/disk string
#d-i partman-auto/disk string /dev/sdd
#d-i partman-auto/disk string /dev/vda
### Regular partitions:
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
## This makes partman automatically partition without confirmation:
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# ### Enable to set up LVM:
# d-i partman-auto/method string lvm
# ## Use only 50% of the available physical volume size and then
# ## adjust the logical volume sizes later with ansible, if needed:
# d-i partman-auto-lvm/guided_size PERCENT 50%
# # If one of the disks that are going to be automatically partitioned
# # contains an old LVM configuration, the user will normally receive a
# # warning. This can be preseeded away...
# d-i partman-lvm/device_remove_lvm boolean true
# # The same applies to pre-existing software RAID array:
# d-i partman-md/device_remove_md boolean true
# # And the same goes for the confirmation to write the lvm partitions.
# d-i partman-lvm/confirm boolean true
# d-i partman-lvm/confirm_nooverwrite boolean true
# # You can choose one of the three predefined partitioning recipes:
# # - atomic: all files in one partition
# # - home: separate /home partition
# # - multi: separate /home, /var, and /tmp partitions
# d-i partman-auto/choose_recipe select multi
# Enable popcon:
popularity-contest popularity-contest/participate boolean true
### Package selection
#tasksel tasksel/first multiselect standard, ssh-server, gnome-desktop, print-server
tasksel tasksel/first multiselect standard, ssh-server, kde-desktop
### Individual additional packages to install
#d-i pkgsel/include string firmware-linux ansible git
d-i pkgsel/include string ansible git firmware-linux
#d-i pkgsel/include string firmware-linux ansible/buster-backports git
#d-i pkgsel/include string firmware-linux
### GRUB on default disk:
d-i grub-installer/bootdev string default
### This command is run just before the install finishes:
d-i preseed/late_command string \
if [ -n "$playbook" ] ; then \
mkdir -v /target/dev/shm ; \
in-target mount -v -t tmpfs tmpfs /dev/shm ; \
echo "$vaultpw" > /target/dev/shm/vaultpw ; \
in-target ansible-pull --verbose --purge --extra-vars="run_in_installer=true" \
--vault-password-file /dev/shm/vaultpw -l localhost \
-i inventory-sample.yml --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C main $playbook ; \
fi
#
## When installing in combination with ansible-pull,
## export your ansible playbook like:
##
## git daemon --verbose --export-all \
## --base-path=/dir/of/playbook -- /dir/of/playbook
##
## Conditions may be applied in the playbook like:
## when: run_in_installer|default(false)|bool
## when: not run_in_installer|default(false)|bool
### Avoid that last message about the install being complete.
d-i finish-install/reboot_in_progress note
## Do not modify boot order (netboot first):
grub-efi-amd64 grub2/update_nvram boolean false
##grub-efi-amd64 grub2/force_efi_extra_removable boolean true

View file

@ -0,0 +1,2 @@
---
fvs_remove_discover: true # Remove discover to disable update_notify

View file

@ -0,0 +1,113 @@
// configure plasma defaults
function forEachWidgetInContainmentList(containmentList, callback) {
for (var containmentIndex = 0; containmentIndex < containmentList.length; containmentIndex++) {
var containment = containmentList[containmentIndex];
var widgets = containment.widgets();
for (var widgetIndex = 0; widgetIndex < widgets.length; widgetIndex++) {
var widget = widgets[widgetIndex];
callback(widget, containment);
if (widget.type === "org.kde.plasma.systemtray") {
systemtrayId = widget.readConfig("SystrayContainmentId");
if (systemtrayId) {
forEachWidgetInContainmentList([desktopById(systemtrayId)], callback)
}
}
}
}
}
function forEachWidget(callback) {
forEachWidgetInContainmentList(desktops(), callback);
forEachWidgetInContainmentList(panels(), callback);
}
function forEachWidgetByType(type, callback) {
forEachWidget(function(widget, containment) {
if (widget.type == type) {
callback(widget, containment);
}
});
}
function widgetSetProperty(args) {
if (!(args.widgetType && args.configGroup && args.configKey)) {
return;
}
forEachWidgetByType(args.widgetType, function(widget){
widget.currentConfigGroup = [args.configGroup];
/*
//--- Delete when done debugging
const oldValue = widget.readConfig(args.configKey);
print("" + widget.type + " (id: " + widget.id + "):");
print("\t[" + args.configGroup + "] " + args.configKey + ": " +
oldValue + " => " + args.configValue + "\n");
//--- End Debug
*/
widget.writeConfig(args.configKey, args.configValue);
});
}
// configure task bar starters:
widgetSetProperty({
widgetType: "org.kde.plasma.icontasks",
configGroup: "General",
configKey: "launchers",
configValue: [
"applications:systemsettings.desktop",
"preferred://browser",
"applications:thunderbird.desktop",
"applications:libreoffice-startcenter.desktop",
"preferred://filemanager"
//"applications:org.kde.konsole.desktop",
//"applications:org.kde.discover.desktop"
],
});
// kickoff is the default menu:
/* this does not work (anymore?)
widgetSetProperty({
widgetType: "org.kde.plasma.kickoff",
configGroup: "General",
configKey: "favorites",
configValue: ["applications:libreoffice-startcenter.desktop",],
});
*/
widgetSetProperty({
widgetType: "org.kde.plasma.kickoff",
configGroup: "General",
configKey: "systemFavorites",
configValue: ["reboot", "shutdown", "logout"],
//configValue: ["logout"],
});
// prepare a folder view on the desktop:
/* 20230917 disabled for now
var allDesktops = desktops();
for (var desktopIndex = 0; desktopIndex < allDesktops.length; desktopIndex++) {
var d = allDesktops[desktopIndex];
d.addWidget("org.kde.plasma.folder", 50, 50, 456, 600)
print("Folder app generated!\n")
}
widgetSetProperty({
widgetType: "org.kde.plasma.folder",
configGroup: "General",
configKey: "url",
configValue: "/lmn/media/",
});
widgetSetProperty({
widgetType: "org.kde.plasma.folder",
configGroup: "General",
configKey: "labelMode",
configValue: "0",
});
*/
// /usr/share/plasma/shells/org.kde.plasma.desktop/contents/updates/fvs-config.js

View file

@ -0,0 +1,5 @@
[Desktop Entry]
Type=Directory
Name=FvS
Icon=face-smile-big
#X-KDE-BaseGroup=info

View file

@ -0,0 +1,12 @@
<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
<Name>Applications</Name>
<Menu>
<Name>FvS</Name>
<Directory>fvs.directory</Directory>
<Include>
<Category>fvs</Category>
</Include>
</Menu>
</Menu>

View file

@ -0,0 +1,6 @@
if [[ "$UID" -gt 10000 ]] && [[ ! -f ~/.local/share/user-places.xbel.lmn ]] ; then
(sleep 30 ; lmn-patch-dolphin.sh) &
fi
if [[ "$UID" -gt 10000 ]] && [[ -f ~/.local/share/user-places.xbel ]] ; then
lmn-fixhome-dolphin.sh
fi

View file

@ -0,0 +1,20 @@
#!/usr/bin/bash
set -eu
file="${1:-$HOME/.local/share/user-places.xbel}"
[[ -e "$file" ]] || exit 0
if id | grep -q teachers; then
exit 0
fi
NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
[[ -d $NETHOME ]] || exit 0
if FOUND=$(grep -o "/srv/samba/schools/default-school/students/.*/$USER" $file); then
if [[ "$NETHOME" != "$FOUND" ]] ; then
sed -i "s|/srv/samba/schools/default-school/students/.*/$USER|$NETHOME|g" $file
fi
fi

View file

@ -0,0 +1,89 @@
#!/bin/bash
#
# patch 'Tausch' and 'Nextcloud' into dolphin's bookmarks
#
set -eu
file="${1:-$HOME/.local/share/user-places.xbel}"
[[ -e "$file" ]] || exit 0
if grep -q "Tausch\|Nextcloud" "$file" ; then
echo "Your Dolphin seems to already contain 'Tausch' and/or 'Nextcloud'." | tee "$file.lmn"
exit 0
fi
id="$(grep ID "$file" | sed -E "s|^.+ID>([[:digit:]]+)/([[:digit:]]+)</ID.+$|\1:\2|" \
| sort -n -t: -k2 | tail -1 )"
if id | grep -q teachers; then
NETHOME=/srv/samba/schools/default-school/teachers/$USER
else
NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
fi
[[ -d $NETHOME ]] || exit 0
IDENTITY="${id%%:*}"
NUM0="${id##*:}"
NUM1=$(( NUM0 + 1 ))
NUM2=$(( NUM0 + 2 ))
NUM3=$(( NUM0 + 3 ))
if [[ $HOME =~ ^/home/ ]]; then
HOMEONSERVER="+ <bookmark href=\"file://$NETHOME\">
+ <title>Home@Server</title>
+ <info>
+ <metadata owner=\"http://freedesktop.org\">
+ <bookmark:icon name=\"user-home-symbolic\"/>
+ </metadata>
+ <metadata owner=\"http://www.kde.org\">
+ <ID>$IDENTITY/${NUM1}</ID>
+ <isSystemItem>true</isSystemItem>
+ </metadata>
+ </info>
+ </bookmark>"
else
HOMEONSERVER=$'+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+'
fi
patch="
--- a/$file
+++ b/$file
@@ -98,9 +98,45 @@
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
$HOMEONSERVER
+ <bookmark href=\"file:///srv/samba/schools/default-school/share\">
+ <title>Tausch</title>
+ <info>
+ <metadata owner=\"http://freedesktop.org\">
+ <bookmark:icon name=\"folder-publicshare\"/>
+ </metadata>
+ <metadata owner=\"http://www.kde.org\">
+ <ID>$IDENTITY/${NUM2}</ID>
+ <isSystemItem>true</isSystemItem>
+ </metadata>
+ </info>
+ </bookmark>
+ <bookmark href=\"file:///lmn/media/$USER/nextcloud\">
+ <title>Nextcloud</title>
+ <info>
+ <metadata owner=\"http://freedesktop.org\">
+ <bookmark:icon name=\"folder-cloud\"/>
+ </metadata>
+ <metadata owner=\"http://www.kde.org\">
+ <ID>$IDENTITY/${NUM3}</ID>
+ <isSystemItem>true</isSystemItem>
+ </metadata>
+ </info>
+ </bookmark>
<bookmark href=\"remote:/\">
<title>Network</title>
<info>
<metadata owner=\"http://freedesktop.org\">
<bookmark:icon name=\"folder-network\"/>
"
echo "$patch" | patch -z '.lmn' --fuzz=0 --backup "$file"

View file

@ -0,0 +1,222 @@
#!/bin/bash
sed -e "s|HOME|/${HOME##/srv/samba/schools/default-school/}|g" -e "s|USER|${USER}|g" > ~/.local/share/user-places.xbel <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xbel>
<xbel xmlns:mime="http://www.freedesktop.org/standards/shared-mime-info" xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks" xmlns:kdepriv="http://www.kde.org/kdepriv">
<info>
<metadata owner="http://www.kde.org">
<kde_places_version>4</kde_places_version>
<GroupState-Places-IsHidden>false</GroupState-Places-IsHidden>
<GroupState-Remote-IsHidden>false</GroupState-Remote-IsHidden>
<GroupState-Devices-IsHidden>false</GroupState-Devices-IsHidden>
<GroupState-RemovableDevices-IsHidden>false</GroupState-RemovableDevices-IsHidden>
<GroupState-Tags-IsHidden>false</GroupState-Tags-IsHidden>
<withRecentlyUsed>true</withRecentlyUsed>
<GroupState-RecentlySaved-IsHidden>false</GroupState-RecentlySaved-IsHidden>
<withBaloo>true</withBaloo>
<GroupState-SearchFor-IsHidden>false</GroupState-SearchFor-IsHidden>
</metadata>
</info>
<bookmark href="file:///srv/samba/schools/default-schoolHOME">
<title>Home</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="user-home"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/0</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Schreibtisch">
<title>Desktop</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="user-desktop"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/1</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Dokumente">
<title>Documents</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-documents"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/2</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Downloads">
<title>Downloads</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-downloads"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/3</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Musik">
<title>Music</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-music"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/6</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Bilder">
<title>Pictures</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-pictures"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/7</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-schoolHOME/Videos">
<title>Videos</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-videos"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/8</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///srv/samba/schools/default-school/share">
<title>Tausch</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-publicshare"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/9</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="file:///lmn/media/USER/nextcloud">
<title>Nextcloud</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-cloud"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/10</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="remote:/">
<title>Network</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-network"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/4</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="trash:/">
<title>Trash</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="user-trash"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/5</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="recentlyused:/files">
<title>Recent Files</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="document-open-recent"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/9</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<bookmark href="recentlyused:/locations">
<title>Recent Locations</title>
<info>
<metadata owner="http://freedesktop.org">
<bookmark:icon name="folder-open-recent"/>
</metadata>
<metadata owner="http://www.kde.org">
<ID>1682498425/10</ID>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</bookmark>
<separator>
<info>
<metadata owner="http://www.kde.org">
<UDI>/org/kde/fstab///server/default-school/:/srv/samba/schools/default-school</UDI>
<isSystemItem>true</isSystemItem>
<IsHidden>true</IsHidden>
</metadata>
</info>
</separator>
<separator>
<info>
<metadata owner="http://www.kde.org">
<UDI>/org/kde/fstab///server/default-school/:/lmn/media/USER/home</UDI>
<isSystemItem>true</isSystemItem>
<IsHidden>true</IsHidden>
</metadata>
</info>
</separator>
<separator>
<info>
<metadata owner="http://www.kde.org">
<UDI>/org/kde/fstab///server/sysvol/:/srv/samba/USER/sysvol</UDI>
<isSystemItem>true</isSystemItem>
<IsHidden>true</IsHidden>
</metadata>
</info>
</separator>
<separator>
<info>
<metadata owner="http://www.kde.org">
<UDI>/org/kde/fstab///server/default-school/:/lmn/media/USER/share</UDI>
<isSystemItem>true</isSystemItem>
<IsHidden>true</IsHidden>
</metadata>
</info>
</separator>
<separator>
<info>
<metadata owner="http://www.kde.org">
<UDI>/org/freedesktop/UDisks2/block_devices/sda2</UDI>
<isSystemItem>true</isSystemItem>
</metadata>
</info>
</separator>
</xbel>
EOF

View file

@ -0,0 +1,20 @@
#!/usr/bin/bash
#
# Synchronize local program directory and desktop starters
#
set -eu
if ! nslookup server; then
exit 0
fi
#[[ -d /usr/local/lmn ]] || mkdir -p /usr/local/lmn
#rsync -rlptD --chown=pgmadmin:root --chmod=F755,D755 rsync://server:/local-program/ /usr/local/lmn
RSYNC_COMMAND=$(rsync -ai --delete --exclude=mimeinfo.cache \
--chown=root:root --chmod=F644,D755 "rsync://server:/desktopstarter" \
/usr/local/share/applications/ | sed '/ \.\//d')
if [[ $? -eq 0 ]] && [[ -n "${RSYNC_COMMAND}" ]]; then
echo "${RSYNC_COMMAND}"
update-desktop-database /usr/local/share/applications
fi

View file

@ -0,0 +1,6 @@
[Unit]
Description=Synchronize program data and desktop starters
[Service]
Type=simple
ExecStart=/usr/local/sbin/lmn-sync

View file

@ -0,0 +1,9 @@
[Unit]
Description=Run lmn-sync after boot
After=network-online.target
[Timer]
OnBootSec=0min
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,98 @@
{
"policies": {
"Proxy": {
"Mode": "autoDetect"
},
"OverrideFirstRunPage": "https://www.steinbeisschule-reutlingen.de",
"Homepage": {
"URL": "https://www.steinbeisschule-reutlingen.de",
"Locked": false,
"StartPage": "previous-session"
},
"DisplayBookmarksToolbar": true,
"ManagedBookmarks": [
{
"toplevel_name": "FvS-Reutlingen"
},
{
"url": "https://www.steinbeisschule-reutlingen.de",
"name": "FvS-Homepage"
},
{
"url": "https://idam.steinbeis.schule/realms/fvs/account/#/security/signingin",
"name": "Authentifizierung/Passwort"
},
{
"url": "https://mail.steinbeis.schule",
"name": "FvS-eMail"
},
{
"url": "https://dw.steinbeis.schule",
"name": "FvS-Hilfesystem"
},
{
"url": "https://moodle.steinbeis.schule",
"name": "FvS-Moodle"
},
{
"url": "https://nc.steinbeis.schule",
"name": "FvS-Nextcloud"
},
{
"url": "https://server.pn.steinbeis.schule",
"name": "Schulkonsole"
},
{
"url": "https://peleus.webuntis.com/WebUntis/?school=Ferd.von+Steinbeis#/basic/login",
"name": "FvS-Stundenplan"
},
{
"url": "https://kreis-reutlingen.schulanmeldungen.com/anmeldeformulare/avdual",
"name": "Anmeldung AVdual"
},
{
"url": "https://steinbeisschule-reutlingen.schulanmeldungen.com/",
"name": "Anmeldung FVS"
},
{
"name": "Debian",
"children": [
{
"url": "https://www.debian.org",
"name": "Debian Homepage"
},
{
"url": "https://wiki.debian.org",
"name": "Debian Wiki"
},
{
"name": "Debian LAN/Live",
"children": [
{
"url": "https://salsa.debian.org/andi/debian-lan-ansible",
"name": "Debian LAN Ansible"
},
{
"url": "https://wiki.debian.org/DebianLive",
"name": "Debian Live"
}
]
}
]
}
],
"SearchEngines": {
"Add": [
{
"Name": "Startpage",
"URLTemplate": "https://www.startpage.com/sp/search?query={searchTerms}",
"Method": "GET",
"IconURL": "https://www.startpage.com/sp/cdn/favicons/favicon--default.ico",
"Alias": "sp",
"Description": "Startpage Search Engine"
}
],
"Default": "Startpage"
}
}
}

View file

@ -0,0 +1,7 @@
---
- name: Run update-desktop-database
ansible.builtin.command: update-desktop-database "{{ item }}"
loop:
- /usr/local/share/applications
- /usr/local/share/desktop-directories
- /etc/xdg/menus/applications-merged

View file

@ -0,0 +1,253 @@
---
- name: Preseed wireshark to allow users sniffing packets
ansible.builtin.debconf:
name: wireshark-common
question: wireshark-common/install-setuid
value: 'true'
vtype: boolean
- name: Preseed ttf-mscorefonts-installer
ansible.builtin.debconf:
name: ttf-mscorefonts-installer
question: msttcorefonts/dlurl
value: "{{ mirror_msfonts }}"
vtype: string
when: mirror_msfonts is defined and mirror_msfonts | length > 0
- name: Install desktop EDU packages and some more
ansible.builtin.apt:
name:
- atftp
- audacity
- biber
- calligraplan
- cmake ## for kdevelop
- codelite
- codelite-plugins
- curl
- elpa-color-theme-modern
- elpa-magit
- emacs
- filezilla
- freeplane
- git
- git-cola
- gitg
- gitk
- git-gui
- htop
- jq
- jupyter
- kchmviewer
- kdevelop
- kdevelop-php
- kdevelop-python
- krita
- libasound2-dev
- libdbus-glib-1-2 ## needed for zotero
- libnotify-bin ## needed for pwroff script
- libwayland-dev
- libxcursor-dev
- libxi-dev
- libxinerama-dev
- libxkbcommon-dev
- libxrandr-dev
- links2
- minder
- mosquitto-clients
- neovim
- net-tools
- netcat-openbsd
- nmap
- okular-extra-backends ## needed for CHM files
- pdf-presenter-console
- php-cli
- pipx
- planner
- pulseview
- python3-paho-mqtt
- python3-websockets
- qpdfview
- shellcheck
- sigrok
- sigrok-cli
- texlive-lang-german
- texlive-latex-recommended
- texlive-xetex
- texstudio
- tmux
- tree
- ttf-mscorefonts-installer
- twinkle
- unison-gtk
- w3m
- wireshark
- zulucrypt-gui
autoremove: true
state: latest
environment:
http_proxy: '' # this is needed to avoid ttf-mscorefonts-installer picking up aptcacher
- name: Remove update notifications from plasma-discover
ansible.builtin.apt:
name:
- plasma-discover
autoremove: true
state: absent
when: fvs_remove_discover
- name: Make sure wireshark works for all users after installation and upgrades
ansible.builtin.copy:
dest: /etc/apt/apt.conf.d/92wireshark4all
mode: '0644'
content: |
## Modify permissions after installation/upgrade to allow all
## users dumping packages on network interfaces for wireshark
DPkg::Post-Invoke {"/usr/bin/chmod o+x /usr/bin/dumpcap || true"; };
- name: Create firefox policies directory
ansible.builtin.file:
path: /etc/firefox-esr/policies
state: directory
mode: '0755'
- name: Create a symbolic link firefox to firefox-esr
ansible.builtin.file:
src: /etc/firefox-esr
dest: /etc/firefox
state: link
- name: Copy firefox policy
ansible.builtin.copy:
src: policies.json
dest: /etc/firefox-esr/policies/
mode: '0644'
- name: Create chromium policies directory
ansible.builtin.file:
path: /etc/chromium/policies/managed
state: directory
mode: '0755'
- name: Set chromium proxy-policy to auto_detect
ansible.builtin.copy:
dest: /etc/chromium/policies/managed/proxy.json
mode: '0644'
content: |
{
"ProxyMode": "auto_detect"
}
- name: Copy dolphin config scripts
ansible.builtin.copy:
src: "{{ item }}"
dest: /usr/local/bin/
mode: '0755'
loop:
- lmn-reset-dolphin.sh
- lmn-patch-dolphin.sh
- lmn-fixhome-dolphin.sh
- name: Configure KDE dolphin menu
ansible.builtin.copy:
src: lmn-dolphin.sh
dest: /etc/profile.d/
mode: '0644'
- name: Copy fvs-config.js to configure plasma
ansible.builtin.copy:
src: fvs-config.js
dest: /usr/share/plasma/shells/org.kde.plasma.desktop/contents/updates/fvs-config.js
mode: '0644'
- name: Configure some KDE aspects
ansible.builtin.blockinfile:
path: /etc/xdg/kdeglobals
create: true
mode: '0644'
block: |
[KDE]
SingleClick=false
[KDE Action Restrictions][$i]
action/start_new_session=false
#action/switch_user=false
#action/lock_screen=false
- name: Start with empty session by default
ansible.builtin.copy:
dest: /etc/xdg/ksmserverrc
mode: '0644'
content: |
[General]
loginMode=emptySession
# - name: Avoid starting kscreen (confusing autodetection)
# ansible.builtin.copy:
# dest: /etc/xdg/kded5rc
# content: |
# [Module-kscreen]
# autoload=false
#
# - name: Disable automatic lock screen and user specific modifications
# ansible.builtin.copy:
# path: /etc/xdg/kscreenlockerrc
# content: |
# [Daemon][$i]
# Autolock=false
# LockOnResume=false
#
- name: Download libdvdcss from mirror
ansible.builtin.get_url:
url: "{{ mirror_dvdcss }}/libdvdcss.so.2.2.0"
dest: /usr/lib/x86_64-linux-gnu/libdvdcss.so.2.2.0
mode: '0644'
use_proxy: false
when: mirror_dvdcss is defined and mirror_dvdcss | length > 0
- name: Link library so name
ansible.builtin.file:
src: libdvdcss.so.2.2.0
dest: /usr/lib/x86_64-linux-gnu/libdvdcss.so.2
state: link
when: mirror_dvdcss is defined and mirror_dvdcss | length > 0
- name: Patch sddm login screen to show hostname
ansible.builtin.blockinfile:
path: /usr/share/sddm/themes/debian-breeze/Main.qml
marker: // {mark} ANSIBLE MANAGED BLOCK
insertbefore: '^}$'
block: |
Text {
id: hostname
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 10
anchors.rightMargin: 15
color: "#ffffff"
text: sddm.hostName + " | <{{ ansible_date_time['date'] }}>"
font.pointSize: config.fontSize
}
- name: Set git default-branch to main
ansible.builtin.copy:
dest: /etc/gitconfig
mode: '0644'
content: |
[init]
defaultBranch = main
- name: Adjust mmcblk-device gid to allow users to access SD-cards
ansible.builtin.copy:
dest: /etc/udev/rules.d/80-mmcblk.rules
mode: '0644'
content: |
KERNEL=="mmcblk[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users"
KERNEL=="mmcblk[0-9]p[0-9]*", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users"
- name: Include sync
ansible.builtin.include_tasks: sync.yml

View file

@ -0,0 +1,58 @@
---
- name: Create directory for local .desktop-Files
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: '0755'
loop:
- /usr/local/share/applications
- /usr/local/share/desktop-directories
notify: Run update-desktop-database
- name: Copy fvs.directory
ansible.builtin.copy:
src: fvs.directory
dest: /usr/local/share/desktop-directories/
mode: '0644'
notify: Run update-desktop-database
- name: Copy fvs.menu
ansible.builtin.copy:
src: fvs.menu
dest: /etc/xdg/menus/applications-merged/
mode: '0644'
notify: Run update-desktop-database
- name: Copy lmn-sync script
ansible.builtin.copy:
src: lmn-sync
dest: /usr/local/sbin/
mode: '0755'
register: lmn_sync
- name: Run lmn-sync script
ansible.builtin.shell: /usr/local/sbin/lmn-sync
when: lmn_sync.changed # noqa: no-handler
- name: Deploy sudo configurations (lmn-sync for role-teacher)
ansible.builtin.copy:
dest: /etc/sudoers.d/90-lmn-sync
owner: root
group: root
mode: '0700'
content: |
%role-teacher ALL=(root) NOPASSWD: /usr/local/sbin/lmn-sync
- name: Provide lmn-sync service and timer
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- lmn-sync.service
- lmn-sync.timer
- name: Enable lmn-sync.timer
ansible.builtin.systemd:
name: lmn-sync.timer
enabled: true

View file

@ -0,0 +1,5 @@
- name: Reload sshd
ansible.builtin.systemd:
name: sshd
state: reloaded
when: not run_in_installer|default(false)|bool

View file

@ -0,0 +1,49 @@
- name: Install kerberos packages
ansible.builtin.apt:
name: krb5-user
- name: Kerberize sshd server
ansible.builtin.copy:
dest: /etc/ssh/sshd_config.d/kerberize.conf
mode: '0644'
content: |
GSSAPIAuthentication yes
notify: "Reload sshd"
- name: Kerberize ssh client, authenticate and delegate credentials
ansible.builtin.copy:
dest: /etc/ssh/ssh_config.d/kerberize.conf
mode: '0644'
content: |
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
- name: Check if firefox is available
ansible.builtin.stat:
path: /etc/firefox-esr/firefox-esr.js
register: firefox
- name: Kerberize firefox for sites in the local domain
ansible.builtin.lineinfile:
dest: /etc/firefox-esr/firefox-esr.js
line: "{{ item }}"
with_items:
- '// kerberize for sites in the local domain:'
- 'pref("network.negotiate-auth.delegation-uris", "{{ kerberize_uris | default(ansible_domain) }}");'
- 'pref("network.negotiate-auth.trusted-uris", "{{ kerberize_uris | default(ansible_domain) }}");'
when: firefox.stat.exists
- name: Ensures /etc/chromium/policies/managed dir exists
ansible.builtin.file:
path: "/etc/chromium/policies/managed"
state: directory
mode: '0755'
- name: Kerberize chromium for sites in the local domain
ansible.builtin.copy:
dest: /etc/chromium/policies/managed/idam.json
mode: '0644'
content: |
{
"AuthServerAllowlist": "{{ kerberize_uris | default(ansible_domain) }}"
}

View file

@ -0,0 +1,2 @@
---
exam_mode: true

View file

@ -0,0 +1,16 @@
#!/usr/bin/bash
# exit if not running as root. Because other user don't have privileges to start/stop firewalld.
[[ "${UID}" -eq "0" ]] || exit 0
if [[ "${PAM_USER}" =~ -exam$ ]]; then
systemctl start firewalld.service
if systemctl is-enabled --quiet libvirtd.service; then
systemctl restart libvirtd.service
fi
elif ! (users | grep -q -- "-exam"); then
systemctl stop firewalld.service
if systemctl is-enabled --quiet libvirtd.service; then
systemctl restart libvirtd.service
fi
fi

16
roles/lmn_exam/files/rmexam Executable file
View file

@ -0,0 +1,16 @@
#!/usr/bin/bash
#
# rename -exam directories in /home and /lmn/media older than 12h
# remove -exam.* directories in /home and /lmn/media older than 10d
#
set -eu
for dir in /home/ /lmn/media ; do
if [[ -d "${dir}" ]]; then
find "${dir}" -maxdepth 1 -mindepth 1 -name '*-exam' -type d -cmin +720 \
-exec bash -c 'mv "$0" "$0".$( date +%Y%m%d-%H%M --reference="$0" )' {} \;
find "${dir}" -maxdepth 1 -mindepth 1 -name '*-exam.*' -type d -cmin +14400 \
-exec rm -rf {} \;
fi
done

View file

@ -0,0 +1,6 @@
[Unit]
Description=Rename/Remove -exam directories older than 12h/10d
[Service]
Type=simple
ExecStart=/usr/local/sbin/rmexam

View file

@ -0,0 +1,8 @@
[Unit]
Description=Run rmexam after boot
[Timer]
OnBootSec=0min
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,70 @@
---
# Requirement: Install firewalld after installing libvirt
- name: Install firewalld packages
ansible.builtin.apt:
name:
- firewalld
register: result
- name: Stop firewalld-service
ansible.builtin.systemd:
name: firewalld
state: stopped
when: result.changed # noqa: no-handler
- name: Disable firewalld-service
ansible.builtin.systemd:
name: firewalld
enabled: false
- name: Add virbr0 to libvirt zone
ansible.posix.firewalld:
zone: libvirt
interface: virbr0
permanent: true
state: enabled
when: vm_support is defined and vm_support
- name: Permit access to cups from libvirt
ansible.posix.firewalld:
zone: libvirt
port: 631/tcp
permanent: true
state: enabled
when: vm_support is defined and vm_support # and printing is defined and printing
- name: Permit access to usersquid from libvirt
ansible.posix.firewalld:
zone: libvirt
port: 3128/tcp
permanent: true
state: enabled
when: vm_support is defined and vm_support # and localsquid is defined and localsquid
- name: Copy some scripts
ansible.builtin.copy:
src: "{{ item }}"
dest: /usr/local/sbin/
mode: '0755'
loop:
- pam-exec.sh
- rmexam
- name: Enable login script via pam_exec.so
ansible.builtin.lineinfile:
dest: /etc/pam.d/common-session
line: 'session optional pam_exec.so /usr/local/sbin/pam-exec.sh'
- name: Provide rmexam services and timers for some scripts
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- rmexam.service
- rmexam.timer
- name: Enable rmexam.timer
ansible.builtin.systemd:
name: rmexam.timer
enabled: true

View file

@ -0,0 +1,6 @@
extra_pkgs: []
extra_pkgs1: []
extra_pkgs2: []
extra_pkgs_bpo: []
extra_pkgs_bpo1: []
extra_pkgs_bpo2: []

View file

@ -0,0 +1,34 @@
---
- name: Install extra packages from stable
ansible.builtin.apt:
name: "{{ item }}"
loop:
- "{{ extra_pkgs }}"
- "{{ extra_pkgs1 }}"
- "{{ extra_pkgs2 }}"
- name: Add backports for {{ ansible_distribution_release }}
ansible.builtin.apt_repository:
repo: >
deb http://deb.debian.org/debian/ {{ ansible_distribution_release }}-backports
main non-free-firmware
state: present
update_cache: true
when: extra_pkgs_bpo | length > 0 or extra_pkgs_bpo1 | length > 0 or extra_pkgs_bpo2 | length > 0
- name: Install extra packages from backports
ansible.builtin.apt:
name: "{{ item }}"
state: latest # noqa package-latest
default_release: "{{ ansible_distribution_release }}-backports"
loop:
- "{{ extra_pkgs_bpo }}"
- "{{ extra_pkgs_bpo1 }}"
- "{{ extra_pkgs_bpo2 }}"
when: extra_pkgs_bpo | length > 0 or extra_pkgs_bpo1 | length > 0 or extra_pkgs_bpo2 | length > 0
- name: Timestamp successfull run and send up-to-date report
ansible.builtin.shell:
cmd: date --iso-8601=seconds >> /var/local/ansible-stamps && /usr/local/sbin/reporter
changed_when: false
tags: upgrade

View file

@ -0,0 +1,40 @@
---
kde_desktop_pkg:
- akonadi-backend-sqlite
- arduino
- bluefish
- calligra
- codeblocks
- dia
- filius
- flameshot
- freecad
- fritzing
- ghex
- gimp
- inkscape
- kde-full
- keepassxc
- kicad
- kicad-doc-de
- librecad
- openboard
- qtcreator
- spyder
- sqlite3
- sqlitebrowser
- task-german-desktop
- task-german-kde-desktop
- task-kde-desktop
- thonny
- thunderbird-l10n-de
- vlc
- vym
- webext-privacy-badger
- webext-ublock-origin-chromium
- webext-ublock-origin-firefox
- xdg-desktop-portal-kde
- xdg-desktop-portal-wlr # share screen in browser
- xournalpp
kde_desktop_pkg_bpo: [ ]

View file

@ -0,0 +1,32 @@
#!/usr/bin/bash
#
# Dolphin keeps old paths after modifications.
# Run with '--do-it' to really make the change.
#
set -eu
do="${1:-}"
bmk=".local/share/user-places.xbel"
rt="/srv/samba/schools/default-school/students"
extract() {
local grp="$1"
grp="${grp##*${rt}/}"
grp="${grp%%/*}"
echo $grp
}
for f in $(find $rt/*/*/$bmk) ; do
cor="$(extract $f)"
for l in "$(grep "$rt" "$f")" ; do
fnd="$(extract "$l")"
if [[ "$cor" != "$fnd" ]] ; then
echo "Check ${f##*${rt}/}: '$cor' != '$fnd'."
if [[ "$do" = "--do-it" ]] ; then
sed -i.lmn-fix-path "s|$rt/$fnd|$rt/$cor|g" "$f"
break
fi
fi
done
done

View file

@ -0,0 +1,68 @@
---
- name: Install desktop and educational packages
ansible.builtin.apt:
name: "{{ kde_desktop_pkg }}"
- name: Add backports {{ ansible_distribution_release }}
ansible.builtin.apt_repository:
repo: deb http://deb.debian.org/debian/ {{ ansible_distribution_release }}-backports main non-free-firmware
state: present
update_cache: true
when: kde_desktop_pkg_bpo | length > 0
- name: Install extra packages from backports
ansible.builtin.apt:
name: "{{ kde_desktop_pkg_bpo }}"
autoremove: true
default_release: "{{ ansible_distribution_release }}-backports"
when: kde_desktop_pkg_bpo | length > 0
- name: Create akonadi config dir
ansible.builtin.file:
path: /etc/xdg/akonadi/
state: directory
mode: '0755'
- name: Use sqlite in akonadi
ansible.builtin.blockinfile:
path: /etc/xdg/akonadi/akonadiserverrc
create: true
mode: '0644'
block: |
[%General]
Driver=QSQLITE3
## Akonadi complains if not set:
- name: Add home dirs to apparmor
ansible.builtin.lineinfile:
dest: /etc/apparmor.d/tunables/home.d/ubuntu
line: >-
@{HOMEDIRS}+=/srv/samba/schools/default-school/teachers/
/srv/samba/schools/default-school/students/*/
/srv/samba/schools/default-school/examusers/
- name: Tune SDDM login
ansible.builtin.blockinfile:
path: /etc/sddm.conf
create: true
mode: '0644'
block: |
[Users]
MaximumUid=999
RememberLastUser=false
RememberLastSession=false
- name: Deploy dolphin script
ansible.builtin.copy:
src: lmn-fix-dolphin.sh
dest: /usr/local/bin/
mode: '0755'
- name: Default KDE filepicker
ansible.builtin.lineinfile:
path: /etc/environment.d/90lmn-filepicker.conf
create: true
mode: '0644'
line: GTK_USE_PORTAL=1

View file

@ -0,0 +1,3 @@
---
localhome: false
localhome_logout_missing_serverhome: true

View file

@ -0,0 +1,29 @@
#!/usr/bin/bash
#
# create ~/.unison/SyncHome.prf if not exists
#
set -eu
[[ -f ~/.unison/SyncHome.prf ]] && exit 0
mkdir -p ~/.unison
if id | grep teachers; then
NETHOME="$(find /srv/samba/schools/default-school/teachers/ -maxdepth 1 -type d -name "${USER}")"
else
NETHOME="$(find /srv/samba/schools/default-school/students/ -maxdepth 2 -type d -name "${USER}")"
fi
if [[ ! -f ~/.unison/SyncHome.prf ]]; then
echo "# Unison preferences
label = Sync Home on Server
path = Bilder
path = Dokumente
path = Musik
path = Videos
root = $HOME
root = $NETHOME
dontchmod = true
perms = 0" > ~/.unison/SyncHome.prf
fi

View file

@ -0,0 +1,39 @@
---
- name: Enable pam_mkhomedir.so
ansible.builtin.lineinfile:
dest: /etc/pam.d/common-session
line: "session optional pam_mkhomedir.so umask=0077"
insertbefore: '^session\s*optional\s*pam_mount.so'
- name: Patch sddm login screen to inform about localhome
ansible.builtin.blockinfile:
path: /usr/share/sddm/themes/debian-breeze/Main.qml
marker: // {mark} ANSIBLE MANAGED BLOCK localhome
insertbefore: '^}$'
block: |
Text {
id: localhome
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: 10
anchors.leftMargin: 15
color: "#ffffff"
text: "Lokale Anmeldung!\nHome-Verzeichnis liegt nicht im Netz!"
font.pointSize: config.fontSize
}
- name: Copy unison-createconfig scripts
ansible.builtin.copy:
src: lmn-create-unisonconfig.sh
dest: /usr/local/bin/
mode: '0755'
- name: Install auto-logout-script for first login in /etc/profile.d/
ansible.builtin.copy:
dest: /etc/profile.d/lmn-logout.sh
mode: '0755'
content: |
[[ "${UID}" -gt 10000 ]] && ! findmnt "/lmn/media/${USER}/home" > /dev/null && exit 0
{% if localhome_logout_missing_serverhome %}
[[ "${UID}" -gt 10000 ]] && ! findmnt /srv/samba/schools/default-school > /dev/null && exit 0
{% endif %}

View file

@ -0,0 +1,3 @@
---
localproxy: false
localproxy_parent: "firewall.{{ domain }}"

View file

@ -0,0 +1,11 @@
[Unit]
Description=Run squid in usermode using user kerberos ticket
[Service]
Type=simple
ExecStart=/usr/local/bin/startusersquid.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=xdg-desktop-autostart.target

View file

@ -0,0 +1,48 @@
---
- name: Install squid
ansible.builtin.apt:
name:
- squid
- name: Disable squid
ansible.builtin.systemd:
name: squid
enabled: false
state: stopped
- name: Deploy squid user mode configuration
ansible.builtin.template:
src: "{{ item }}.j2"
dest: "/etc/squid/{{ item }}"
mode: '0644'
loop:
- squid-usermode.conf
- squid-usermode-external.conf
- name: Deploy startusersquid script
ansible.builtin.template:
src: startusersquid.sh.j2
dest: /usr/local/bin/startusersquid.sh
mode: '0755'
- name: Provide usersquid service
ansible.builtin.copy:
src: usersquid.service
dest: /etc/systemd/user/usersquid.service
mode: '0644'
- name: Enable usersquid service
ansible.builtin.systemd:
name: usersquid.service
scope: global
enabled: true
- name: Deploy http proxy config
ansible.builtin.copy:
dest: /etc/environment.d/10-lmn-proxy.conf
mode: '0644'
content: |
http_proxy="http://localhost:3128"
https_proxy="http://localhost:3128"
ftp_proxy="http://localhost:3128"
no_proxy="{{ no_proxy }}"

View file

@ -0,0 +1,14 @@
acl local-servers dstdomain .{{ domain }}
cache_peer {{ localproxy_parent }} parent 3128 0 no-query default login=NEGOTIATE auth-no-keytab
never_direct deny local-servers
always_direct allow all
#access_log stdio:/tmp/access.log squid
access_log none
cache_log /dev/null
logfile_rotate 0
pid_filename none
{% if vm_support %}
http_port 192.168.122.1:3128
{% endif %}
http_port 127.0.0.1:3128
http_access allow all

View file

@ -0,0 +1,14 @@
acl local-servers dstdomain .{{ domain }}
cache_peer {{ localproxy_parent }} parent 3128 0 no-query default login=NEGOTIATE auth-no-keytab
never_direct deny local-servers
never_direct allow all
#access_log stdio:/tmp/access.log squid
access_log none
cache_log /dev/null
logfile_rotate 0
pid_filename none
{% if vm_support %}
http_port 192.168.122.1:3128
{% endif %}
http_port 127.0.0.1:3128
http_access allow all

View file

@ -0,0 +1,8 @@
#!/usr/bin/bash
#
if nslookup firewall.{{ domain }}; then
/usr/sbin/squid --foreground -f /etc/squid/squid-usermode.conf
else
/usr/sbin/squid --foreground -f /etc/squid/squid-usermode-external.conf
fi

View file

@ -0,0 +1,4 @@
---
localuser: false
localuser_password: "Muster!"
localuser_secretsalt: "4ANAxPycC3q"

View file

@ -0,0 +1,28 @@
---
- name: Mount tmpfs on /home/{{ localuser }}
ansible.posix.mount:
name: /home/{{ localuser }}
src: tmpfs
fstype: tmpfs
opts: uid=1001,gid=1001,mode=755,size=4G
state: mounted
- name: Add local guest user
ansible.builtin.user:
name: "{{ localuser }}"
comment: "Local Guest User,,,"
shell: /bin/bash
uid: 1001
password_expire_min: 99999
createhome: false
password: "{{ localuser_password | password_hash('sha512',localuser_secretsalt) }}"
- name: Prepare generator for local guest user
ansible.builtin.copy:
dest: /etc/systemd/user-environment-generators/60-guest-user.sh
content: |
#!/usr/bin/bash
set -eu
[[ "$UID" -ne 1001 ]] && exit 0
cp -r -n /etc/skel/.* "$HOME"
mode: "0755"

View file

@ -0,0 +1,9 @@
---
misc_avoid_suspend: true
misc_pwroff: true
misc_pwroff_idle: true
misc_pxe_first: false
misc_reporter: false
misc_reporter_serv: "localhost 1234"
misc_clonescreen: false
misc_clonescreen_mode: "1920x1080@60"

View file

@ -0,0 +1,18 @@
#!/usr/bin/bash
#
# fix boot order: first PXE, then Debian
#
set -eu
cur="$(efibootmgr | grep -Ei 'BootOrder:' | \
sed -E 's/^BootOrder: ([[:xdigit:]]{4}),.+$/\1/')"
pxeip4="$(efibootmgr | grep -Ei "IP.*4" | \
sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/')"
debian="$(efibootmgr | grep -Ei "debian" | \
sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/')"
if [[ "$cur" != "$pxeip4" ]] && [[ -n "$pxeip4" ]] && [[ -n "$debian" ]] ; then
efibootmgr -o $pxeip4,$debian
else
echo "Nothing to do."
fi

48
roles/lmn_misc/files/pwroff Executable file
View file

@ -0,0 +1,48 @@
#!/bin/bash
#
# logout idle users and shutdown machine
#
set -eu
action="systemctl poweroff"
uptime=$(cat /proc/uptime | cut -f1 -d.)
maxidle=3600 ## seconds
u=($(loginctl list-users --no-legend | sort -hr | head -1))
una=${u[1]:-''}
uid=${u[0]:-''}
talk2dbus() {
local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
sudo -u $una DISPLAY=$display \
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus "$@"
}
########
## shutdown if nobody is loged in:
if [[ -z "$una" ]] || [[ $uid -lt 1000 ]] ; then
exec $action
fi
# FIXME: find idle time independent of running screensaver
if ! t=$(talk2dbus qdbus org.kde.screensaver /ScreenSaver GetActiveTime) ; then
echo "No graphical logins found."
else
idle=$(( t / 1000 ))
if [[ $idle -gt $maxidle ]] && [[ ! -d "/srv/samba/schools/default-school/teachers/" ]] ; then
talk2dbus notify-send -i system-shutdown -u critical -a 'Important System Information' \
'Please log out, the system will shut down soon!' \
'There has been no activity for too long.'
## shutdown:
#talk2dbus qdbus org.kde.ksmserver /KSMServer logout 1 2 0
## logout:
talk2dbus qdbus org.kde.ksmserver /KSMServer logout 1 0 0 || \
loginctl terminate-user $una
echo "Log-out user $una after being idle for $idle seconds."
else
echo "The user $una has been idle for $idle seconds."
fi
fi
#w -s | grep tty | sed "s/[[:space:]]\+/ /g" | cut -f4 -d ' '

View file

@ -0,0 +1,6 @@
[Unit]
Description=Run pwroff script
[Service]
Type=simple
ExecStart=/usr/local/sbin/pwroff

View file

@ -0,0 +1,9 @@
[Unit]
Description=Run pwroff script every 15 min after 90 min uptime
[Timer]
OnBootSec=90min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.target

33
roles/lmn_misc/files/reporter Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/bash
#
# Send stdout of some commands to monitoring server.
# Collect the reports with 'nc -u -k -l 1234' on 'sendto'.
# Use /bin/nc.openbsd, /bin/nc.traditional seems not to work.
#
set -eu
sendto="collector.steinbeis.schule 1234"
n=0
cmds=(
'uname -a'
'tail -1 /var/local/ansible-stamps'
'ip route list default'
'ip link show | \
sed -nE -e "s/^[2-9]: (\S+): .+/\1/p" -e "s/.+ether ([0-9a-f:]+) .+/\1/p" | \
paste - -'
)
# 'w'
# 'uptime'
# 'ls -d --full-time /home/ansible/.ansible/tmp/'
# 'ip addr show'
# 'apt list --upgradeable -o Apt::Cmd::Disable-Script-Warning=true'
r="$HOSTNAME ------- $(date --rfc-3339=seconds) -------
$(for c in "${cmds[@]}" ; do
n=$(( n + 1 ))
echo -n "$n"
eval "$c" | sed 's/^/\t/'
done | sed "s/^/$HOSTNAME /")
## -------------------------------------------------"
echo "$r" | nc -w 1 -u $sendto

View file

@ -0,0 +1,6 @@
[Unit]
Description=Run reporting script
[Service]
Type=simple
ExecStart=/usr/local/sbin/reporter

View file

@ -0,0 +1,9 @@
[Unit]
Description=Run reporter script every 15 min
[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,2 @@
- name: Run update-grub
ansible.builtin.command: update-grub

View file

@ -0,0 +1,217 @@
---
- name: Enable wake-on-lan for all ethernet connections
ansible.builtin.copy:
dest: /etc/NetworkManager/conf.d/wake-on-lan.conf
mode: '0644'
content: |
[connection]
ethernet.wake-on-lan=64
- name: Prepare directory for apt-daily override
ansible.builtin.file:
path: /etc/systemd/system/apt-daily.timer.d/
mode: '0755'
state: directory
- name: Run apt update early to avoid outdated package lists
ansible.builtin.copy:
dest: /etc/systemd/system/apt-daily.timer.d/override.conf
mode: '0644'
content: |
[Timer]
RandomizedDelaySec=30m
# Avoid suspend
- name: Create directory to avoid suspend
ansible.builtin.file:
path: /etc/systemd/sleep.conf.d/
state: directory
mode: '0755'
when: misc_avoid_suspend
- name: Avoid suspending
ansible.builtin.blockinfile:
path: /etc/systemd/sleep.conf.d/nosuspend.conf
create: true
mode: '0644'
block: |
[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowSuspendThenHibernate=no
AllowHybridSleep=no
when: misc_avoid_suspend
# Auto Poweroff
- name: Copy pwroff script
ansible.builtin.copy:
src: pwroff
dest: /usr/local/sbin/
mode: '0755'
- name: Provide services and timers for pwroff
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- pwroff.service
- pwroff.timer
when: misc_pwroff
- name: Enable pwroff.timer
ansible.builtin.systemd:
name: pwroff.timer
enabled: true
when: misc_pwroff
# Shut down when idle for too long
- name: Shut down when idle for too long
ansible.builtin.copy:
dest: /etc/xdg/powermanagementprofilesrc
mode: '0644'
content: |
[AC][SuspendSession]
idleTime=7200000
suspendType=8
when: misc_pwroff_idle
# Boot splash
- name: Enable boot splash screen
ansible.builtin.replace:
dest: "/etc/default/grub"
regexp: '"quiet"$'
replace: '"quiet splash"'
notify: Run update-grub
# Grub settings
- name: Protect editing grub menu entries
ansible.builtin.blockinfile:
path: /etc/grub.d/40_custom
block: |
set superusers='root'
export superusers
password_pbkdf2 root {{ grub_pwd }}
notify: Run update-grub
when: grub_pwd | bool | default(false)
- name: Allow booting grub menu entries
ansible.builtin.lineinfile:
dest: /etc/grub.d/10_linux
line: CLASS="${CLASS} --unrestricted"
insertafter: '^CLASS=.*'
firstmatch: true
notify: Run update-grub
- name: Disable Grub submenus
ansible.builtin.lineinfile:
dest: /etc/default/grub
line: 'GRUB_DISABLE_SUBMENU=true'
insertafter: '^GRUB_TIMEOUT=.*'
notify: Run update-grub
- name: Grub timeout
ansible.builtin.lineinfile:
dest: /etc/default/grub
regexp: '^(GRUB_TIMEOUT=).*'
line: '\g<1>1'
backrefs: true
notify: Run update-grub
# PXE first boot order
- name: Copy some scripts
ansible.builtin.copy:
src: bootorder.sh
dest: /usr/local/sbin/
mode: '0755'
when: misc_pxe_first
- name: PXE first boot order
ansible.builtin.command: /usr/local/sbin/bootorder.sh
register: cmd_result
changed_when: cmd_result.stdout is not search('Nothing to do.')
when: misc_pxe_first
# Disable Caps Lock
- name: Keyboard compose key
ansible.builtin.lineinfile:
dest: /etc/default/keyboard
regexp: '^(XKBOPTIONS=).*'
line: '\1"compose:caps"'
backrefs: true
# Activate unattended upgrades
- name: Install unattended-upgrades
ansible.builtin.apt:
name:
- unattended-upgrades
- name: Update all packages unattended
ansible.builtin.replace:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^//(\s+"origin=.+-updates";)$'
replace: ' \1'
# Install reporter
- name: Copy reporter
ansible.builtin.template:
src: reporter.j2
dest: /usr/local/sbin/reporter
mode: '0755'
- name: Provide services and timers for reporter
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- reporter.service
- reporter.timer
when: misc_reporter
- name: Enable reporter.timer
ansible.builtin.systemd:
name: reporter.timer
enabled: true
when: misc_reporter
# Prepare CloneScreen on Presenter PCs
- name: Fix primary screen for class room PCs with projector
when: misc_clonescreen
block:
- name: Set primary screen for login
ansible.builtin.blockinfile:
path: /usr/share/sddm/scripts/Xsetup
block: |
xrandr --output {{ dual_screen[0] }} --primary
when: dual_screen is defined
- name: Reset primary screen for login
ansible.builtin.blockinfile:
path: /usr/share/sddm/scripts/Xsetup
state: absent
when: dual_screen is not defined
- name: Deploy fix-screen script
ansible.builtin.template:
src: lmn-fix-screen.j2
dest: /usr/local/bin/lmn-fix-screen
mode: '0755'
- name: Deploy fix-screen autostarter
ansible.builtin.copy:
dest: /etc/xdg/autostart/lmn-fix-screen.desktop
mode: '0644'
content: |
[Desktop Entry]
Name=fix-screen
Exec=lmn-fix-screen
Type=Application
NoDisplay=true

View file

@ -0,0 +1,29 @@
#!/usr/bin/bash
#
# Set the primary screen after login
# Clone screen on all displays
# Set audio-default-sink
#
set -eu
if [[ "$XDG_SESSION_TYPE" = wayland ]] ; then
while ! kscreen-doctor -o; do
sleep 1
done
sleep 2
{% if dual_screen is defined %}
kscreen-doctor output.{{ dual_screen[1] }}.priority.1
{% endif %}
for N in $(kscreen-doctor -j | jq -r .outputs[].name) ; do
kscreen-doctor output.$N.mode.{{ misc_clonescreen_mode }} output.$N.position.0,0 output.$N.scale.$(kscreen-doctor -j | jq .outputs[].scale | sort | head -1);
done
fi
{% if audio_output is defined %}
pactl set-card-profile alsa_card.{{ audio_output[0] }} output:{{ audio_output[1] }}
pactl set-default-sink alsa_output.{{ audio_output[0] }}.{{ audio_output[1] }}
{% else %}
if pactl list cards | grep output:hdmi-stereo: | grep verfügbar:\ ja; then
pactl set-card-profile $(pactl list short cards | grep -m1 pci | head -1 | cut -f2) output:hdmi-stereo
pactl set-default-sink $(pactl list short cards | grep -m1 pci | head -1 | cut -f2 | sed s/card/output/g).output:hdmi-stereo
fi
{% endif %}

View file

@ -0,0 +1,33 @@
#!/usr/bin/bash
#
# Send stdout of some commands to monitoring server.
# Collect the reports with 'nc -u -k -l 1234' on 'sendto'.
# Use /bin/nc.openbsd, /bin/nc.traditional seems not to work.
#
set -eu
sendto="{{ misc_reporter_serv }} 1234"
n=0
cmds=(
'uname -a'
'tail -1 /var/local/ansible-stamps'
'ip route list default'
'ip link show | \
sed -nE -e "s/^[2-9]: (\S+): .+/\1/p" -e "s/.+ether ([0-9a-f:]+) .+/\1/p" | \
paste - -'
)
# 'w'
# 'uptime'
# 'ls -d --full-time /home/ansible/.ansible/tmp/'
# 'ip addr show'
# 'apt list --upgradeable -o Apt::Cmd::Disable-Script-Warning=true'
r="$HOSTNAME ------- $(date --rfc-3339=seconds) -------
$(for c in "${cmds[@]}" ; do
n=$(( n + 1 ))
echo -n "$n"
eval "$c" | sed 's/^/\t/'
done | sed "s/^/$HOSTNAME /")
## -------------------------------------------------"
echo "$r" | nc -w 1 -u $sendto

View file

@ -0,0 +1,3 @@
smb_server: "server"
smb_share: "default-school/"
nfs4: false

View file

@ -0,0 +1,4 @@
if [[ "${UID}" -gt 60000 ]]; then
[[ -L "/lmn/media/${USER}/share" ]] || ln -s .default-school/share "/lmn/media/${USER}/share"
[[ -L "/lmn/media/${USER}/home" ]] || ln -s ".default-school/${HOME##/srv/samba/schools/default-school/}" "/lmn/media/${USER}/home"
fi

View file

@ -0,0 +1,3 @@
if [[ "${UID}" -gt 60000 ]]; then
sudo /usr/local/bin/mounthome.sh &
fi

View file

@ -0,0 +1,112 @@
---
- name: Install needed packages
ansible.builtin.apt:
name:
- libpam-mount
- cifs-utils
- nfs-common
- hxtools
- davfs2
state: latest
- name: Configure pam_mount for Webdav Nextcloud
ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK (mount Nextcloud) -->"
block: |
<volume
fstype="davfs"
path="{{ web_dav }}"
mountpoint="/lmn/media/%(USER)/nextcloud"
options="username=%(USER),nosuid,nodev,uid=%(USER),gid=%(USERGID),grpid,file_mode=0700,dir_mode=0700,forceuid,forcegid"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
insertafter: "<!-- Volume definitions -->"
when: web_dav is defined and web_dav | length > 0
- name: Configure pam_mount for LMN homes
ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK (mount LMN home) -->"
block: |
<volume
fstype="cifs"
server="{{ smb_server }}"
path="{{ smb_share }}"
mountpoint="/srv/samba/schools/default-school"
options="sec=krb5i,cruid=%(USERUID),user=%(USER),gid=%(USERGID),file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600{{ cifsopt | default(",cache=loose") }}"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
insertafter: "<!-- Volume definitions -->"
- name: Prepare mount point for homes
ansible.builtin.file:
path: /srv/samba/schools/default-school/
state: directory
mode: '0755'
- name: Prepare persistent user cache base directory
ansible.builtin.file:
path: /var/cache/user/
state: directory
mode: '1777'
- name: Create user-environment-generator directory
ansible.builtin.file:
path: /etc/systemd/user-environment-generators/
state: directory
mode: '0755'
- name: Prepare generator for persistent user cache directory
ansible.builtin.copy:
dest: /etc/systemd/user-environment-generators/50-xdg-cache-home.sh
content: |
#!/usr/bin/bash
set -eu
## local users do not need the extra cache dir:
[[ "$UID" -le 60000 ]] && exit 0
cp -r -n /etc/skel/.* "$HOME"
DIR="/var/cache/user/${UID}/"
[[ -d "$DIR" ]] || mkdir -m 0700 "$DIR"
echo XDG_CACHE_HOME="$DIR"
echo JUPYTER_ALLOW_INSECURE_WRITES=1
mode: "0755"
- name: Clean up all user processes after logout
ansible.builtin.replace:
path: /etc/security/pam_mount.conf.xml
regexp: '^(<logout wait="0" hup="no" term="no" kill="no" />)$'
replace: '<!-- \1 -->\n<logout wait="1000" hup="yes" term="yes" kill="yes" />'
- name: Kill all user processes on logout
ansible.builtin.lineinfile:
path: /etc/systemd/logind.conf
line: KillUserProcesses=yes
insertafter: '#KillUserProcesses=no'
- name: Bind mount /lmn/media with nosuid directory
ansible.posix.mount:
src: /lmn/media
path: /lmn/media
opts: nosuid,bind
state: present
fstype: none
- name: Mount NFSv4 tools directory
ansible.posix.mount:
src: "{{ nfs_server }}:tools"
path: /lmn/tools
opts: rw,_netdev,x-systemd.automount,x-systemd.idle-timeout=10s,timeo=100,soft
state: present
fstype: nfs4
when: nfs_server is defined
- name: Mount NFSv4 home directory
ansible.posix.mount:
src: server:/default-school
path: /srv/samba/schools/default-school
opts: sec=krb5p,_netdev,x-systemd.automount,x-systemd.idle-timeout=60
state: present
fstype: nfs4
when: nfs4

View file

@ -0,0 +1,23 @@
---
- name: Set aptcache
ansible.builtin.copy:
dest: /etc/apt/apt.conf
mode: '0644'
content: >
{{ apt_conf }}
when: apt_conf | bool | default(false)
- name: Set NTP server
ansible.builtin.lineinfile:
path: /etc/systemd/timesyncd.conf
insertafter: '^#NTP='
line: NTP={{ ntp_serv }}
when: ntp_serv | bool | default(false)
- name: Add proposed-updates repository
ansible.builtin.apt_repository:
repo: >
deb http://deb.debian.org/debian/ {{ ansible_distribution_release }}-proposed-updates
main non-free-firmware
state: present
when: "'R202' in group_names"

View file

@ -0,0 +1,2 @@
---
printer_admin_group: ""

View file

@ -0,0 +1,3 @@
%examusers ALL=(root) NOPASSWD: /usr/local/bin/install-printers.sh
%role-student ALL=(root) NOPASSWD: /usr/local/bin/install-printers.sh
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/install-printers.sh

View file

@ -0,0 +1,67 @@
---
- name: Install cups
ansible.builtin.apt:
name:
- cups
- name: Disable cups printer browsing
ansible.builtin.lineinfile:
dest: /etc/cups/cupsd.conf
regexp: '^(Browsing ).*'
line: '\1No'
backrefs: true
- name: Listen on all Interfaces
ansible.builtin.lineinfile:
dest: /etc/cups/cupsd.conf
line: 'Listen *:631'
regexp: '^Listen localhost'
state: present
- name: Allow access from localhost and from VM
ansible.builtin.blockinfile:
dest: /etc/cups/cupsd.conf
block: |
Allow localhost
Allow 192.168.122.0/24
insertafter: "<Location {{ item }}>"
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item }}"
state: present
loop:
- "/"
- "/admin"
- name: Allow group role-teacher to manage printers
ansible.builtin.lineinfile:
dest: /etc/cups/cups-files.conf
line: "SystemGroup root lpadmin {{ printer_admin_group }}"
regexp: '^SystemGroup'
state: present
when: printer_admin_group | length > 0
- name: Disable cups-browsed
ansible.builtin.systemd:
name: cups-browsed.service
state: stopped
enabled: false
- name: Install install-printers.sh
ansible.builtin.template:
src: install-printers.sh.j2
dest: /usr/local/bin/install-printers.sh
mode: '0755'
- name: Install lmn-install-printers sudoers
ansible.builtin.copy:
src: 90-lmn-install-printers
dest: /etc/sudoers.d/
mode: '0660'
owner: root
group: root
- name: Run printer script from /etc/profile.d/
ansible.builtin.copy:
dest: /etc/profile.d/lmn-printer.sh
mode: '0644'
content: |
[[ "${UID}" -gt 10000 ]] && (sudo /usr/local/bin/install-printers.sh > /dev/null &)

View file

@ -0,0 +1,50 @@
#!/usr/bin/bash
set -eu
## Exit if first printserver is not reachable
ping -c1 -W1 {{ printservers | first }} || exit 0
printservers="{{ printservers | join(' ') }}"
hostgroup="$(id -Gn "${HOSTNAME^^}$")"
usergroup="$(id -Gn "${SUDO_USER}")"
installedprinters="$(lpstat -v | cut -f 3 -d" " | sed 's/:$//' )"
cat <<EOF
Hostgroups: ${hostgroup}
Usergroups: ${usergroup}
Local print queues:
${installedprinters}
EOF
## Remove all printers not wanted:
for p in $installedprinters ; do
printer_ip=$(lpstat -v "${p}" | sed -nE "s%.*ipp://(.+)/printers.*%\1%p")
if [[ -n $printer_ip ]] && (echo "${printservers}" | grep -w -q "${printer_ip}"); then
echo "Removing print queue '$p'."
lpadmin -x "$p"
fi
done
installedprinters="$(lpstat -v | cut -f 3 -d" " | sed 's/:$//' )"
## Add all printers needed:
for ps in $printservers ; do
echo "Checking print server '$ps' for available printers:"
printers="$(timeout 5 lpstat -h "$ps" -U "${SUDO_USER}" -v | sed -E 's/^.+ (\w+): .+$/\1/')"
echo -e "$printers\n"
for p in $printers; do
if [[ "${hostgroup}" =~ "$p" ]] || [[ "${usergroup}" =~ "$p" ]] ; then
if [[ "$installedprinters" =~ "$p" ]] ; then
echo "Print queue '$p' already available."
else
echo "Adding print queue '$p'."
timeout 10 lpadmin -p "$p" -E -v \
"ipp://$ps/printers/$p" \
-m "driverless:ipp://$ps/printers/$p" || echo "Adding queue '$p' failed."
installedprinters+=" $p"
fi
fi
done
done

View file

@ -0,0 +1,2 @@
---
security_defaultuser_login_disable: true

View file

@ -0,0 +1,11 @@
- name: Reload sshd
ansible.builtin.systemd:
name: sshd
state: reloaded
when: not run_in_installer|default(false)|bool
- name: Restart polkit
ansible.builtin.systemd:
name: polkit
state: restarted
when: not run_in_installer|default(false)|bool

View file

@ -0,0 +1,52 @@
---
- name: Deploy SSH keys
ansible.posix.authorized_key:
user: ansible
key: "{{ item }}"
loop: "{{ keys2deploy }}"
when: keys2deploy is defined
- name: Allow sudo without password for ansible
ansible.builtin.lineinfile:
path: /etc/sudoers.d/95-lmn-ansible
line: 'ansible ALL=(root) NOPASSWD: ALL'
create: true
owner: root
group: root
mode: '0700'
- name: Disable ansible user login
ansible.builtin.user:
name: ansible
password_lock: true
when: security_defaultuser_login_disable
- name: Limit SSH access to user ansible
ansible.builtin.blockinfile:
dest: /etc/ssh/sshd_config.d/local.conf
create: true
mode: '0644'
block: |
PasswordAuthentication no
AllowUsers ansible
notify: Reload sshd
- name: Deploy sudo configurations
ansible.builtin.copy:
dest: /etc/sudoers.d/90-lmn-security
owner: root
group: root
mode: '0700'
content: |
{% for user, programs in sudo_permissions.items() %}
{{ user }} ALL=(root) NOPASSWD: {% for program in programs %}{{ program }}{% if not loop.last %}, {% endif %}{% endfor %}
{% endfor %}
when: sudo_permissions is defined
- name: Deploy polkit configurations
ansible.builtin.template:
src: polkit_rules.j2
dest: /etc/polkit-1/rules.d/lmn-security.rules
mode: '0644'
notify: Restart polkit
when: polkit_rules is defined

View file

@ -0,0 +1,12 @@
// /etc/polkit-1/rules.d/lmn-security.rules
polkit.addRule(function(action, subject) {
{% for group, privlist in polkit_rules.items() %}
if (subject.isInGroup("{{ group }}")){
{% for priv in privlist %}
if (action.id == "{{ priv }}") { return polkit.Result.YES; }
{% endfor %}
}
{% endfor %}
});

View file

@ -0,0 +1,6 @@
- name: Restart sssd
ansible.builtin.service:
name: sssd
state: restarted
enabled: true
listen: "Restart sssd"

View file

@ -0,0 +1,24 @@
---
- name: Install needed packages
ansible.builtin.apt:
name:
- sssd-ad
- sssd-tools
- adcli
- name: Provide user identities from AD
ansible.builtin.template:
src: sssd.conf.j2
dest: /etc/sssd/sssd.conf
mode: '0600'
notify: Restart sssd
## Either one of the variables is defined:
- name: Join the domain
ansible.builtin.shell:
cmd: >
echo "{{ ansible_cmdline.adpw | default('') + adpw.user_input | default('') }}" |
adcli join --stdin-password -U global-admin {{ domain | upper }}
when: >
ansible_cmdline.adpw | default('') | length > 0 or
adpw.user_input | default('') | length > 0

View file

@ -0,0 +1,22 @@
[sssd]
domains = {{ domain }}
config_file_version = 2
implicit_pac_responder = False
[domain/{{ domain }}]
krb5_realm = {{ domain | upper }}
ad_domain = {{ domain }}
id_provider = ad
access_provider = ad
use_fully_qualified_names = False
cache_credentials = True
krb5_store_password_if_offline = True
default_shell = /usr/bin/bash
# default: # ldap_id_mapping = True
ad_gpo_access_control = disabled
ad_gpo_ignore_unreadable = True
ad_maximum_machine_account_password_age = 0
ignore_group_members = True
{% if localhome is defined and localhome %}
override_homedir = /home/%u
{% endif %}

View file

@ -0,0 +1,23 @@
--- /usr/lib/python3/dist-packages/spyder/plugins/editor/widgets/editor.py 2024-06-20 07:16:54.096395325 +0200
+++ /usr/lib/python3/dist-packages/spyder/plugins/editor/widgets/editor.py 2024-06-20 14:39:07.693577124 +0200
@@ -2370,15 +2370,16 @@
else:
# Else, testing if it has been modified elsewhere:
lastm = QFileInfo(finfo.filename).lastModified()
- if to_text_string(lastm.toString()) \
- != to_text_string(finfo.lastmodified.toString()):
+ dt = finfo.lastmodified.msecsTo(lastm)
+ if dt > 1000:
if finfo.editor.document().isModified():
self.msgbox = QMessageBox(
QMessageBox.Question,
self.title,
- _("<b>%s</b> has been modified outside Spyder."
+ _("It looks like <b>%s</b> has been modified "
+ "outside Spyder. The working copy is from %i milliseconds ago."
"<br>Do you want to reload it and lose all "
- "your changes?") % name,
+ "your changes?") % (name, dt),
QMessageBox.Yes | QMessageBox.No,
self)
answer = self.msgbox.exec_()

View file

@ -0,0 +1,72 @@
---
## Temporary fixes and quirks:
- name: Remove disturbing NetworkManager connection
ansible.builtin.file:
path: "/etc/NetworkManager/system-connections/Wired connection 1"
state: absent
when: ansible_interfaces | select('search', '^en[pso].+') | length > 1
- name: Fix 8086:4909 external graphics card
ansible.builtin.replace:
dest: "/etc/default/grub"
regexp: 'GRUB_CMDLINE_LINUX=""$'
replace: 'GRUB_CMDLINE_LINUX="i915.force_probe=4909"'
notify: Run update-grub
when: ansible_board_vendor == "LENOVO" and ansible_board_name == "32CB"
- name: Fix sound on 312A
ansible.builtin.replace:
dest: "/etc/default/grub"
regexp: 'GRUB_CMDLINE_LINUX="snd-intel-dspcfg.dsp_driver=1"$'
replace: 'GRUB_CMDLINE_LINUX=""'
notify: Run update-grub
when: ansible_board_vendor == "LENOVO" and ansible_board_name == "312A"
- name: Fix sound on 312A and 312D
ansible.builtin.apt:
name: firmware-sof-signed
state: latest
when: >
ansible_board_vendor == "LENOVO" and
(ansible_board_name == "312D" or ansible_board_name == "312A")
- name: Install customized CodeBlocks packages
when: "'PCroom' in group_names"
block:
- name: Check for old CodeBlocks
ansible.builtin.command:
cmd: dpkg -l codeblocks
register: codeblocks_version
changed_when: false
- name: Download codeblocks zip archive
ansible.builtin.get_url:
url: "http://livebox.pn.steinbeis.schule/codeblocks/CodeBlocks.zip"
dest: /tmp/CodeBlocks.zip
mode: '0644'
use_proxy: false
register: new_codeblocks
when: codeblocks_version.stdout is not search('svn13544')
- name: Unpack zip archive and install packages manually
ansible.builtin.shell:
cmd: unzip -d /tmp/cb/ CodeBlocks.zip && dpkg -i cb/*.deb
chdir: /tmp/
when: new_codeblocks.changed | default(false)
- name: Work around sddm hang on shutdown
ansible.builtin.lineinfile:
path: /etc/systemd/system.conf
line: DefaultTimeoutStopSec=5s
insertafter: '^#DefaultTimeoutStopSec=.*'
- name: Check if spyder is installed
ansible.builtin.stat:
path: /usr/lib/python3/dist-packages/spyder/plugins/editor/widgets/editor.py
register: spyder
- name: Patch spyder to fix 'file-has-changed' issues on CIFS
ansible.posix.patch:
src: spyder.patch
dest: /usr/lib/python3/dist-packages/spyder/plugins/editor/widgets/editor.py
when: spyder.stat.exists

View file

@ -0,0 +1,170 @@
---
# clean up stuff from obsolete/faulty tasks:
- name: Remove sddm login screen patch with deprecated marker (homeondisk)
ansible.builtin.blockinfile:
path: /usr/share/sddm/themes/debian-breeze/Main.qml
marker: // {mark} ANSIBLE MANAGED BLOCK homeondisk
state: absent
- name: Remove packages we do not need anymore
ansible.builtin.apt:
name:
- cachefilesd
- mosquitto
state: absent
purge: true
- name: Remove virtiofs service
ansible.builtin.file:
path: /etc/systemd/system/virtiofs@.service
state: absent
- name: Fix mount point permissions and owner
ansible.builtin.file:
path: "{{ item }}"
mode: '0755'
owner: root
group: root
loop:
- /srv/samba
- /srv/samba/schools
- name: Remove pam_mount sysvol mount
ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK (SysVol) -->"
block: |
<volume
fstype="cifs"
server="{{ smb_server }}"
path="sysvol/"
mountpoint="/srv/samba/%(USER)/sysvol"
options="sec=krb5i,cruid=%(USERUID),user=%(USER),gid=1010,file_mode=0770,dir_mode=0770,mfsymlinks"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
state: absent
- name: Remove pam_mount for VM bind mounts
ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK (bind mount school for VMs) -->"
state: absent
- name: Check if rmlpr.timer is installed
ansible.builtin.stat:
path: /etc/systemd/system/rmlpr.timer
register: rmlpr
- name: Disable rmlpr.timer
ansible.builtin.systemd:
name: rmlpr.timer
enabled: false
when: rmlpr.stat.exists
- name: Check if vmimage-torrent.service is installed
ansible.builtin.stat:
path: /etc/systemd/system/vmimage-torrent.service
register: vmimagetorrent
- name: Disable vmimage-torrent.service
ansible.builtin.systemd:
name: vmimage-torrent.service
enabled: false
when: vmimagetorrent.stat.exists
- name: Remove deprecated files and directories
ansible.builtin.file:
path: "{{ item }}"
state: absent
with_items:
- /etc/linuxmuster-linuxclient7
- /usr/lib/python3/dist-packages/linuxmusterLinuxclient7
- /usr/share/linuxmuster-linuxclient7
- /usr/local/bin/onLogin
- /etc/sudoers.d/90-lmn-sudotools
- /etc/systemd/system/rmlpr.service
- /etc/systemd/system/rmlpr.timer
- /usr/local/bin/sync-vm.sh
- /usr/local/bin/run-vm.sh
- /usr/local/bin/rebase-vm.sh
- /usr/local/bin/create-vm.sh
- /usr/local/bin/upload-vm.sh
- /usr/local/bin/vmimage-torrent
- /etc/systemd/system/vmimage-torrent.service
- /usr/local/bin/linbo-torrenthelper.sh
- /usr/local/bin/link-images.sh
- /usr/local/bin/start-virtiofsd.sh
- /etc/sudoers.d/90-lmn-upload-vm
- /etc/sudoers.d/90-lmn-sync-vm
- /etc/sudoers.d/90-lmn-startvirtiofsd
- /etc/sudoers.d/90-lmn-link-images
- /etc/rsync.secret
- /etc/systemd/network/30-virbr1.netdev
- /etc/systemd/network/30-virbr2.netdev
- /etc/systemd/network/40-ethernet.network
- /etc/systemd/network/40-ethernet-usb.network
- /etc/systemd/network/50-virbr1.network
- /etc/systemd/network/50-virbr2.network
- /etc/systemd/network/60-wlan0-dhcp.network
- /etc/NetworkManager/system-connections/macvlan-vm-macvtap.nmconnection
- /etc/tmpfiles.d/clean-exam.conf
- /etc/polkit-1/rules.d/lmn-networkmanager.rules
- /etc/polkit-1/rules.d/lmn-packagekit.rules
- name: Check if vm_usage_information.txt exists
ansible.builtin.stat:
path: /lmn/vm/vm_usage_information.txt
register: vm_usage_information
- name: Pre-fill vm_usage_information.txt
ansible.builtin.shell:
cmd: |
ls -tr *.qcow2 > vm_usage_information.txt || touchvm_usage_information.txt
chown lmnsynci:lmnsynci vm_usage_information.txt
chdir: /lmn/vm/
when: vm_support and not vm_usage_information.stat.exists
- name: Detect if IPP-Everywhere printers exist
ansible.builtin.shell:
cmd: grep "IPP Everywhere" /etc/cups/printers.conf
register: ipp_everywhere
failed_when: false
changed_when: false
- name: Delete old IPP-Everywhere printers
ansible.builtin.shell:
cmd: |
for p in $(lpstat -p | cut -d" " -f2); do
lpadmin -x "$p"
done
when: not ipp_everywhere.rc
- name: Remove old VM-printerlists
ansible.builtin.shell:
cmd: rm -f /lmn/media/*/.printerlist.csv
- name: Remove Listen on VMBridge
ansible.builtin.lineinfile:
dest: /etc/cups/cupsd.conf
line: 'Listen 192.168.122.1:631'
state: absent
- name: Remove NetworkManager Ansible-Block for non-laptops
ansible.builtin.blockinfile:
path: /etc/NetworkManager/NetworkManager.conf
state: absent
when: "'laptop' not in group_names"
- name: Remove pam-exec from common-auth
ansible.builtin.lineinfile:
dest: /etc/pam.d/common-auth
line: "auth optional pam_exec.so /usr/local/sbin/pam-exec.sh"
state: absent
when: exam_mode
- name: Remove pam-mkhomedir from common-session
ansible.builtin.lineinfile:
dest: /etc/pam.d/common-session
line: "session optional pam_mkhomedir.so umask=0077"
state: absent
when: localhome

View file

@ -0,0 +1,10 @@
---
- name: Remove disturbing NetworkManager connection
ansible.builtin.include_tasks:
file: "{{ taskfile }}"
loop_control:
loop_var: taskfile
loop:
- bookworm.yml
- cleanup.yml
when: ansible_distribution_release == "bookworm"

View file

@ -0,0 +1,4 @@
---
vm_support: false
vm_torrent_serv: "seedbox.{{ domain }}"
vm_uploadseed_pwd: secret = "token:topsecret"

View file

@ -0,0 +1,14 @@
#!/usr/bin/bash
#
# Synchronize desktop starters
#
set -eu
source /etc/lmn/vm.conf
RSYNC_COMMAND=$(rsync -ai --delete --exclude=mimeinfo.cache \
--chown=root:root --chmod=F644,D755 "${DESKTOPSTARTERDIR}" \
/usr/local/share/applications/ | sed '/ \.\//d')
if [[ $? -eq 0 ]] && [[ -n "${RSYNC_COMMAND}" ]]; then
echo "${RSYNC_COMMAND}"
update-desktop-database /usr/local/share/applications
fi

25
roles/lmn_vm/files/lmn-vm Normal file
View file

@ -0,0 +1,25 @@
# vm-sync: Download and synchronize VM-Images and xml-Files
%role-teacher ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync
%role-student ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync
%examusers ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync
# vm-aria2: Start/Stop aria2 as systemd-service for VM-Images
lmnsynci ALL=(root) NOPASSWD: /usr/local/bin/vm-aria2
# vm-link-images: Link VM-Images to User-tmp-directory
%examusers ALL=(root) NOPASSWD: /usr/local/bin/vm-link-images
%role-student ALL=(root) NOPASSWD: /usr/local/bin/vm-link-images
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/vm-link-images
# vm-virtiofsd: Start Virtiofsd as systemd-service
%examusers ALL=(root) NOPASSWD: /usr/local/bin/vm-virtiofsd
%role-student ALL=(root) NOPASSWD: /usr/local/bin/vm-virtiofsd
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/vm-virtiofsd
# desktop-sync:
%examusers ALL=(root) NOPASSWD: /usr/local/bin/desktop-sync
%role-student ALL=(root) NOPASSWD: /usr/local/bin/desktop-sync
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/desktop-sync
# vm-upload:
%role-teacher ALL=(root) NOPASSWD: /usr/local/bin/vm-upload

View file

@ -0,0 +1,42 @@
#!/usr/bin/bash
#
# <umount>/usr/local/sbin/pam-umount.sh %(USER) %(USERUID) %(MNTPT)</umount>'
set -eu
usr="$1"
uid="$2"
mtp="$3"
slce="system-virtiofs.slice"
slp=false
shutdownVMs(){
local VM
for VM in $(sudo -u $usr XDG_RUNTIME_DIR="/run/user/$uid" \
XDG_CONFIG_HOME="/var/tmp/vm/$uid" \
XDG_CACHE_HOME="/var/cache/user/$uid/" \
virsh list --state-running | \
sed -nE "s/.*\s+(\S+)\s+running/\1/p") ; do
sudo -u $usr XDG_RUNTIME_DIR="/run/user/$uid" \
XDG_CONFIG_HOME="/var/tmp/vm/$uid" \
XDG_CACHE_HOME="/var/cache/user/$uid/" \
virsh destroy "$VM" 2>&1 | systemd-cat || true
slp=true
done
}
######################
## This is the first mount we need to get rid of:
if [[ "$mtp" =~ "/lmn/media/$usr/share" ]] && [[ -d "/run/user/$uid" ]] ; then
shutdownVMs
[[ "$slp" = true ]] && sleep 5 # leave some time to write caches …
sudo -u ${usr} killall gvfsd | systemd-cat
sudo -u ${usr} killall dbus-daemon | systemd-cat
systemctl -q is-active "$slce" && systemctl kill "$slce"
# debug to find processes blocking umount:
# lsof >> /var/log/lsof.log
fi
## Just umount:
exec umount "$mtp"

View file

@ -0,0 +1,2 @@
[Service]
Environment=HOME=/tmp/pulse.%u

158
roles/lmn_vm/files/sync-vm.sh Executable file
View file

@ -0,0 +1,158 @@
#!/usr/bin/bash
# Push VM-Disk-Image on server
set -eu
show_help() {
cat << EOF >&2
Usage: $(basename "$0") [-d] [-a] [-t] [vmnames]"
Images from vmnames-List will be synced from server. Default by torrent.
Using flag -d VMs will be synced by rsync
Using flag -a images from images.list and xml-directory will be synced from server.
Using flag -t all torrents and xml-VM-Definitions will be synced
EOF
}
download_image() {
rsync -av "rsync://server:/vmimages-download/${VM_NAME}.qcow2" \
/lmn/vm/
rsync -av "rsync://server:/vmimages-download/${VM_NAME}.xml" \
/lmn/vm/
rsync -av "rsync://server:/vmimages-download/${VM_NAME}.qcow2.torrent" \
/lmn/vm/
/usr/local/bin/vmimage-torrent restart "${VM_NAME}.qcow2"
}
torrent_image() {
if [[ ! -f "/lmn/vm/${VM_NAME}.qcow2.torrent" ]]; then
echo "No torrent-File found"
exit 1
fi
lockfile="/tmp/sync-vm-${VM_NAME}.lock"
if ! flock -n "$lockfile" echo "try to acquire lock"; then
echo torrent seems to be in process.
echo waiting for completion ...
flock -w 3600 "$lockfile" echo "...completed"
sleep 5
else
(
if ! flock -n 200; then
echo "failed to acquire lock"
echo "Bitte noch einmal starten."
echo "Beliebige Taste zum Beenden."
read -n 1
exit 1
fi
torrent="${VM_NAME}.qcow2.torrent"
session="${torrent//./_}"
if vmimage-torrent status | grep -qw ^"$session"; then
vmimage-torrent stop "${VM_NAME}.qcow2"
fi
cd /lmn/vm
ctorrent -e 0 "${VM_NAME}.qcow2.torrent"
/usr/local/bin/vmimage-torrent restart "${VM_NAME}.qcow2"
if ! flock -u 200; then
echo failed to drop lock
exit 1
fi
) 200>"$lockfile"
fi
}
sync_all_images() {
rsync -av --files-from=/lmn/vm/images.list \
rsync://server:/vmimages-download/ /lmn/vm/
rsync -av rsync://server:/vmimages-download/*.xml \
/lmn/vm/
}
delete_old_qcows() {
cd /lmn/vm
for qcow2 in $(find . -maxdepth 1 -name "*.qcow2" -exec basename {} ';'); do
qcowsize=$(stat -c%s "${qcow2}")
if [[ -f "${qcow2}.size" ]] && [[ "${qcowsize}" != $(<"${qcow2}.size") ]]; then
torrent="${qcow2}.torrent"
session="${torrent//./_}"
if vmimage-torrent status | grep -qw ^"$session"; then
vmimage-torrent stop "${qcow2}"
fi
mv "${qcow2}" /tmp/
fi
done
}
sync_all_torrents() {
rsync -ai rsync://server:/vmimages-download/*.torrent /lmn/vm/
rsync -ai rsync://server:/vmimages-download/*.size /lmn/vm/
delete_old_qcows
rsync -ai rsync://server:/vmimages-download/*.xml /lmn/vm/
RSYNC_COMMAND=$(rsync -ai --delete --exclude=mimeinfo.cache rsync://server:/vmimages-download/desktop/ /usr/local/share/applications/ | sed '/ \.\//d')
if [[ $? -eq 0 ]] && [[ -n "${RSYNC_COMMAND}" ]]; then
echo "${RSYNC_COMMAND}"
update-desktop-database /usr/local/share/applications
fi
}
create_starter() {
if [[ ! -f "/usr/share/applications/VM_${VM_NAME}_starter.desktop" ]]; then
cat << EOF >"/usr/share/applications/VM_${VM_NAME}_starter.desktop"
[Desktop Entry]
Version=1.0
Type=Application
Name=VMstart: ${VM_NAME}
GenericName=VM starter ${VM_NAME}
Comment=Start VM ${VM_NAME}
#TryExec=konsole
Exec=/usr/local/bin/run-vm.sh ${VM_NAME}
Icon=clementine
Categories=VM;Engineering;
MimeType=image/vnd.dxf;
Keywords=design;VM;diagrams;graphics
Terminal=true
EOF
update-desktop-database /usr/share/applications
fi
}
if [[ "$(id -nu)" != "lmnsynci" ]]; then
echo "$(basename "$0") must be run as lmnsynci user"
show_help
exit 1
fi
while getopts ':dat' OPTION; do
case "$OPTION" in
d)
DOWNLOAD=1
;;
a)
sync_all_images
exit 0
;;
t)
sync_all_torrents
exit 0
;;
?)
show_help
exit 1
;;
esac
done
shift "$((OPTIND -1))"
# if less than one arguments supplied, display usage
if [[ $# -lt 1 ]]; then
show_help
exit 1
fi
for VM_NAME in "$@"; do
if [[ -v "DOWNLOAD" ]]; then
echo "Downloading $VM_NAME"
download_image
else
echo "Torrenting $VM_NAME"
torrent_image
fi
done

View file

@ -0,0 +1,13 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Sync Starters
GenericName=Aktualisiert Info über vorhandene VMs
Comment=Sync VM Image information
#TryExec=konsole
Exec=if sudo /usr/local/bin/desktop-sync; then echo 'sync erfolgreich.\nFenster schließt sich in 3 Sekunden.'; sleep 3; else echo "Fehler - sollte nicht vorkommen."; read; fi
Icon=bittorrent-sync
Categories=fvs;
MimeType=image/vnd.dxf;
Keywords=design;VM;diagrams;graphics
Terminal=true

93
roles/lmn_vm/files/uploadseed Executable file
View file

@ -0,0 +1,93 @@
#!/usr/bin/python3
import os, sys
import subprocess
import xmlrpc.client as xc
import ssl
import argparse
parser = argparse.ArgumentParser(description='Upload a file to the bittorrent seeder.')
parser.add_argument('--server', required=True,
help="the server address and RPC port like 'IPaddress:port'")
parser.add_argument('--dht-port', required=True,
help='the DHT port the RPC server is listening on')
pwgrp = parser.add_mutually_exclusive_group(required=True)
pwgrp.add_argument('--passwd',
help='the RPC secret. Either this or --pwdfile needs to be ' \
'provided')
pwgrp.add_argument('--pwdfile',
help="file containing the RPC secret in the form " \
"'secret = \"token:SECRET\"'. " \
'Either this or --secret needs to be provided')
certgrp = parser.add_mutually_exclusive_group(required=True)
certgrp.add_argument('--no-cert', action='store_true',
help='do not use SSL certificate')
certgrp.add_argument('--cert', help='the certificate to use for verification')
parser.add_argument('FILE', help='the file to upload')
args = parser.parse_args()
rpcseeder = 'https://' + args.server + '/rpc'
dhtentry = args.server.split(':')[0] + ':' + args.dht_port
file2send = args.FILE
torrent = '/tmp/' + os.path.basename(file2send) + '.torrent'
if args.passwd:
secret = 'token:' + args.passwd
else:
exec(open(args.pwdfile).read())
ssl_ctx = ssl.create_default_context()
if args.no_cert:
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE
print("Certificate verification disabled.")
elif args.cert is not None:
ssl_ctx.load_verify_locations(args.cert)
s = xc.ServerProxy(rpcseeder, context = ssl_ctx)
def make_torrent():
if os.path.isfile(torrent):
print("Torrent file", torrent, "exists already, please (re)move it.")
sys.exit(1)
subprocess.run(["/usr/bin/mktorrent", "-l 24", "-v", "-o", torrent, file2send], check=True)
h = subprocess.check_output(["/usr/bin/aria2c", "-S ", torrent])
for line in h.decode().splitlines():
if "Info Hash" in line:
return line.split(': ')[1]
def check_seeds(bthash):
active_seeds = s.aria2.tellActive(secret)
for seed in active_seeds:
f = seed['bittorrent']['info']['name']
gid = seed['gid']
ihash = seed['infoHash']
if f == os.path.basename(file2send):
print(file2send, "is already seeded with GID:", gid)
print("Info Hash is:", ihash)
if bthash == ihash:
print("The torrent file has not changed, exiting.")
return False
else:
print("The torrent file has changed, replacing torrent.")
s.aria2.remove(secret, gid)
return True
print("="*19, " Uploading new torrent with aria2 now. ", "="*19)
return True
def upload_torrent():
s.aria2.addTorrent(secret, xc.Binary(open(torrent, mode='rb').read()))
subprocess.run(["/usr/bin/aria2c",
"--dht-entry-point=" + dhtentry,
"--check-integrity",
"--dir=" + os.path.dirname(file2send),
torrent])
############################
if __name__ == '__main__':
infoHash = make_torrent()
if check_seeds(infoHash):
upload_torrent()
print("Upload finished.")

BIN
roles/lmn_vm/files/virtiofsd Executable file

Binary file not shown.

33
roles/lmn_vm/files/vm-aria2 Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/bash
set -eu
# if less than one arguments supplied, display usage
if [[ $# -ne 2 ]]; then
echo "This script takes as input the name of the VM " >&2
echo "Usage: $0 [start|stop] vm_name" >&2
exit 1
fi
COMMAND="$1"
VM_NAME="$2"
source /etc/lmn/vm.conf
if [[ "${COMMAND}" = "start" ]]; then
systemd-run --unit=aria2-"${VM_NAME}" \
--slice=system-aria2 \
--uid="$(id -u lmnsynci)" \
--gid="$(id -g lmnsynci)" \
--nice=19 \
--working-directory="${VM_SYSDIR}" \
--collect \
--property=Type=exec \
--property=SuccessExitStatus=1 \
aria2c --bt-hash-check-seed=true --check-integrity=true --seed-ratio=0.0 \
--dht-entry-point="${SEEDBOX_HOST}:${SEEDBOX_PORT}" \
--dht-file-path=$DHTDAT \
"${VM_SYSDIR}/${VM_NAME}.qcow2.torrent"
elif [[ "${COMMAND}" = "stop" ]] && systemctl is-active "aria2-${VM_NAME}.service"; then
systemctl stop "aria2-${VM_NAME}.service"
fi

Some files were not shown because too many files have changed in this diff Show more