]> gitweb.michael.orlitzky.com - untangle-https-backup.git/blob - bin/untangle-https-backup
Rename the executable, and implement a bunch of missing stuff.
[untangle-https-backup.git] / bin / untangle-https-backup
1 #!/usr/bin/python3
2 """
3 Back up Untangle configurations over HTTPS.
4 """
5
6 from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
7 import configparser
8 import http.cookiejar
9 from os import chmod
10 import ssl
11 from sys import stderr
12 import urllib.parse
13 import urllib.request
14
15
16 # Define a few exit codes.
17 EXIT_OK = 0
18 EXIT_BACKUPS_FAILED = 1
19
20
21 class Untangle:
22
23 def __init__(self, s):
24 """
25 Initialize this Untangle object with a ConfigParser section.
26 """
27 self.name = s.name
28 self.host = s['host']
29 self.username = s.get('username', 'admin')
30 self.password = s['password']
31 self.version = int(s.get('version', '11'))
32 self.base_url = 'https://' + self.host + '/' # This never changes
33
34 # Sanity check the numerical version.
35 if self.version not in [9, 11]:
36 msg = 'Invalid version "' + str(self.version) + '" '
37 msg += 'in section "' + s.name + '"'
38 raise configparser.ParsingError(msg)
39
40 # Sanity check the boolean verify_cert parameter.
41 vc = s.get('verify_cert', 'False')
42 if vc == 'True':
43 self.verify_cert = True
44 elif vc == 'False':
45 self.verify_cert = False
46 else:
47 msg = 'Invalid value "' + vc + '" for verify_cert '
48 msg += 'in section "' + s.name + '"'
49 raise configparser.ParsingError(msg)
50
51 #
52 # Finally, create a URL opener to make HTTPS requests.
53 #
54 # First, create a cookie jar that we'll attach to our URL
55 # opener thingy.
56 cj = http.cookiejar.CookieJar()
57 cookie_proc = urllib.request.HTTPCookieProcessor(cj)
58
59 # SSL mumbo jumbo to make it ignore the certificate's hostname
60 # when verify_cert = False.
61 if self.verify_cert:
62 ssl_ctx = ssl.create_default_context()
63 else:
64 ssl_ctx = ssl._create_unverified_context()
65
66 https_handler = urllib.request.HTTPSHandler(context=ssl_ctx)
67
68 # Now Create a URL opener, and tell it to use our cookie jar
69 # and SSL context. We keep this around for future requests.
70 self.opener = urllib.request.build_opener(https_handler, cookie_proc)
71
72
73 def login(self):
74 login_path = 'auth/login?url=/setup/welcome.do&realm=Administrator'
75 url = self.base_url + login_path
76 post_vars = {'username': self.username, 'password': self.password }
77 post_data = urllib.parse.urlencode(post_vars).encode('ascii')
78 self.opener.open(url, post_data)
79
80
81 def get_backup(self):
82 if self.version == 9:
83 return self.get_backup_v9()
84 elif self.version == 11:
85 return self.get_backup_v11()
86
87
88 def get_backup_v9(self):
89 url = self.base_url + '/webui/backup'
90 post_vars = {'action': 'requestBackup'}
91 post_data = urllib.parse.urlencode(post_vars).encode('ascii')
92 self.opener.open(url, post_data)
93
94 url = self.base_url + 'webui/backup?action=initiateDownload'
95 with self.opener.open(url) as response:
96 return response.read()
97
98
99 def get_backup_v11(self):
100 url = self.base_url + '/webui/download?type=backup'
101 post_vars = {'type': 'backup'}
102 post_data = urllib.parse.urlencode(post_vars).encode('ascii')
103 with self.opener.open(url, post_data) as response:
104 return response.read()
105
106
107
108 # Create an argument parser using our docsctring as its description.
109 parser = ArgumentParser(description = __doc__,
110 formatter_class = ArgumentDefaultsHelpFormatter)
111
112 parser.add_argument('-c',
113 '--config-file',
114 default='/etc/untangle-https-backup.ini',
115 help='path to configuration file')
116
117 args = parser.parse_args()
118
119 # Default to success, change it if anything fails.
120 status = EXIT_OK
121
122 config = configparser.ConfigParser()
123 config.read(args.config_file)
124
125 for section in config.sections():
126 untangle = Untangle(config[section])
127 try:
128 untangle.login()
129 backup = untangle.get_backup()
130 filename = untangle.name + '.backup'
131 with open(filename, 'wb') as f:
132 f.write(backup)
133 chmod(filename, 0o600)
134
135 except urllib.error.URLError as e:
136 msg = untangle.name + ': ' + str(e.reason)
137 msg += ' from ' + untangle.host
138 print(msg, file=stderr)
139 status = EXIT_BACKUPS_FAILED
140 except urllib.error.HTTPError as e:
141 msg = untangle.name + ': ' + 'HTTP error ' + str(e.code)
142 msg += ' from ' + untangle.host
143 print(msg, file=stderr)
144 status = EXIT_BACKUPS_FAILED
145
146 exit(status)