# -*- 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
import pwd
import sys
import subprocess
import socket
import time
import urllib . request as urllib2
from urllib . error import URLError
from . function import _print , get_ip_mac_type , parse_error
import OpenSSL
import 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 , readFile
_ = lambda x : x
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 = client . get_sid ( )
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 os . environ . get ( " DEBUG " ) :
print ( _ ( " The client uses certificate {certfile} "
" (server ID {cert_id} ) " ) . format (
certfile = client . CERT_FILE , cert_id = 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
client . write_sid ( result_sid [ 0 ] )
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 : " " )
pkey = makePKey ( rsa )
if not passphrase_callback ( private_key_passwd ) :
pkey . save_key ( key , cipher = None , callback = lambda * unused : " " )
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 , ' wb ' )
crtfile . write ( crtreq )
crtfile . close ( )
user_name = pwd . getpwuid ( os . getuid ( ) ) . pw_name
try :
pwdObj = pwd . getpwnam ( user_name )
except KeyError as e :
_print ( parse_error ( e ) )
return None
os . chown ( key , pwdObj . pw_uid , pwdObj . pw_gid )
os . chmod ( key , 0o600 )
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 as e :
_print ( parse_error ( e ) )
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 " ) % readFile ( cert_path + ' req_id ' ) )
ans = 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 , URLError ) as 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 = 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 = readFile ( csr_file )
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. " ) )
return 1
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 = readFile ( os . path . join ( cert_path , server_host_name + ' .csr ' ) , binary = True )
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 as e :
_print ( parse_error ( e ) )
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 as e :
_print ( parse_error ( e ) )
return None
os . chown ( cert_file , pwdObj . pw_uid , pwdObj . pw_gid )
os . chmod ( cert_file , 0o600 )
if ca_root :
system_ca_db = clVars . Get ( ' core.cl_glob_root_cert ' )
if os . path . exists ( system_ca_db ) :
if ca_root in readFile ( system_ca_db ) :
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 . encode ( " UTF-8 " ) )
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 ] == b ' CN ' :
filename = item [ 1 ] . decode ( " UTF-8 " )
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 = client . get_sid ( )
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 as 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 [ readFile ( cmdLineFile ) . strip ( ) , procNum ]
except :
pass
return [ " " , procNum ]
if not os . access ( ' /proc ' , os . R_OK ) :
return [ ]
return [ getCmd ( x ) for x in listDirectory ( ' /proc ' ) if x . isdigit ( ) ]
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 as e :
_print ( parse_error ( e ) )
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 = readFile ( file_path ) . split ( )
s . connect ( ( ' localhost ' , int ( serv_port ) ) )
req = ' delete, %s , %s , %s , %s ' % ( server_host , str ( server_port ) ,
username , hash_val )
s . send ( req )
s . recv ( size )
return
else :
connect_error + = 1
time . sleep ( 0.3 )
break
except socket . error :
time . sleep ( 0.3 )
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 = readFile ( file_path ) . split ( )
s . connect ( ( ' localhost ' , int ( serv_port ) ) )
return s , hash_val
else :
connect_error + = 1
time . sleep ( 0.3 )
break
except socket . error :
time . sleep ( 0.3 )
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