#-*- coding: utf-8 -*- # Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, pwd import sys, subprocess import socket, time import urllib2 from function import get_sid, get_ip_mac_type import OpenSSL, hashlib from client_class import HTTPSClientCertTransport from cert_verify import VerifyError from calculate.core.datavars import DataVarsCore from calculate.core.server.methods_func import get_password from calculate.lib.cl_lang import setLocalTranslate from calculate.lib.utils.common import getpass from calculate.lib.utils.files import listDirectory setLocalTranslate('cl_console3',sys.modules[__name__]) VERSION = 0.11 def client_post_cert (client, clVars, show_info = False): """ send a certificate server for check """ sid = get_sid(client.SID_FILE) lang = os.environ['LANG'][:2] _result_post_cert, _result_sid = client.service.init_session(sid, lang) result_post_cert = _result_post_cert[1].integer result_sid = _result_sid[1].integer print _("the client uses certificate %s") %client.CERT_FILE print result_post_cert[0] if result_post_cert[0] == -4: print _("Certificate not found on the server") print _("the client uses certificate %s") %client.CERT_FILE print _('You can generate a new certificate using options --gen-cert-by and '\ '--get-cert-from') raise Exception(3) # client_sid(sid, client, cert_id = results[0][0], clVars = clVars) if result_post_cert[0] == -3: print _("Certificate not sent!") elif result_post_cert[0] == -2: print _("Using the upstream certificate") else: if show_info: print _(" Your certifitate ID = %d") %(result_post_cert[0]) try: if result_post_cert[1] == -2: print _("The certificate has expired") elif result_post_cert[1] > 0: if show_info: print _("The certificate expires after %d days") \ %(result_post_cert[1]) except: pass # work with sid fi = open(client.SID_FILE, 'w') sid = str(result_sid[0]) fi.write(sid) fi.close() if show_info: if result_sid[1] == 1: print _(" New Session") else: print _(" Old Session") print _(" Your session ID = %s") %sid #Creation of secret key of the client def new_key_req(key, cert_path, server_host_name, private_key_passwd = None, \ auto = False): from create_cert import generateRSAKey, makePKey, makeRequest,\ passphrase_callback rsa = generateRSAKey() rsa.save_key(key+'_pub', cipher=None, callback = lambda *unused: None) pkey = makePKey(rsa) if not passphrase_callback(private_key_passwd): pkey.save_key(key, cipher = None, callback = lambda *unused: None) else: pkey.save_key(key, callback= lambda *unused: str(private_key_passwd)) req = makeRequest(rsa, pkey, server_host_name, auto) crtreq = req.as_pem() req_file = cert_path + '/%s.csr' %server_host_name crtfile = open(req_file, 'w') crtfile.write(crtreq) crtfile.close() user_name = pwd.getpwuid(os.getuid()).pw_name try: pwdObj = pwd.getpwnam(user_name) except KeyError, e: _print (e) return None os.chown(key, pwdObj.pw_uid, pwdObj.pw_gid) os.chmod(key, 0600) return req_file def delete_old_cert(client): try: os.unlink(client.CERT_FILE) os.unlink(client.REQ_FILE) os.unlink(client.PKEY_FILE) os.unlink(client.PubKEY_FILE) except OSError, e: _print (e.message) def client_post_request (cert_path, args): if os.path.exists(cert_path + 'req_id'): print \ _("You already sent a certificate signature request.") _print (_("Request ID = %s") %open(cert_path + 'req_id', 'r').read()) ans = raw_input (_("Send a new request? y/[n]: ")) if not ans.lower() in ['y','yes']: return 0 clVars = DataVarsCore() clVars.importCore() clVars.flIniFile() port = args.port or clVars.Get('core.cl_core_port') url = "https://%s:%s/?wsdl" %(args.by_host, port) print '%s\n'% url, _("connecting...") from client_class import Client_suds try: client = Client_suds(url, transport = HTTPSClientCertTransport \ (None, None, cert_path)) except (KeyboardInterrupt, urllib2.URLError), e: print '\n'+_("Closing. Connection error.") _print (_("Error: %s") %e) return 0 client.wsdl.services[0].setlocation(url) server_host_name = client.service.get_server_host_name() key = os.path.join(cert_path, server_host_name + '.key') csr_file = os.path.join(cert_path, server_host_name +'.csr') if os.path.exists(key) and os.path.exists(csr_file): print _("the private key and request now exist") ask = raw_input(_("Create a new private key and request? y/[n]: ")) if ask.lower() in ['y','yes']: passwd = get_password() new_key_req(key, cert_path, server_host_name, private_key_passwd = passwd) else: passwd = get_password() new_key_req(key, cert_path, server_host_name, private_key_passwd = passwd) ip, mac, client_type = get_ip_mac_type() data = open(csr_file).read() res = client.service.post_client_request(request = data, ip = ip,\ mac = mac, client_type = client_type) if int(res) < 0: print _("The server has not signed the certificate!") return 1 fc = open(os.path.join(cert_path, 'req_id'), 'w') fc.write(res) fc.close() _print (_("Your request ID = %s") %res + '.\n', _("To submit the certificate request on the server use command") + \ '\n'+'cl-core --sign-client ID_CLIENT_REQUEST') return 0 def client_get_cert(cert_path, args): clVars = DataVarsCore() clVars.importCore() clVars.flIniFile() if not os.path.exists(os.path.join(cert_path, 'req_id')): print _("Request not sent or file %s deleted") \ %(os.path.join(cert_path, 'req_id')) return 1 fc = open(os.path.join(cert_path, 'req_id'), 'r') req_id = fc.read() fc.close() port = args.port or clVars.Get('core.cl_core_port') url = "https://%s:%s/?wsdl" %(args.from_host, port) print '%s\n' %url, _("connecting...") from client_class import Client_suds try: client = Client_suds(url, \ transport = HTTPSClientCertTransport(None, None, cert_path)) except KeyboardInterrupt: print _("Closing. Connection error.") client.wsdl.services[0].setlocation(url) server_host_name = client.service.get_server_host_name() if not os.path.exists(os.path.join(cert_path, server_host_name + '.csr')): print _("Request %s not found on the client's side") \ %(os.path.join(cert_path, server_host_name + '.csr')) return 1 request = open(os.path.join(cert_path, server_host_name + '.csr')).read() md5 = hashlib.md5() md5.update(request) md5sum = md5.hexdigest() result = client.service.get_client_cert(req_id, md5sum) cert = result[0][0] try: ca_root = result[0][1] except IndexError: ca_root = None if cert == '1': print _("Signature request rejected!") return 1 elif cert == '2': print _("Signature request not examined yet.") print _("Your request ID = %s") %req_id + '.\n',\ _("To submit the certificate request on the server use command") + \ '\n'+'cl-core --sign-client ID_CLIENT_REQUEST' return 1 elif cert == '3': print _("Request or signature not matching earlier data.") return 1 elif cert == '4': print _("The request was sent from another IP.") return 1 cert_file = os.path.join(cert_path, server_host_name + '.crt') fc = open(cert_file, 'w') fc.write(cert) fc.close() try: os.unlink(cert_path + 'req_id') except OSError, e: _print (e.message) print _('Certificate saved. Your certificate ID: %s') %req_id user_name = pwd.getpwuid(os.getuid()).pw_name try: pwdObj = pwd.getpwnam(user_name) except KeyError, e: _print (e) return None os.chown(cert_file, pwdObj.pw_uid, pwdObj.pw_gid) os.chmod(cert_file, 0600) if ca_root: system_ca_db = clVars.Get('core.cl_glob_root_cert') if os.path.exists(system_ca_db): if ca_root in open(system_ca_db, 'r').read(): return 0 cl_client_cert_dir = clVars.Get('core.cl_client_cert_dir') homePath = clVars.Get('ur_home_path') cl_client_cert_dir = cl_client_cert_dir.replace("~",homePath) root_cert_md5 = os.path.join(cl_client_cert_dir, "ca/cert_list") md5 = hashlib.md5() md5.update(ca_root) md5sum = md5.hexdigest() print "\n=================================================" print "md5sum = ", md5sum if not os.path.exists(root_cert_md5): fc = open(root_cert_md5,"w") fc.close() filename = None with open(root_cert_md5) as fd: t = fd.read() # for each line for line in t.splitlines(): # Split string into a words list words = line.split(' ',1) if words[0] == md5sum: filename = words[1] if not filename: certobj = OpenSSL.crypto.load_certificate \ (OpenSSL.SSL.FILETYPE_PEM, ca_root) Issuer = certobj.get_issuer().get_components() for item in Issuer: if item[0] == 'CN': filename = item[1] fc = open(root_cert_md5,"a") fc.write('%s %s\n' %(md5sum, filename)) fc.close() if not filename: print _('Field "CN" not found in the certificate!') return 1 fd = open(os.path.join(cl_client_cert_dir, 'ca', filename), 'w') fd.write(ca_root) fd.close() user_root_cert = clVars.Get('core.cl_user_root_cert') user_root_cert = user_root_cert.replace("~",homePath) fa = open(user_root_cert, 'a') fa.write(ca_root) fa.close() print _("filename = "), filename print _("Certificate added") else: print _("The file containing the CA certificate now exists") return 0 def client_post_auth(client): """ authorization client or post request """ sid = get_sid(client.SID_FILE) client.sid = int(sid) try: if os.path.exists(client.CERT_FILE): pass#client_post_cert(client) else: #client_post_request(client) print _("You do not have a certificate. Use option --gen-cert-by HOST to generate a new request or --get-cert-from HOST to get a new certificate from the server.") raise Exception(1) # print client.service.versions(sid, VERSION) except VerifyError, e: print e.value raise Exception(1) ########## Get password def getRunProc(): """List run program""" def getCmd(procNum): cmdLineFile = '/proc/%s/cmdline'%procNum try: if os.path.exists(cmdLineFile): return [open(cmdLineFile,'r').read().strip(), procNum] except: pass return ["", procNum] if not os.access('/proc',os.R_OK): return [] return map(getCmd, filter(lambda x:x.isdigit(), listDirectory('/proc'))) def owner(pid): UID = 1 for ln in open('/proc/%s/status' %pid): if ln.startswith('Uid:'): uid = int(ln.split()[UID]) return pwd.getpwuid(uid).pw_name def create_socket(file_path, username): host = '' # ip port = 5501 # порт find_proc = False # if not file_path: # home_path = pwd.getpwuid(os.getuid()).pw_dir # file_path = os.path.join(home_path, '.calculate', 'passwd_daemon') # if not username: # username = pwd.getpwuid(os.getuid()).pw_name for run_commands in filter(lambda x:'cl-consoled' in \ x[0],getRunProc()): if 'python' in run_commands[0]: if username == owner(run_commands[1]): #print 'YES' find_proc = True if not find_proc: try: os.unlink(file_path) except OSError, e: _print (e.message) cmd = ['cl-consoled'] #print cmd subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout = subprocess.PIPE, stderr=subprocess.PIPE) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) while True: try: s.bind((host,port)) # ассоциировать адрес с сокетом break except socket.error: port += 1 return s def set_password(s, req, size): password = getpass.getpass(_('Password: ')) msg = '%s,%s' %(req,password) s.send(msg) resp = s.recv(size) if resp.startswith('Error'): _print (resp) return password def clear_password(server_host, server_port): size = 1024 # размер данных username = pwd.getpwuid(os.getuid()).pw_name home_path = pwd.getpwuid(os.getuid()).pw_dir file_path = os.path.join(home_path, '.calculate', 'passwd_daemon') s = create_socket(file_path, username) connect_error = 0 while connect_error < 16: try: while connect_error < 10: if os.path.isfile(file_path): serv_port, hash_val = open(file_path, 'r').read().split() break else: connect_error += 1 time.sleep(0.3) s.connect(('localhost', int(serv_port))) break except socket.error: time.sleep(0.3) req = 'delete,%s,%s,%s,%s' %(server_host, str(server_port), username, hash_val) s.send(req) resp = s.recv(size) def socket_connect(s, file_path): connect_error = 0 while connect_error < 16: try: while connect_error < 10: if os.path.isfile(file_path): serv_port, hash_val = open(file_path, 'r').read().split() break else: connect_error += 1 time.sleep(0.3) s.connect(('localhost', int(serv_port))) break except socket.error: time.sleep(0.3) return s, hash_val def get_password_from_daemon(server_host, server_port, wait_thread): size = 1024 # размер данных username = pwd.getpwuid(os.getuid()).pw_name home_path = pwd.getpwuid(os.getuid()).pw_dir file_path = os.path.join(home_path, '.calculate', 'passwd_daemon') while True: s = create_socket(file_path, username) s, hash_val = socket_connect(s, file_path) req = '%s,%s,%s,%s' %(server_host,str(server_port),username,hash_val) s.send(req) resp = s.recv(size) if resp.startswith('Error'): if 'timeout' in resp: continue wait_thread.stop() sys.stdout.write('\r') sys.stdout.flush() password = set_password(s, req, size) else: password = resp if resp else None return password