OSDN Git Service

2020.05.10 update
[rebornos/cnchi-gnome-osdn.git] / Cnchi / encfs.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 #  encfs.py
5 #
6 #  Copyright © 2013-2019 RebornOS
7 #
8 #  This file is part of Cnchi.
9 #
10 #  Cnchi is free software; you can redistribute it and/or modify
11 #  it under the terms of the GNU General Public License as published by
12 #  the Free Software Foundation; either version 3 of the License, or
13 #  (at your option) any later version.
14 #
15 #  Cnchi is distributed in the hope that it will be useful,
16 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 #  GNU General Public License for more details.
19 #
20 #  The following additional terms are in effect as per Section 7 of the license:
21 #
22 #  The preservation of all legal notices and author attributions in
23 #  the material or in the Appropriate Legal Notices displayed
24 #  by works containing it is required.
25 #
26 #  You should have received a copy of the GNU General Public License
27 #  along with Cnchi; If not, see <http://www.gnu.org/licenses/>.
28
29
30 """ Configures Antergos to encrypt user's home with encFS """
31
32 import os
33 import shutil
34 import subprocess
35 import logging
36
37 import misc.extra as misc
38
39 # TODO: This is unfinished and untested
40
41
42 @misc.raise_privileges
43 def backup_conf_files(dest_dir):
44     """ Copy encfs setup files """
45     conf_files = [
46         "etc/security/pam_encfs.conf",
47         "etc/security/pam_env.conf",
48         "etc/fuse.conf",
49         "etc/pam.d/system-login",
50         "etc/pam.d/system-auth"]
51     for conf_file in conf_files:
52         path = os.path.join(dest_dir, conf_file)
53         if os.path.exists(path):
54             shutil.copy(path, path + ".cnchi")
55     os.system("sync")
56
57
58 @misc.raise_privileges
59 def setup_conf_files(dest_dir):
60     """ Setup encfs """
61     path = os.path.join(dest_dir, "etc/security/pam_encfs.conf")
62     with open(path, 'w') as pam_encfs:
63         pam_encfs.write("# File created by Cnchi (RebornOS Installer)\n\n")
64         pam_encfs.write(
65             "# If this is specified program will attempt to drop permissions "
66             "before running encfs.\n")
67         pam_encfs.write("drop_permissions\n\n")
68         pam_encfs.write(
69             "# This specifies which options to pass to encfs for every user.\n")
70         pam_encfs.write(
71             "# You can find encfs options by running encfs without any arguments\n")
72         pam_encfs.write("encfs_default --idle=1\n\n")
73         pam_encfs.write("# Same for fuse\n")
74         pam_encfs.write("# you can find fuse options with encfs -H\n")
75         pam_encfs.write("fuse_default allow_root,nonempty\n\n")
76         pam_encfs.write("# Added by Cnchi - RebornOS Installer\n")
77         # USERNAME SOURCE TARGET_PATH ENCFS_Options FUSE_Options
78         pam_encfs.write("-\t/home/.encfs\t-\t-v\t-\n")
79
80     path = os.path.join(dest_dir, "etc/security/pam_env.conf")
81     with open(path, 'a') as pam_env:
82         pam_env.write("\n# Added by Cnchi - RebornOS Installer\n")
83         pam_env.write(
84             "# Set the ICEAUTHORITY file location to allow GNOME to start on encfs $HOME\n")
85         pam_env.write("ICEAUTHORITY DEFAULT=/tmp/.ICEauthority_@{PAM_USER}\n")
86
87     path = os.path.join(dest_dir, "etc/fuse.conf")
88     with open(path, 'a') as fuse_conf:
89         fuse_conf.write("\n# Added by Cnchi - RebornOS Installer\n")
90         fuse_conf.write("user_allow_other\n")
91
92     path = os.path.join(dest_dir, "etc/pam.d/system-login")
93     with open(path, 'a') as system_login:
94         system_login.write("\n# Added by Cnchi - RebornOS Installer\n")
95         system_login.write("session required\tpam_encfs.so\n")
96         system_login.write("session optional\tpam_mount.so\n")
97
98     path = os.path.join(dest_dir, "etc/pam.d/system-auth")
99     with open(path, "a") as system_auth:
100         system_auth.write("\n# Added by Cnchi - RebornOS Installer\n")
101         system_auth.write("auth sufficient\tpam_encfs.so\n")
102         system_auth.write("auth optional\tpam_mount.so\n")
103
104
105 @misc.raise_privileges
106 def setup(username, dest_dir, password):
107     """ Encrypt user's home folder """
108     # encfs and pam_mount packages are needed
109     # and pam_encfs from AUR, too.
110     # Reference: https://wiki.debian.org/TransparentEncryptionForHomeFolder
111
112     try:
113         backup_conf_files(dest_dir)
114         setup_conf_files(dest_dir)
115     except Exception as ex:
116         logging.error("Can't create and modify encfs configuration files.")
117         template = "An exception of type {0} occured. Arguments:\n{1!r}"
118         message = template.format(type(ex).__name__, ex.args)
119         logging.error(message)
120         logging.error("Home directory won't be encrypted.")
121         return False
122
123     # Move user home dir out of the way
124     mount_dir = os.path.join(dest_dir, "home/", username)
125     backup_dir = os.path.join(dest_dir, "var/tmp/", username)
126     shutil.move(mount_dir, backup_dir)
127
128     # Create necessary dirs, encrypted and mounted(unencrypted)
129     encrypted_dir = os.path.join(dest_dir, "home/.encfs/", username)
130     os.makedirs(encrypted_dir, mode=0o755)
131     os.makedirs(mount_dir, mode=0o755)
132
133     # Set owner
134     shutil.chown(encrypted_dir, username, "users")
135     shutil.chown(mount_dir, username, "users")
136
137     # Create encrypted directory
138     try:
139         cmd = ["/bin/echo", "-e", "p\n{0}\n".format(password)]
140         passw = subprocess.Popen(cmd, stdout=subprocess.PIPE)
141         cmd = ['encfs', '-S', encrypted_dir, mount_dir, "--public"]
142         encfs = subprocess.Popen(
143             cmd, stdin=passw.stdout, stdout=subprocess.PIPE)
144         encfs.communicate()
145         if encfs.poll() != 0:
146             logging.error("Can't run encfs. Bad password?")
147     except subprocess.CalledProcessError as err:
148         logging.error("Error running %s: %s", err.cmd, err.output)
149
150     # Restore user home files
151     for name in os.listdir(backup_dir):
152         shutil.move(os.path.join(backup_dir, name),
153                     os.path.join(mount_dir, name))
154
155     # Delete home backup
156     os.rmdir(backup_dir)
157
158
159 if __name__ == '__main__':
160     setup("test", "/", "1234")
161