3 Back up Untangle configurations over HTTPS.
6 from argparse
import ArgumentDefaultsHelpFormatter
, ArgumentParser
11 from sys
import stderr
16 # Define a few exit codes.
18 EXIT_BACKUPS_FAILED
= 1
23 def __init__(self
, s
):
25 Initialize this Untangle object with a ConfigParser section.
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
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
)
40 # Sanity check the boolean verify_cert parameter.
41 vc
= s
.get('verify_cert', 'False')
43 self
.verify_cert
= True
45 self
.verify_cert
= False
47 msg
= 'Invalid value "' + vc
+ '" for verify_cert '
48 msg
+= 'in section "' + s
.name
+ '"'
49 raise configparser
.ParsingError(msg
)
52 # Finally, create a URL opener to make HTTPS requests.
54 # First, create a cookie jar that we'll attach to our URL
56 cj
= http
.cookiejar
.CookieJar()
57 cookie_proc
= urllib
.request
.HTTPCookieProcessor(cj
)
59 # SSL mumbo jumbo to make it ignore the certificate's hostname
60 # when verify_cert = False.
62 ssl_ctx
= ssl
.create_default_context()
64 ssl_ctx
= ssl
._create
_unverified
_context
()
66 https_handler
= urllib
.request
.HTTPSHandler(context
=ssl_ctx
)
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
)
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
)
83 return self
.get_backup_v9()
84 elif self
.version
== 11:
85 return self
.get_backup_v11()
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
)
94 url
= self
.base_url
+ 'webui/backup?action=initiateDownload'
95 with self
.opener
.open(url
) as response
:
96 return response
.read()
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()
108 # Create an argument parser using our docsctring as its description.
109 parser
= ArgumentParser(description
= __doc__
,
110 formatter_class
= ArgumentDefaultsHelpFormatter
)
112 parser
.add_argument('-c',
114 default
='/etc/untangle-https-backup.ini',
115 help='path to configuration file')
117 args
= parser
.parse_args()
119 # Default to success, change it if anything fails.
122 config
= configparser
.ConfigParser()
123 config
.read(args
.config_file
)
125 for section
in config
.sections():
126 untangle
= Untangle(config
[section
])
129 backup
= untangle
.get_backup()
130 filename
= untangle
.name
+ '.backup'
131 with open(filename
, 'wb') as f
:
133 chmod(filename
, 0o600)
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