diff --git a/test/functional/setup/build_ksp.py b/test/functional/setup/build_ksp.py deleted file mode 100644 index fb524719..00000000 --- a/test/functional/setup/build_ksp.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/python3 -######################################################################################### -# -# Description: This script builds a custom keystore provider and compiles the app that -# uses this KSP. Their names can be passed as arguments, but the outputs -# are always -# - myKSP.dll (myKSPx64.dll) / myKSP.so -# - ksp_app.exe / ksp_app -# -# Requirement: -# python 3.x -# myKSP.c (or any equivalent) -# ksp_app.c (or any equivalent) -# msodbcsql.h (odbc header file) -# -# Execution: Run with command line with optional options -# py build_ksp.py --KSP myKSP --APP ksp_app -# -############################################################################################# - -import sys -import os -import platform -import argparse - -# This creates a batch *filename*, which compiles a C program according to -# *command* and *arch* (either x86 or x64) -def create_batch_file(arch, filename, command): - root_dir = 'C:' + os.sep - vcvarsall = os.path.join(root_dir, "Program Files (x86)", "Microsoft Visual Studio 14.0", "VC", "vcvarsall.bat") - - try: - file = open(filename, 'w') - file.write('@ECHO OFF' + os.linesep) - if arch == 'x64': - file.write('@CALL "' + vcvarsall + '" amd64' + os.linesep) - else: - file.write('@CALL "' + vcvarsall + '" x86' + os.linesep) - - # compile the code - file.write('@CALL ' + command + os.linesep) - file.close() - except: - print('Cannot create ', filename) - -# This invokes the newly created batch file to compile the code, -# according to *arch* (either x86 or x64). The batch file will be -# removed afterwards -def compile_KSP_windows(arch, ksp_src): - output = 'myKSP' - if arch == 'x64': - output = output + arch + '.dll' - else: - output = output + '.dll' - - command = 'cl {0} /LD /MD /link /out:'.format(ksp_src) + output - batchfile = 'build_KSP.bat' - create_batch_file(arch, batchfile, command) - os.system(batchfile) - os.remove(batchfile) - -# This compiles myKSP.c -# -# In Windows, this will create batch files to compile two dll(s). -# Otherwise, this will compile the code and generate a .so file. -# -# Output: A custom keystore provider created -def compile_KSP(ksp_src): - print('Compiling ', ksp_src) - if platform.system() == 'Windows': - compile_KSP_windows('x64', ksp_src) - compile_KSP_windows('x86', ksp_src) - else: - os.system('gcc -fshort-wchar -fPIC -o myKSP.so -shared {0}'.format(ksp_src)) - -# This compiles ksp app, which assumes the existence of the .dll or the .so file. -# -# In Windows, a batch file is created in order to compile the code. -def configure_KSP(app_src): - print('Compiling ', app_src) - if platform.system() == 'Windows': - command = 'cl /MD {0} /link odbc32.lib /out:ksp_app.exe'.format(app_src) - batchfile = 'build_app.bat' - create_batch_file('x86', batchfile, command) - os.system(batchfile) - os.remove(batchfile) - else: - os.system('gcc -o ksp_app -fshort-wchar {0} -lodbc -ldl'.format(app_src)) - -################################### Main Function ################################### -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('-ksp', '--KSPSRC', default='myKSP.c', help='The source file of KSP (keystore provider)') - parser.add_argument('-app', '--APPSRC', default='ksp_app.c', help='The source file for the app that uses the KSP') - args = parser.parse_args() - - ksp_src = args.KSPSRC - app_src = args.APPSRC - header = 'msodbcsql.h' - - cwd = os.getcwd() - - # make sure all required source and header files are present - work_dir = os.path.dirname(os.path.realpath(__file__)) - os.chdir(work_dir) - - if not os.path.exists(os.path.join(work_dir, header)): - print('Error: {0} not found!'.format(header)) - exit(1) - if not os.path.exists(os.path.join(work_dir, ksp_src)): - print('Error: {0}.c not found!'.format(ksp_src)) - exit(1) - if not os.path.exists(os.path.join(work_dir, app_src)): - print('Error: {0}.c not found!'.format(app_src)) - exit(1) - - compile_KSP(ksp_src) - configure_KSP(app_src) - - os.chdir(cwd) - - \ No newline at end of file diff --git a/test/functional/setup/ksp_app.c b/test/functional/setup/ksp_app.c deleted file mode 100644 index 86107802..00000000 --- a/test/functional/setup/ksp_app.c +++ /dev/null @@ -1,305 +0,0 @@ -/****************************************************************************** - Example application for demonstration of custom keystore provider usage - - Windows: compile with cl /MD ksp_app.c /link odbc32.lib /out:ksp_app.exe - Linux/mac: compile with gcc -o ksp_app -fshort-wchar ksp_app.c -lodbc -ldl - - usage: kspapp connstr - - ******************************************************************************/ - -#define KSPNAME L"MyCustomKSPName" -#define PROV_ENCRYPT_KEY "LPKCWVD07N3RG98J0MBLG4H2" /* this can be any character string */ - -#include -#include -#ifdef _WIN32 -#include -#else -#define __stdcall -#include -#endif -#include -#include -#include "msodbcsql.h" - -enum job { - set_up = 0, - clean_up = 1 -}; - -/* Convenience functions */ - -int checkRC(SQLRETURN rc, char *msg, int ret, SQLHANDLE h, SQLSMALLINT ht) { - if (rc == SQL_ERROR) { - fprintf(stderr, "Error occurred upon %s\n", msg); - if (h) { - SQLSMALLINT i = 0; - SQLSMALLINT outlen = 0; - char errmsg[1024]; - while ((rc = SQLGetDiagField( - ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS - || rc == SQL_SUCCESS_WITH_INFO) { - fprintf(stderr, "Err#%d: %s\n", i, errmsg); - } - } - if (ret) - exit(ret); - return 0; - } - else if (rc == SQL_SUCCESS_WITH_INFO && h) { - SQLSMALLINT i = 0; - SQLSMALLINT outlen = 0; - char errmsg[1024]; - printf("Success with info for %s:\n", msg); - while ((rc = SQLGetDiagField( - ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS - || rc == SQL_SUCCESS_WITH_INFO) { - fprintf(stderr, "Msg#%d: %s\n", i, errmsg); - } - } - return 1; -} - -void postKspError(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...) { - if (msg > (wchar_t*)65535) - wprintf(L"Provider emitted message: %s\n", msg); - else - wprintf(L"Provider emitted message ID %d\n", msg); -} - -int setKSPLibrary(SQLHSTMT stmt) { - unsigned char CEK[32]; - unsigned char *ECEK; - unsigned short ECEKlen; - unsigned char foundProv = 0; - int i; -#ifdef _WIN32 - HMODULE hProvLib; -#else - void *hProvLib; -#endif - CEKEYSTORECONTEXT ctx = {0}; - CEKEYSTOREPROVIDER **ppKsp, *pKsp; - int(__stdcall *pEncryptCEK)(CEKEYSTORECONTEXT *, errFunc *, unsigned char *, unsigned short, unsigned char **, unsigned short *); - - /* Load the provider library */ -#ifdef _WIN32 - if (!(hProvLib = LoadLibrary("myKSP.dll"))) { -#else - if (!(hProvLib = dlopen("./myKSP.so", RTLD_NOW))) { -#endif - fprintf(stderr, "Error loading KSP library\n"); - return 2; - } -#ifdef _WIN32 - if (!(ppKsp = (CEKEYSTOREPROVIDER**)GetProcAddress(hProvLib, "CEKeystoreProvider"))) { -#else - if (!(ppKsp = (CEKEYSTOREPROVIDER**)dlsym(hProvLib, "CEKeystoreProvider"))) { -#endif - fprintf(stderr, "The export CEKeystoreProvider was not found in the KSP library\n"); - return 3; - } - while (pKsp = *ppKsp++) { - if (!memcmp(KSPNAME, pKsp->Name, sizeof(KSPNAME))) { - foundProv = 1; - break; - } - } - if (! foundProv) { - fprintf(stderr, "Could not find provider in the library\n"); - return 4; - } - - if (pKsp->Init && !pKsp->Init(&ctx, postKspError)) { - fprintf(stderr, "Could not initialize provider\n"); - return 5; - } -#ifdef _WIN32 - if (!(pEncryptCEK = (LPVOID)GetProcAddress(hProvLib, "KeystoreEncrypt"))) { -#else - if (!(pEncryptCEK = dlsym(hProvLib, "KeystoreEncrypt"))) { -#endif - fprintf(stderr, "The export KeystoreEncrypt was not found in the KSP library\n"); - return 6; - } - if (!pKsp->Write) { - fprintf(stderr, "Provider does not support configuration\n"); - return 7; - } - - /* Configure the provider with the key */ - if (!pKsp->Write(&ctx, postKspError, PROV_ENCRYPT_KEY, strlen(PROV_ENCRYPT_KEY))) { - fprintf(stderr, "Error writing to KSP\n"); - return 8; - } - - /* Generate a CEK and encrypt it with the provider */ - srand(time(0) ^ getpid()); - for (i = 0; i < sizeof(CEK); i++) - CEK[i] = rand(); - - if (!pEncryptCEK(&ctx, postKspError, CEK, sizeof(CEK), &ECEK, &ECEKlen)) { - fprintf(stderr, "Error encrypting CEK\n"); - return 9; - } - - /* Create a CMK definition on the server */ - { - static char cmkSql[] = "CREATE COLUMN MASTER KEY CustomCMK WITH (" - "KEY_STORE_PROVIDER_NAME = 'MyCustomKSPName'," - "KEY_PATH = 'TheOneAndOnlyKey')"; - printf("Create CMK: %s\n", cmkSql); - SQLExecDirect(stmt, cmkSql, SQL_NTS); - } - - /* Create a CEK definition on the server */ - { - const char cekSqlBefore[] = "CREATE COLUMN ENCRYPTION KEY CustomCEK WITH VALUES (" - "COLUMN_MASTER_KEY = CustomCMK," - "ALGORITHM = 'none'," - "ENCRYPTED_VALUE = 0x"; - char *cekSql = malloc(sizeof(cekSqlBefore) + 2 * ECEKlen + 2); /* 1 for ')', 1 for null terminator */ - strcpy(cekSql, cekSqlBefore); - for (i = 0; i < ECEKlen; i++) - sprintf(cekSql + sizeof(cekSqlBefore) - 1 + 2 * i, "%02x", ECEK[i]); - strcat(cekSql, ")"); - printf("Create CEK: %s\n", cekSql); - SQLExecDirect(stmt, cekSql, SQL_NTS); - free(cekSql); -#ifdef _WIN32 - LocalFree(ECEK); -#else - free(ECEK); -#endif - } - -#ifdef _WIN32 - FreeLibrary(hProvLib); -#else - dlclose(hProvLib); -#endif - - return 0; -} - -void populateTestTable(SQLHDBC dbc, SQLHSTMT stmt) -{ - SQLRETURN rc; - int i, j; - - /* Create a table with encrypted columns */ - { - static char *tableSql = "CREATE TABLE CustomKSPTestTable (" - "c1 int," - "c2 varchar(255) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256')," - "c3 char(5) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256')," - "c4 date ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'))"; - printf("Create table: %s\n", tableSql); - SQLExecDirect(stmt, tableSql, SQL_NTS); - } - - /* Load provider into the ODBC Driver and configure it */ - { - unsigned char ksd[sizeof(CEKEYSTOREDATA) + sizeof(PROV_ENCRYPT_KEY) - 1]; - CEKEYSTOREDATA *pKsd = (CEKEYSTOREDATA*)ksd; - pKsd->name = L"MyCustomKSPName"; - pKsd->dataSize = sizeof(PROV_ENCRYPT_KEY) - 1; - memcpy(pKsd->data, PROV_ENCRYPT_KEY, sizeof(PROV_ENCRYPT_KEY) - 1); -#ifdef _WIN32 - rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "myKSP.dll", SQL_NTS); -#else - rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "./myKSP.so", SQL_NTS); -#endif - checkRC(rc, "Loading KSP into ODBC Driver", 7, dbc, SQL_HANDLE_DBC); - rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREDATA, (SQLPOINTER)pKsd, SQL_IS_POINTER); - checkRC(rc, "Configuring the KSP", 7, dbc, SQL_HANDLE_DBC); - } - - /* Insert some data */ - { - int c1; - char c2[256]; - char c3[6]; - SQL_DATE_STRUCT date; - SQLLEN cbdate; - rc = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &c1, 0, 0); - checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT); - rc = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, c2, 255, 0); - checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT); - rc = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 5, 0, c3, 5, 0); - checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT); - checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT); - cbdate = sizeof(SQL_DATE_STRUCT); - rc = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, &date, 0, &cbdate); - checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT); - - date.year = 2017; - date.month = 8; - for (i = 0; i < 10; i++) { - date.day = i + 10; - - c1 = i * 10 + i + 1; - sprintf(c2, "Sample data %d for column 2", i); - for (j = 0; j < 3; j++) { - c3[j] = 'a' + i + j; - } - c3[3] = '\0'; - rc = SQLExecDirect(stmt, "INSERT INTO CustomKSPTestTable (c1, c2, c3, c4) values (?, ?, ?, ?)", SQL_NTS); - checkRC(rc, "Inserting rows query", 10, stmt, SQL_HANDLE_STMT); - } - printf("(Encrypted) data has been inserted into CustomKSPTestTable. You may inspect the data now.\n"); - } - -} - -int main(int argc, char **argv) { - char sqlbuf[1024]; - SQLHENV env; - SQLHDBC dbc; - SQLHSTMT stmt; - SQLRETURN rc; - int i; - char connStr[1024]; - enum job task; - - if (argc < 6) { - fprintf(stderr, "usage: kspapp job server database uid pwd\n"); - return 1; - } - - task = atoi(argv[1]); - - sprintf(connStr, "DRIVER={ODBC Driver 17 for SQL Server};SERVER=%s;ColumnEncryption=Enabled;DATABASE=%s;UID=%s;PWD=%s", argv[2], argv[3], argv[4], argv[5]); - - /* Connect to Server */ - rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env); - checkRC(rc, "allocating environment handle", 2, 0, 0); - rc = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); - checkRC(rc, "setting ODBC version to 3.0", 3, env, SQL_HANDLE_ENV); - rc = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); - checkRC(rc, "allocating connection handle", 4, env, SQL_HANDLE_ENV); - rc = SQLDriverConnect(dbc, 0, connStr, strlen(connStr), NULL, 0, NULL, SQL_DRIVER_NOPROMPT); - checkRC(rc, "connecting to data source", 5, dbc, SQL_HANDLE_DBC); - rc = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); - checkRC(rc, "allocating statement handle", 6, dbc, SQL_HANDLE_DBC); - - if (task == set_up) { - printf("Setting up KSP...\n"); - setKSPLibrary(stmt); - populateTestTable(dbc, stmt); - } - else if (task == clean_up) { - printf("Cleaning up KSP...\n"); - - SQLExecDirect(stmt, "DROP TABLE CustomKSPTestTable", SQL_NTS); - SQLExecDirect(stmt, "DROP COLUMN ENCRYPTION KEY CustomCEK", SQL_NTS); - SQLExecDirect(stmt, "DROP COLUMN MASTER KEY CustomCMK", SQL_NTS); - printf("Removed table, CEK, and CMK\n"); - } - - SQLDisconnect(dbc); - SQLFreeHandle(SQL_HANDLE_DBC, dbc); - SQLFreeHandle(SQL_HANDLE_ENV, env); - return 0; -} diff --git a/test/functional/setup/myKSP.c b/test/functional/setup/myKSP.c deleted file mode 100644 index d6188842..00000000 --- a/test/functional/setup/myKSP.c +++ /dev/null @@ -1,132 +0,0 @@ -/****************************************************************************** -Custom Keystore Provider Example - -Windows: compile with cl myKSP.c /LD /MD /link /out:myKSP.dll -Linux/mac: compile with gcc -fshort-wchar -fPIC -o myKSP.so -shared myKSP.c - -******************************************************************************/ - -#ifdef _WIN32 -#include -#else -#define __stdcall -#endif - -#define DEBUG 0 - -#include -#include -#include -#include -#include -#include "msodbcsql.h" - -int wcscmp_short(wchar_t *s1, wchar_t *s2) { - while(*s1 && *s2 && *s1 == *s2) - s1++, s2++; - return *s1 - *s2; -} - -int __stdcall KeystoreInit(CEKEYSTORECONTEXT *ctx, errFunc *onError) { - if (DEBUG) - printf("KSP Init() function called\n"); - return 1; -} - -static unsigned char *g_encryptKey; -static unsigned int g_encryptKeyLen; - -int __stdcall KeystoreWrite(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len) { - if (DEBUG) - printf("KSP Write() function called (%d bytes)\n", len); - if (len) { - if (g_encryptKey) - free(g_encryptKey); - g_encryptKey = malloc(len); - if (!g_encryptKey) { - onError(ctx, L"Memory Allocation Error"); - return 0; - } - memcpy(g_encryptKey, data, len); - g_encryptKeyLen = len; - } - return 1; -} - -// Very simple "encryption" scheme - rotating XOR with the key -int __stdcall KeystoreDecrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const wchar_t *alg, unsigned char *ecek, unsigned short ecekLen, unsigned char **cekOut, unsigned short *cekLen) { - unsigned int i; - if (DEBUG) - printf("KSP Decrypt() function called (keypath=%S alg=%S ecekLen=%u)\n", keyPath, alg, ecekLen); - if (wcscmp_short(keyPath, L"TheOneAndOnlyKey")) { - onError(ctx, L"Invalid key path"); - return 0; - } - if (wcscmp_short(alg, L"none")) { - onError(ctx, L"Invalid algorithm"); - return 0; - } - if (!g_encryptKey) { - onError(ctx, L"Keystore provider not initialized with key"); - return 0; - } -#ifndef _WIN32 - *cekOut = malloc(ecekLen); -#else - *cekOut = LocalAlloc(LMEM_FIXED, ecekLen); -#endif - if (!*cekOut) { - onError(ctx, L"Memory Allocation Error"); - return 0; - } - *cekLen = ecekLen; - for (i = 0; i < ecekLen; i++) - (*cekOut)[i] = ecek[i] ^ g_encryptKey[i % g_encryptKeyLen]; - return 1; -} - -// Note that in the provider interface, this function would be referenced via the CEKEYSTOREPROVIDER -// structure. However, that does not preclude keystore providers from exporting their own functions, -// as illustrated by this example where the encryption is performed via a separate function (with a -// different prototype than the one in the KSP interface.) -#ifdef _WIN32 -__declspec(dllexport) -#endif -int KeystoreEncrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError, - unsigned char *cek, unsigned short cekLen, - unsigned char **ecekOut, unsigned short *ecekLen) { - unsigned int i; - - if (DEBUG) - printf("KSP Encrypt() function called (cekLen=%u)\n", cekLen); - if (!g_encryptKey) { - onError(ctx, L"Keystore provider not initialized with key"); - return 0; - } - *ecekOut = malloc(cekLen); - if (!*ecekOut) { - onError(ctx, L"Memory Allocation Error"); - return 0; - } - *ecekLen = cekLen; - for (i = 0; i < cekLen; i++) - (*ecekOut)[i] = cek[i] ^ g_encryptKey[i % g_encryptKeyLen]; - return 1; -} - -CEKEYSTOREPROVIDER MyCustomKSPName_desc = { - L"MyCustomKSPName", - KeystoreInit, - 0, - KeystoreWrite, - KeystoreDecrypt, - 0 -}; - -#ifdef _WIN32 -__declspec(dllexport) -#endif -CEKEYSTOREPROVIDER *CEKeystoreProvider[] = { - &MyCustomKSPName_desc, - 0 -}; \ No newline at end of file diff --git a/test/functional/setup/run_ksp.py b/test/functional/setup/run_ksp.py deleted file mode 100644 index 0d0ff897..00000000 --- a/test/functional/setup/run_ksp.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/python3 -######################################################################################### -# -# Description: This script assumes the existence of the ksp_app executable and will -# invoke it to create / remove the Column Master Key, the Column Encryption key, -# and the table [CustomKSPTestTable] in the test database. -# -# Requirement: -# python 3.x -# ksp_app executable -# -# Execution: Run with command line with required options -# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd -# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd --REMOVE -# -############################################################################################# - -import sys -import os -import platform -import argparse - -################################### Main Function ################################### -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('-server', '--SERVER', required=True, help='SQL Server') - parser.add_argument('-dbname', '--DBNAME', required=True, help='Name of an existing database') - parser.add_argument('-uid', '--UID', required=True, help='User name') - parser.add_argument('-pwd', '--PWD', required=True, help='User password') - parser.add_argument('-remove', '--REMOVE', action='store_true', help='Clean up KSP related data, false by default') - - args = parser.parse_args() - - app_name = 'ksp_app' - cwd = os.getcwd() - - # first check if the ksp app is present - work_dir = os.path.dirname(os.path.realpath(__file__)) - os.chdir(work_dir) - - if platform.system() == 'Windows': - path = os.path.join(work_dir, app_name + '.exe') - executable = app_name - else: - path = os.path.join(work_dir, app_name) - executable = './' + app_name - - if not os.path.exists(path): - print('Error: {0} not found!'.format(path)) - exit(1) - - if args.REMOVE: - os.system('{0} 1 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD)) - else: - os.system('{0} 0 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD)) - - os.chdir(cwd)