#-*- coding: utf-8 -*- # Copyright 2012 Calculate Ltd. 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('calculate_console',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 if result_post_cert[0] == -4: print _("Certificate not found in Server Database!") print _('client use certificate %s') %client.CERT_FILE print _('You can generate a new certificate using the keys ' '--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 send!") else: if show_info: print _(" Your certifitate id - %d") %(result_post_cert[0]) try: if result_post_cert[1] == -2: print _("expiry date certificate has passed") elif result_post_cert[1] > 0: if show_info: print _("shelf life 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 have sent a request to sign the certificate.") _print (_("request id - %s") %open(cert_path + 'req_id', 'r').read()) ans = raw_input (_("Send new request? y/[n]: ")) if not ans.lower() in ['y','yes']: return 0 url = "https://%s:%d/?wsdl" %(args.by_host, args.port) print '%s\n'% url, _("connect...") from client_class import Client_suds try: client = Client_suds(url, transport = HTTPSClientCertTransport \ (None, None, cert_path)) except (KeyboardInterrupt, urllib2.URLError), e: print '\n'+_("Close. Connecting 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 _('secret key and request exists') ask = raw_input(_("Create new secret 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 _("This server can not sign certificate!") return 1 fc = open(os.path.join(cert_path, 'req_id'), 'w') fc.write(res) fc.close() _print (_("Your request id - %s") %res) return 0 def client_get_cert(cert_path, args): if not os.path.exists(os.path.join(cert_path, 'req_id')): print _("request was not sent or deleted file %s") \ %(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() url = "https://%s:%d/?wsdl" %(args.from_host, args.port) print '%s\n' %url, _("connect...") from client_class import Client_suds try: client = Client_suds(url, \ transport = HTTPSClientCertTransport(None, None, cert_path)) except KeyboardInterrupt: print _("Close. Connecting 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 client 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] ca_root = result[0][1] if cert == '1': print _('Request to sign is rejected!') return 1 elif cert == '2': print _("Request for the signing has not yet reviewed.") print _("Your request id - %s") %req_id return 1 elif cert == '3': print _("Request on signature does not match sent earlier.") return 1 elif cert == '4': print _("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 'OK. Certificate save. 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: clVars = DataVarsCore() clVars.importCore() clVars.flIniFile() system_ca_db = clVars.Get('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('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 _('Not found field "CN" in 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('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 ADD") else: print _("file with ca certificates 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 key --gen-cert-by " "HOST for generate new request or key --get-cert-from " "HOST for get new certificate from 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 #def get_password_from_daemon(server_host, server_port, set_pass = False): # host = '' # ip # port = 5501 # порт # size = 1024 # размер данных # find_proc = False # username = pwd.getpwuid(os.getuid()).pw_name # for run_commands in filter(lambda x:'s.py' in x[0],getRunProc()): # if 'python' in run_commands[0]: # if username == owner(run_commands[1]): # #print 'YES' # find_proc = True # # home_path = pwd.getpwuid(os.getuid()).pw_dir # file_path = os.path.join(home_path, '.calculate', 'passwd_daemon') # if not find_proc: # os.unlink(file_path) # # cmd = ['/var/calculate/s.py'] # #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 # 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) # #print s.recv(1024) # req = '%s,%s,%s,%s' %(server_host, str(server_port), username, hash_val) # s.send(req) # resp = s.recv(size) # if resp.startswith('Error'): # password = getpass() # msg = '%s,%s' %(req,password) # s.send(msg) # resp = s.recv(size) # if resp.startswith('Error'): # print resp # else: # password = resp if resp else None # return password ######################### End get password