source: internals/2016/linuxloginsmartcardwizard/trunk/project1/config.py @ 16354

Last change on this file since 16354 was 16354, checked in by dcorreia, 4 years ago

Added final step of configuration: pam-auth-update execution
Changed user-certificate mapping logic
Added documentation to config module
Code refactoring in config module

File size: 8.8 KB
Line 
1#!/usr/bin/python3
2import os
3import subprocess
4import sys
5import shutil
6import inspect
7
8
9INSTALL_COMMAND = "apt-get install "        # Package installation
10HASHLINK_COMMAND = "pkcs11_make_hash_link"  # PKCS11 hash links creation
11WGET_COMMAND = "wget "                      # Download file with wget
12GUNZIP_COMMAND = "gunzip "                  # Extract zipped files with gunzip
13MV_COMMAND = "mv "                          # Move/Rename file
14INSPECT_COMMAND = "pkcs11_inspect"          # PKCS11 inspect card data
15COMMONAUTH = "/etc/pam.d/common-auth"       # PAM file with authentication configurations
16TRASH_OUTPUT = open(os.devnull, "wb")       # Send output to trash file
17TEMP_OUTPUT = "/tmp/cardData"               # Send output to temporary file
18USEMODULE_OPTION = "use_pkcs11_module"      # Configuration option to choose the active module
19USEMAPPERS_OPTION = "use_mappers"           # Configuration option to choose the active mappers
20# PKCS11 update for common-auth
21PKCS11AUTH = "auth\tsufficient\tpam_pkcs11.so config_file=/etc/pam_pkcs11/pam_pkcs11.conf"
22
23
24def executeCommand(command, outputPath=None):
25    """
26    Executes a shell command and redirects output (optional)
27    :param command: command to execute
28    :param outputPath: path to redirect output (optional)
29    :return: no return value
30    """
31    try:
32        process = subprocess.Popen(command, shell=True, stdout=outputPath, stderr=subprocess.PIPE)
33        process.wait()
34        print("DEBUG: executeCommand (%s) - %s" % (command, process.stderr.read()), file=sys.stderr)
35    except subprocess.CalledProcessError as error:
36        print("DEBUG: executeCommand (%s) - %s" % (command, error), file=sys.stderr)
37
38
39def executeCommandInDirectory(command, directoryPath, outputPath=None):
40    """
41    Executes a shell command in a specific directory and redirects output (optional)
42    :param command: command to execute
43    :param directoryPath: path of the directory
44    :param outputPath: path to redirect output (optional)
45    :return: no return value
46    """
47    oldDirectory = os.getcwd()
48    os.chdir(directoryPath)
49    executeCommand(command, outputPath)
50    os.chdir(oldDirectory)
51
52
53def printDebugInfo(debugData):
54    """
55    Prints debug information
56    :param debugData: string of debug data
57    :return: no return value
58    """
59    print("DEBUG: %s - %s" % (inspect.stack()[1][3], debugData), file=sys.stderr)
60
61
62def installPackage(packageName):
63    """
64    Installs package using apt-get
65    :param packageName: name of the package
66    :return: no return value
67    """
68    executeCommand(INSTALL_COMMAND+packageName, TRASH_OUTPUT)
69
70
71def makeDirectory(directoryPath):
72    """
73    Creates a new directory
74    :param directoryPath: path of the new directory
75    :return: no return value
76    """
77    try:
78        os.mkdir(directoryPath)
79        printDebugInfo("created directory with path "+directoryPath)
80    except OSError as error:
81        printDebugInfo(error)
82
83
84def copyFileToDirectory(filePath, directoryPath):
85    """
86    Copy a file to a directory
87    :param filePath: path of the file to copy
88    :param directoryPath: path of the directory
89    :return: no return value
90    """
91    try:
92        shutil.copy2(filePath, directoryPath)
93    except FileNotFoundError as error:
94        printDebugInfo(error)
95
96
97def readFileToList(filePath):
98    """
99    Reads the file and returns a list with the content
100    :param filePath: path of the file
101    :return: list of strings with content of the file
102    """
103    return open(filePath, mode="r").readlines()
104
105
106def readFileToString(filePath):
107    """
108    Reads a file and returns a string with the content
109    :param filePath: path of the file
110    :return: string of content of the file
111    """
112    return "".join(readFileToList(filePath))
113
114
115def writeStringToFile(filePath, stringData):
116    """
117    Writes input string in the file
118    :param filePath: path of the file
119    :param stringData: string to write
120    :return: no return value
121    """
122    open(filePath, mode="w").write(stringData)
123
124
125def writeListToFile(filePath, listData):
126    """
127    Write input list of data in the file
128    :param filePath: path of the file
129    :param listData: list of data to write
130    :return: no return value
131    """
132    writeStringToFile(filePath, "".join(listData))
133
134
135def appendStringToFile(filePath, stringData):
136    """
137    Append input string to the end of the file
138    :param filePath: path of the file
139    :param stringData: string of data to write
140    :return: no return value
141    """
142    open(filePath, mode="a").write(stringData)
143
144
145def makeHashLinks(directoryPath):
146    """
147    Make pkcs11 hash links in a directory
148    :param directoryPath: path of directory
149    :return: no return value
150    """
151    executeCommandInDirectory(HASHLINK_COMMAND, directoryPath)
152
153
154def getCRLFile(crlWebLink, directoryPath):
155    """
156    Download crl file into a directory
157    :param crlWebLink: link of the crl file
158    :param directoryPath: path of the directory
159    :return: no return value
160    """
161    executeCommandInDirectory(WGET_COMMAND+crlWebLink, directoryPath)
162
163
164def makeConfigFile(configZipPath, configPath, directoryPath):
165    """
166    Make pam_pkcs11.conf configuration file
167    :param configZipPath: path of the configuration file example zip archive
168    :param configPath: path to store the configuration file
169    :param directoryPath: path of the directory for shell commands execution
170    :return: no return value
171    """
172    copyFileToDirectory(configZipPath, directoryPath)
173    executeCommandInDirectory(GUNZIP_COMMAND+"pam_pkcs11.conf.example.gz", directoryPath)
174    executeCommandInDirectory(MV_COMMAND+"pam_pkcs11.conf.example "+configPath, directoryPath)
175
176
177def addConfigModule(moduleFileName, configPath):
178    """
179    Add a configuration module to the pam_pkcs11.conf configuration file
180    :param moduleFileName: name of the module data file
181    :param configPath: path of the configuration file
182    :return: no return value
183    """
184    configData = readFileToList(configPath)
185    configData[-1] = readFileToString(moduleFileName) + "\n" + configData[-1]
186    writeListToFile(configPath, configData)
187
188
189def getIndexOfToken(token, listData):
190    """
191    Gets index of list element that contains the input token
192    :param token: token to find
193    :param listData: list of data
194    :return: index where the token was found
195    """
196    for i in range(0, len(listData)):
197        if token in listData[i]:
198            return i
199
200
201def setConfigurationOption(option, newValue, configPath):
202    """
203    Sets value of a configuration option
204    :param option: the configuration option
205    :param newValue: the new value to be set
206    :param configPath: path of the configuration file
207    :return: no return value
208    """
209    configData = readFileToList(configPath)
210    moduleIndex = getIndexOfToken(option, configData)
211    configData[moduleIndex] = "  " + option + " = " + newValue + ";\n"
212    writeListToFile(configPath, configData)
213
214
215def changeUseModule(newModule, configPath):
216    """
217    Changes module of the use_pkcs11_module configuration option
218    :param newModule: new module to be used
219    :param configPath: path of the configuration file
220    :return: no return value
221    """
222    setConfigurationOption(USEMODULE_OPTION, newModule, configPath)
223
224
225def changeUseMappers(newMappers, configPath):
226    """
227    Changes mappers of the use_mappers configuration option
228    :param newMappers: new mappers to be used
229    :param configPath: path of the configuration file
230    :return: no return value
231    """
232    setConfigurationOption(USEMAPPERS_OPTION, newMappers, configPath)
233
234
235def getCardAuthCertificate():
236    """
237    Gets authentication certificate from the card
238    :return: certificate in string format
239    """
240    executeCommand(INSPECT_COMMAND, open(TEMP_OUTPUT, mode="w"))
241    cardData = readFileToList(TEMP_OUTPUT)
242    for line in cardData:
243        if "Autentica" in line and "serialNumber=" in line:
244            return line
245
246
247def addUserMapping(mappingConfigPath, username):
248    """
249    Add a user mapping with a certificate
250    :param mappingConfigPath: path of the mapping configurations file
251    :param username: name of the user
252    :return: True on success and False on failure
253    """
254    certificate = getCardAuthCertificate()
255    if certificate is None:
256        printDebugInfo("No certificate found. Make sure the card is inserted and the PIN is correct")
257        return False
258    else:
259        combo = certificate.strip() + " -> " + username + "\n"
260        appendStringToFile(mappingConfigPath, combo)
261        return True
262
263
264def runPamAuthUpdate():
265    """
266    Simulates the execution of pam-auth-update to active pam_pkcs11 in the system
267    :return: no return value
268    """
269    authData = readFileToList(COMMONAUTH)
270    pkcs11Index = getIndexOfToken("pam_pkcs11.so", authData)
271    unixIndex = getIndexOfToken("pam_unix.so", authData)
272    if pkcs11Index is None:
273        authData[unixIndex] = PKCS11AUTH + "\n" + authData[unixIndex]
274        writeListToFile(COMMONAUTH, authData)
Note: See TracBrowser for help on using the repository browser.