1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import re
17 import os
18 import pwd
19 import grp
20 import sys
21 import stat
22 import base64
23 from config_common import cfg_exceptions
24 from config_common import local_config
25 from config_common import utils
26 from config_common.rhn_log import log_debug
27 from rhn import rpclib
28 Output = rpclib.transports.Output
29
30 try:
31 PY3 = False
32 import xmlrpclib
33 except ImportError:
34 PY3 = True
35 import xmlrpc.client as xmlrpclib
36 basestring = (str, bytes)
37
38 from spacewalk.common.usix import raise_with_tb
39
40 try:
41 from selinux import lgetfilecon
42 except:
43
46
47
48 from config_common import rpc_wrapper
49 rpclib = rpc_wrapper
50
51
53 """convert a normal decimal int to another int representing the octal value"""
54
55
56 return int(oct(number).replace("o", ""))
57
58
60 _uid_cache = {}
61 _gid_cache = {}
62 _local_config = local_config
63
65 self.default_delimiters = None
66 self.maximum_file_size = None
67
68
69
70
71
75
77 "returns the default delimiters"
78 if self.default_delimiters is None:
79 self.default_delimiters = self._get_default_delimiters()
80 return self.default_delimiters
81
83 raise NotImplementedError
84
86 "returns the maximum file size"
87 if self.maximum_file_size is None:
88 self.maximum_file_size = self._get_maximum_file_size()
89 return self.maximum_file_size
90
92 "To be overwritten in subclasses"
93 return 1024
94
96
97 ret = {}
98 fields = {
99 'mode' : stat.ST_MODE,
100 'user' : stat.ST_UID,
101 'group' : stat.ST_GID,
102 'size' : stat.ST_SIZE,
103 'mtime' : stat.ST_MTIME,
104 'ctime' : stat.ST_CTIME,
105 }
106 for label, st in fields.items():
107 ret[label] = file_stat[st]
108
109
110 ret['mode'] = deci_to_octal(ret['mode'] & int('07777', 8))
111
112
113
114
115
116
117 uid = ret['user']
118 gid = ret['group']
119
120 pw_name = self._uid_cache.get(uid)
121 if not pw_name:
122 try:
123 pw_name = pwd.getpwuid(uid)[0]
124 except KeyError:
125 print("Error looking up user id %s" % (uid, ))
126
127 if pw_name:
128 ret['user'] = pw_name
129 self._uid_cache[uid] = pw_name
130
131 gr_name = self._gid_cache.get(gid)
132 if not gr_name:
133 try:
134 gr_name = grp.getgrgid(gid)[0]
135 except KeyError:
136 print("Error looking up group id %s" % (gid, ))
137
138 if gr_name:
139 ret['group'] = gr_name
140 self._gid_cache[gid] = gr_name
141
142
143
144
145 try:
146 selinux_ctx = lgetfilecon(path)[1]
147 except OSError:
148 selinux_ctx = ''
149 if selinux_ctx == None:
150 selinux_ctx = ''
151
152 ret['selinux_ctx'] = selinux_ctx
153
154 return ret
155
156 - def _make_file_info(self, remote_path, local_path=None, delim_start=None,
157 delim_end=None, load_contents=1):
158 if not local_path:
159
160 local_path = remote_path
161
162 try:
163 file_stat = os.lstat(local_path)
164 except OSError:
165 e = sys.exc_info()[1]
166 raise_with_tb(cfg_exceptions.RepositoryLocalFileError(
167 "Error lstat()-ing local file: %s" % e), sys.exc_info()[2])
168
169
170 if delim_start or delim_end:
171 if not (delim_start and delim_end):
172
173
174 delim_start = delim_end = (delim_start or delim_end)
175 else:
176
177 delim_start, delim_end = self.get_file_delimiters(remote_path)
178
179 params = {
180 'path' : remote_path,
181 'delim_start' : delim_start,
182 'delim_end' : delim_end,
183 }
184
185 file_contents = None
186 if os.path.islink(local_path):
187 params['config_file_type_id'] = 3
188 params['symlink'] = os.readlink(local_path)
189 load_contents = 0
190 elif os.path.isdir(local_path):
191 params['config_file_type_id'] = 2
192 load_contents = 0
193 else:
194 params['config_file_type_id'] = 1
195
196 if load_contents:
197 try:
198 file_contents = open(local_path, "rb").read()
199 except IOError:
200 e = sys.exc_info()[1]
201 raise_with_tb(cfg_exceptions.RepositoryLocalFileError(
202 "Error opening local file: %s" % e), sys.exc_info()[2])
203
204 self._add_content(file_contents, params)
205
206 params.update(self.make_stat_info(local_path, file_stat))
207 return params
208
209 - def _add_content(self, file_contents, params):
210 """Add the file contents to the params hash"""
211
212 params['enc64'] = 1
213 params['file_contents'] = base64.encodestring(file_contents)
214
215 - def login(self, username=None, password=None):
217
218
220
222 Repository.__init__(self)
223
224
225
226
227
228 self.__server_url = self._local_config.get('server_url')
229
230
231
232 self.__server_list = self._local_config.get('server_list')
233
234
235
236
237
238
239 handler = self._local_config.get('server_handler')
240 cap_handler = re.sub('[^/]+$', 'XMLRPC', handler)
241
242 if not self.__server_url:
243 raise cfg_exceptions.ConfigurationError(
244 "Missing entry 'server_url' in the config files\n" \
245 "Try running as root, or configure server_url as described in the configuration file"
246 )
247
248 log_debug(3, "server url", self.__server_url)
249 self.__proxy_user = None
250 self.__proxy_password = None
251 self.__proxy_host = None
252
253 self.__enable_proxy = self._local_config.get('enableProxy')
254 self.__enable_proxy_auth = self._local_config.get('enableProxyAuth')
255
256 if self.__enable_proxy:
257 self.__proxy_host = self._local_config.get('httpProxy')
258
259 if self.__enable_proxy_auth:
260 self.__proxy_user = self._local_config.get('proxyUser')
261 self.__proxy_password = self._local_config.get('proxyPassword')
262
263 ca = self._local_config.get('sslCACert')
264 if isinstance(ca, basestring):
265 ca = [ca]
266
267 ca_certs = ca or ["/usr/share/rhn/RHNS-CA-CERT"]
268
269
270 lang = None
271 for env in 'LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG':
272 if env in os.environ:
273 if not os.environ[env]:
274
275 continue
276 lang = os.environ[env].split(':')[0]
277 lang = lang.split('.')[0]
278 break
279
280 if setup_network:
281
282
283
284
285
286
287
288
289
290 x_server_url = self._patch_uris(self.__server_url, cap_handler)
291 if self.__server_list != None:
292 x_server_list = self._patch_uris(self.__server_list, cap_handler)
293 else:
294 x_server_list = None
295
296 x_server = rpclib.Server(x_server_url,
297 proxy=self.__proxy_host,
298 username=self.__proxy_user,
299 password=self.__proxy_password,
300 server_list=x_server_list,
301 rpc_handler="/XMLRPC")
302
303
304
305 try:
306 x_server.registration.welcome_message()
307 except xmlrpclib.Fault:
308 e = sys.exc_info()[1]
309 sys.stderr.write("XML-RPC error while talking to %s:\n %s\n" % (self.__server_url, e))
310 sys.exit(2)
311
312 self._server_capabilities = get_server_capability(x_server)
313 del x_server
314
315
316
317
318
319
320 self.__server_url = self._patch_uris(self.__server_url, handler)
321 if self.__server_list != None:
322 self.__server_list = self._patch_uris(self.__server_list, handler)
323 else:
324 self.__server_list = None
325
326 self.server = rpclib.Server(self.__server_url,
327 proxy=self.__proxy_host,
328 username=self.__proxy_user,
329 password=self.__proxy_password,
330 server_list=self.__server_list,
331 rpc_handler=handler)
332
333 self._set_capabilities()
334 self.server.set_transport_flags(
335 transfer=Output.TRANSFER_BINARY,
336 encoding=Output.ENCODE_GZIP
337 )
338
339 if lang:
340 self.server.setlang(lang)
341
342 for ca_cert in ca_certs:
343 if not os.access(ca_cert, os.R_OK):
344 raise cfg_exceptions.ConfigurationError("Can not find CA file: %s" % ca_cert)
345
346 log_debug(3, "ca cert", ca_cert)
347
348 self.server.add_trusted_cert(ca_cert)
349
350
351
352
367
369
370 capabilities = {
371 'configfiles.base64_enc' : {'version' : 1, 'value' : 1},
372 'rhncfg.dirs_enabled' : {'version' : 1, 'value' : 1},
373 }
374 for name, hashval in capabilities.items():
375 cap = "%s(%s)=%s" % (name, hashval['version'], hashval['value'])
376 self.server.add_header("X-RHN-Client-Capability", cap)
377
378 - def rpc_call(self, method_name, *params):
379 method = getattr(self.server, method_name)
380 try:
381 result = method(*params)
382 except xmlrpclib.ProtocolError:
383 e = sys.exc_info()[1]
384 sys.stderr.write("XML-RPC call error: %s\n" % e)
385 sys.exit(1)
386 except xmlrpclib.Fault:
387
388 raise
389 except Exception:
390 e = sys.exc_info()[1]
391 sys.stderr.write("XML-RPC error while talking to %s: %s\n" % (
392 self.__server_url, e))
393 sys.exit(2)
394
395 return result
396
398 return self.rpc_call('config.max_upload_fsize')
399
400 - def _add_content(self, file_contents, params):
401 """Add the file contents to the params hash"""
402
403
404
405 if 'rhncfg.content.base64_decode' in self._server_capabilities:
406 params['enc64'] = 1
407 params['file_contents'] = base64.encodestring(file_contents)
408 else:
409 params['file_contents'] = file_contents
410
411 return params
412
414 headers = s.get_response_headers()
415 if headers is None:
416
417 return {}
418 if PY3:
419 cap_headers = ["X-RHN-Server-Capability: %s" % val for val in headers.get_all("X-RHN-Server-Capability")]
420 else:
421 cap_headers = headers.getallmatchingheaders("X-RHN-Server-Capability")
422
423 if not cap_headers:
424 return {}
425 regexp = re.compile(
426 r"^(?P<name>[^(]*)\((?P<version>[^)]*)\)\s*=\s*(?P<value>.*)$")
427 vals = {}
428 for h in cap_headers:
429 arr = h.split(':', 1)
430 assert len(arr) == 2
431 val = arr[1].strip()
432 if not val:
433 continue
434
435 mo = regexp.match(val)
436 if not mo:
437
438 continue
439 vdict = mo.groupdict()
440 for k, v in vdict.items():
441 vdict[k] = v.strip()
442
443 vals[vdict['name']] = vdict
444 return vals
445