Fix crashes

Fix incorrect LDAP attributes
Fix local backdoor
Fix build warnings
Allow configured groups to become machine local administrators
Fix workstation unlock
master
Timothy Pearson 11 years ago
parent 6610cd15cf
commit 89682db9a2

@ -122,31 +122,37 @@ CLDAP::CLDAP( const std::list<mystring>& servers, FILE *fp, const mystring& bind
lp = ldap_init( (const PWCHAR) ptr->c_str(), LDAP_PORT);
ULONG version = LDAP_VERSION3;
if (!lp) {
fprintf( fp, "ldap_init error on server %S\n", ptr->c_str());
if (fp) {
fprintf( fp, "ldap_init error on server %S\n", ptr->c_str());
}
continue;
}
int ret = ldap_set_option( lp, LDAP_OPT_VERSION, &version);
if (ret != LDAP_SUCCESS) {
fprintf( fp, "ldap_set_option error %x on server %S\n", ret, ptr->c_str());
ldap_unbind( lp);
continue;
if (fp) {
fprintf( fp, "ldap_set_option error %x on server %S\n", ret, ptr->c_str());
}
ldap_unbind( lp);
continue;
}
if (binddn == L"" || bindpasswd == L"") {
ret = ldap_simple_bind_s( lp, NULL, NULL);
if (LDAP_SUCCESS != ret) {
if (fp)
if (fp) {
fprintf( fp, "anonymous ldap_simple_bind_s error %x on server %S\n", ret, ptr->c_str());
}
ldap_unbind( lp);
lp = NULL;
}
} else {
ret = ldap_simple_bind_s( lp, (PWCHAR) binddn.c_str(), (PWCHAR) bindpasswd.c_str());
if (LDAP_SUCCESS != ret) {
if (fp)
if (fp) {
fprintf( fp, "ldap_simple_bind_s error %x on server %S, basedn %S, passwd %S\n",
ret, ptr->c_str(), binddn.c_str(), bindpasswd.c_str());
}
ldap_unbind( lp);
lp = NULL;
}

@ -1,159 +1,181 @@
/*
$Id: manageUser.cpp,v 1.1.1.1 2005/07/07 15:05:59 oflebbe Exp $
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include "ldapuser.h"
#include "netusergroup.h"
#include "utility.h"
#include "manageUser.h"
#include "reg.h"
#define SCAPKEY L"Software\\science + computing\\scap"
void
manageLocalAccount( const mystring& userName, FILE *fp) {
Registry reg( SCAPKEY);
// get LDAP Servers
std::list<mystring> ldapservers = reg.getValues( L"servers");
if (ldapservers.size() == 0) {
if (fp)
fprintf( fp, "ldapservers empty: Please set REG_MULTI_SZ value in HKLM\\%S\\servers", SCAPKEY);
return;
}
mystring binddn = reg.getValue( L"binddn");
mystring bindpasswd = reg.getValue( L"bindpasswd");
// make bind
LDAPUser ld( ldapservers, fp, binddn, bindpasswd);
mystring basedn = reg.getValue( L"basedn");
if (basedn == L"") {
if (fp)
fprintf( fp, "basedn empty: Please set REG_SZ in HKLM\\%S\\basedn", SCAPKEY);
return;
}
ld.setContext( basedn);
stringSet userAttrs;
#define SAMBAHOMEPATH L"sambaHomePath"
#define HOMEDIRECTORY L"homeDirectory"
#define SAMBAHOMEDRIVE L"sambaHomeDrive"
#define SAMBAPROFILEPATH L"sambaProfilePath"
#define SAMBALOGONSCRIPT L"sambaLogonScript"
userAttrs.insert( SAMBAHOMEPATH);
userAttrs.insert( HOMEDIRECTORY);
userAttrs.insert( SAMBAHOMEDRIVE);
userAttrs.insert( SAMBAPROFILEPATH );
userAttrs.insert( SAMBALOGONSCRIPT);
userAttrs.insert( L"gidNumber");
stringMap userVals = ld.getAttribsByUserName( userName, userAttrs);
if (userVals.size() == 0 || (userVals.find( L"gidNumber") == userVals.end())) {
// nothing found
if (fp) {
fprintf( fp, "user %S not found in LDAP: trying to delete user account\n", userName.c_str());
fflush( fp);
}
fprintf( fp, "isdisabled %d\n", isDisabledUser( userName));
// if local user exists and is disabled: delete!
if (isDisabledUser( userName) == 1)
delUser( userName);
return;
}
if (fp) {
fprintf( fp, "add user %S\n", userName.c_str());
fflush( fp);
}
mystring gid = userVals[ L"gid"];
// homepath
mystring homePath;
if (userVals.find( SAMBAHOMEPATH) != userVals.end()) {
homePath = userVals[ SAMBAHOMEPATH]; // use first Element
} else {
if (userVals.find( HOMEDIRECTORY) != userVals.end()) {
homePath = userVals[ HOMEDIRECTORY];
} else {
homePath = reg.getValue( L"homepath");
}
// search and replace with registry keys
homePath = searchAndReplace( convertSlashes( homePath), L"homepathreplace", reg, fp);
}
// homedrive
mystring homeDrive;
if (userVals.find( SAMBAHOMEDRIVE) != userVals.end()) {
homeDrive = *(userVals[ SAMBAHOMEDRIVE].begin()); // use first Element
} else {
homeDrive = reg.getValue( L"homedrive");
}
// profilePath
mystring profilePath;
if (userVals.find( SAMBAPROFILEPATH) != userVals.end()) {
profilePath = userVals[ SAMBAPROFILEPATH];
} else {
if (homeDrive != L"") {
profilePath= homeDrive + reg.getValue( L"profilepath");
} else {
profilePath = homePath + reg.getValue( L"profilepath");
profilePath = searchAndReplace( profilePath, L"profilereplace", reg, fp);
}
}
//logonscript
mystring logonScript;
if (userVals.find( SAMBALOGONSCRIPT) != userVals.end()) {
logonScript = userVals[ SAMBALOGONSCRIPT];
} else {
logonScript = reg.getValue( L"logonscript");
}
// add user only if it does not exists before.
// Do not clutter Event Log
if (-1 == isDisabledUser( userName))
addUser( userName, homePath, homeDrive, profilePath, logonScript );
stringSet ldapList = ld.getGroupsByUserName( userName, gid);
stringSet ntList = listGroups( userName);
stringSet worker;
std::set_difference( ldapList.begin(), ldapList.end(), ntList.begin(), ntList.end(), std::inserter(worker, worker.begin()));
// worker is now Groups containe not in ntlist but ldapList -> add to user
for (stringSet::const_iterator ptr = worker.begin(); ptr != worker.end(); ptr++) {
fprintf( fp, "add to group %S\n", ptr->c_str());
addUserToGroup( userName, *ptr);
}
std::set_difference( ntList.begin(), ntList.end(), ldapList.begin(), ldapList.end(), std::inserter(worker, worker.begin()));
// worker is now Groups containe not in ntlist but ldapList -> add to user
for (stringSet::const_iterator ptr = worker.begin(); ptr != worker.end(); ptr++) {
fprintf( fp, "remove from group %S\n", ptr->c_str());
delUserFromGroup( userName, *ptr);
}
fflush( fp);
}
/*
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
Copyright (C) 2013 Timothy Pearson, Northern Illinois University
kb9vqf@pearsoncomputing.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include "ldapuser.h"
#include "netusergroup.h"
#include "utility.h"
#include "manageUser.h"
#include "reg.h"
#define SCAPKEY L"Software\\science + computing\\scap"
void
manageLocalAccount( const mystring& userName, const mystring& password, FILE *fp) {
Registry reg( SCAPKEY);
// get LDAP Servers
std::list<mystring> ldapservers = reg.getValues( L"servers");
if (ldapservers.size() == 0) {
if (fp)
fprintf( fp, "ldapservers empty: Please set REG_MULTI_SZ value in HKLM\\%S\\servers", SCAPKEY);
return;
}
mystring binddn = reg.getValue( L"binddn");
mystring bindpasswd = reg.getValue( L"bindpasswd");
// make bind
LDAPUser ld( ldapservers, fp, binddn, bindpasswd);
mystring basedn = reg.getValue( L"basedn");
if (basedn == L"") {
if (fp)
fprintf( fp, "basedn empty: Please set REG_SZ in HKLM\\%S\\basedn", SCAPKEY);
return;
}
ld.setContext( basedn);
stringSet userAttrs;
#define SAMBAHOMEPATH L"sambaHomePath"
#define HOMEDIRECTORY L"homeDirectory"
#define SAMBAHOMEDRIVE L"sambaHomeDrive"
#define SAMBAPROFILEPATH L"sambaProfilePath"
#define SAMBALOGONSCRIPT L"sambaLogonScript"
userAttrs.insert( SAMBAHOMEPATH);
userAttrs.insert( HOMEDIRECTORY);
userAttrs.insert( SAMBAHOMEDRIVE);
userAttrs.insert( SAMBAPROFILEPATH );
userAttrs.insert( SAMBALOGONSCRIPT);
userAttrs.insert( L"gidNumber");
stringMap userVals = ld.getAttribsByUserName( userName, userAttrs);
if (userVals.size() == 0 || (userVals.find( L"gidNumber") == userVals.end())) {
// nothing found
if (fp) {
fprintf( fp, "user %S not found in LDAP: trying to delete user account\n", userName.c_str());
fflush( fp);
fprintf( fp, "isdisabled %d\n", isDisabledUser( userName));
}
// if local user exists and is disabled: delete!
if (isDisabledUser( userName) == 1)
delUser( userName);
return;
}
if (fp) {
fprintf( fp, "add user %S\n", userName.c_str());
fflush( fp);
}
mystring gid = userVals[L"gidNumber"];
if (fp) {
fprintf( fp, "primary GID %S\n", gid.c_str());
}
// homepath
mystring homePath;
if (userVals.find( SAMBAHOMEPATH) != userVals.end()) {
homePath = userVals[ SAMBAHOMEPATH]; // use first Element
} else {
if (userVals.find( HOMEDIRECTORY) != userVals.end()) {
homePath = userVals[ HOMEDIRECTORY];
} else {
homePath = reg.getValue(L"homepath");
}
// search and replace with registry keys
homePath = searchAndReplace( convertSlashes( homePath), L"homepathreplace", reg, fp);
}
// homedrive
mystring homeDrive;
if (userVals.find( SAMBAHOMEDRIVE) != userVals.end()) {
homeDrive = *(userVals[ SAMBAHOMEDRIVE].begin()); // use first Element
} else {
homeDrive = reg.getValue(L"homedrive");
}
// profilePath
mystring profilePath;
if (userVals.find( SAMBAPROFILEPATH) != userVals.end()) {
profilePath = userVals[ SAMBAPROFILEPATH];
} else {
if (homeDrive != L"") {
profilePath= homeDrive + reg.getValue(L"profilepath");
} else {
profilePath = homePath + reg.getValue(L"profilepath");
profilePath = searchAndReplace( profilePath, L"profilereplace", reg, fp);
}
}
//logonscript
mystring logonScript;
if (userVals.find( SAMBALOGONSCRIPT) != userVals.end()) {
logonScript = userVals[ SAMBALOGONSCRIPT];
} else {
logonScript = reg.getValue(L"logonscript");
}
// add user only if it does not exists before.
// Do not clutter Event Log
if (-1 == isDisabledUser( userName))
addUser( userName, password, homePath, homeDrive, profilePath, logonScript );
else
modifyUser( userName, password, homePath, homeDrive, profilePath, logonScript );
resetAccountExpiry(userName, password, fp);
stringSet ldapList = ld.getGroupsByUserName(userName, gid);
stringSet ntList = listGroups(userName);
stringSet worker;
std::list<mystring> machineadmingroups = reg.getValues(L"machineadmingroups");
for (std::list<mystring>::const_iterator machineadminptr = machineadmingroups.begin(); machineadminptr != machineadmingroups.end(); machineadminptr++) {
if (ldapList.find(*machineadminptr) != ldapList.end()) {
ldapList.insert(L"Administrators");
}
}
worker.clear();
std::set_difference(ldapList.begin(), ldapList.end(), ntList.begin(), ntList.end(), std::inserter(worker, worker.begin()));
// worker is now Groups contained not in ntlist but ldapList -> add to user
for (stringSet::const_iterator ptr = worker.begin(); ptr != worker.end(); ptr++) {
if (fp) {
fprintf( fp, "add to group %S\n", ptr->c_str());
}
addUserToGroup(userName, *ptr);
}
worker.clear();
std::set_difference( ntList.begin(), ntList.end(), ldapList.begin(), ldapList.end(), std::inserter(worker, worker.begin()));
// worker is now Groups contained not in ntlist but ldapList -> add to user
for (stringSet::const_iterator ptr = worker.begin(); ptr != worker.end(); ptr++) {
if (fp) {
fprintf( fp, "remove from group %S\n", ptr->c_str());
}
delUserFromGroup(userName, *ptr);
}
if (fp) {
fflush(fp);
}
}

@ -28,6 +28,6 @@
#include <stdio.h>
#include "typedefs.h"
void
manageLocalAccount( const mystring& userName, FILE *fp);
manageLocalAccount( const mystring& userName, const mystring& password, FILE *fp);
#endif

@ -1,8 +1,8 @@
/*
$Id: netusergroup.cpp,v 1.1.1.1 2005/07/07 15:05:59 oflebbe Exp $
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
Copyright (C) 2013 Timothy Pearson, Northern Illinois University
kb9vqf@pearsoncomputing.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@
#include <windows.h>
#include <lm.h>
#include <time.h>
#include "netusergroup.h"
int
@ -53,7 +54,7 @@ delUserFromGroup( const mystring& userName, const mystring& groupName) {
int addGroup( const mystring& groupName) {
LOCALGROUP_INFO_0 gent;
gent.lgrpi0_name = wcsdup( groupName.c_str());
gent.lgrpi0_name = _wcsdup( groupName.c_str());
int ret = NetLocalGroupAdd( NULL, 0, (LPBYTE )&gent, NULL);
free( gent.lgrpi0_name);
if (!(ret == NERR_Success || ret == NERR_GroupExists || ret == ERROR_ALIAS_EXISTS)) {
@ -80,13 +81,13 @@ addUser( const mystring& userName) {
return (!(ret == NERR_Success || ret == NERR_UserExists));
}
int addUser( const mystring& userName, const mystring& homepath, const mystring& homedrive,
int addUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
const mystring& profile, const mystring& script) {
USER_INFO_4 ui; /* INFO_3 für 2000? */
memset( &ui, 0, sizeof( ui));
ui.usri4_name = (LPWSTR) userName.c_str();
ui.usri4_password = L"xyzzy";
ui.usri4_password = (LPWSTR) password.c_str();
ui.usri4_priv = USER_PRIV_USER;
ui.usri4_home_dir = (LPWSTR) homepath.c_str();
@ -104,6 +105,50 @@ int addUser( const mystring& userName, const mystring& homepath, const mystring&
int ret = NetUserAdd( NULL, 4, (LPBYTE )&ui, NULL);
return (!(ret == NERR_Success || ret == NERR_UserExists));
}
int modifyUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
const mystring& profile, const mystring& script) {
LPUSER_INFO_4 ui = NULL;
if (NERR_Success == NetUserGetInfo( NULL, userName.c_str(), 4, (LPBYTE *)&ui)) {
ui->usri4_name = (LPWSTR) userName.c_str();
ui->usri4_home_dir = (LPWSTR) homepath.c_str();
ui->usri4_script_path = (LPWSTR) script.c_str();
ui->usri4_profile = (LPWSTR) profile.c_str();
ui->usri4_home_dir_drive = (LPWSTR) homedrive.c_str();
int ret = NetUserSetInfo( NULL, userName.c_str(), 4, (LPBYTE )ui, NULL);
return (!(ret == NERR_Success || ret == NERR_UserExists));
}
else {
return 1;
}
}
int
resetAccountExpiry( const mystring& userName, const mystring& password, FILE *fp) {
if (fp) {
fprintf( fp, "resetting account expiration for user '%S'\n", userName.c_str());
fflush(fp);
}
LPUSER_INFO_4 ui = NULL;
if (NERR_Success == NetUserGetInfo( NULL, userName.c_str(), 4, (LPBYTE *)&ui)) {
ui->usri4_acct_expires = (DWORD)time(0) + 10; /* only allow login for up to 10 seconds after Kerberized authentication */
//ui->usri4_acct_expires = TIMEQ_FOREVER;
ui->usri4_password = (LPWSTR) password.c_str();
ui->usri4_flags = (ui->usri4_flags & (~UF_ACCOUNTDISABLE)); /* ensure account is enabled */
int ret = NetUserSetInfo( NULL, userName.c_str(), 4, (LPBYTE )ui, NULL);
if (fp) {
fprintf( fp, "new time %d: commit returned %d\n", ui->usri4_acct_expires, ret);
fflush(fp);
}
return (!(ret == NERR_Success || ret == NERR_UserExists));
}
else {
return 1;
}
}
// return 1: User exists and disabled
// return 0: User exists and enabled
// return -1: User does not exist

@ -1,56 +1,63 @@
/*
$Id: netusergroup.h,v 1.1.1.1 2005/07/07 15:05:59 oflebbe Exp $
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NETUSERGROUP_H
#define NETUSERGROUP_H
#define WINDOWS_MEAN_AND_LEAN
#define UNICODE
#include <stdio.h>
#include "typedefs.h"
int
addUserToGroup( const mystring& userName, const mystring& groupName);
int
delUserFromGroup( const mystring& userName, const mystring& groupName);
int
addUser( const mystring& userName);
int
addUser( const mystring& userName, const mystring& homepath, const mystring& homedrive,
const mystring& profile, const mystring& script);
int
addGroup( const mystring& userName);
int
delUser( const mystring& userName);
int
isDisabledUser( const mystring& userName);
/*
$Id: netusergroup.h,v 1.1.1.1 2005/07/07 15:05:59 oflebbe Exp $
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NETUSERGROUP_H
#define NETUSERGROUP_H
#define WINDOWS_MEAN_AND_LEAN
#define UNICODE
#include <stdio.h>
#include "typedefs.h"
int
addUserToGroup( const mystring& userName, const mystring& groupName);
int
delUserFromGroup( const mystring& userName, const mystring& groupName);
int
addUser( const mystring& userName);
int
addUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
const mystring& profile, const mystring& script);
int
modifyUser( const mystring& userName, const mystring& password, const mystring& homepath, const mystring& homedrive,
const mystring& profile, const mystring& script);
int
addGroup( const mystring& userName);
int
delUser( const mystring& userName);
int
isDisabledUser( const mystring& userName);
int
resetAccountExpiry( const mystring& userName, const mystring& password, FILE *fp);
stringSet
listUsers();
listUsers();
stringSet
listGroups( const mystring& user);
#endif
listGroups( const mystring& user);
#endif

@ -1,249 +1,398 @@
/*
$Id: sspap3.cpp,v 1.1.1.1 2005/07/07 15:05:59 oflebbe Exp $
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define UNICODE
#define SECURITY_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ntsecapi.h>
#include <sspi.h>
#include <ntsecpkg.h>
#include <stdio.h>
//#include <ntstatus.h>
#include <string.h>
//#include <subauth.h>
#include <malloc.h>
#include <algorithm>
#include <list>
#include "reg.h"
HMODULE msvHandle = 0;
#include "manageUser.h"
extern "C" {
NTSTATUS SEC_ENTRY SpUserModeInitialize(
ULONG LsaVersion,
PULONG PackageVersion,
PSECPKG_USER_FUNCTION_TABLE* ppTables,
PULONG pcTables
) {
if (!msvHandle)
msvHandle = LoadLibrary(L"kerberos.dll");
NTSTATUS status = (*((SpUserModeInitializeFn ) GetProcAddress( msvHandle, "SpUserModeInitialize")))
(LsaVersion, PackageVersion,ppTables, pcTables );
return status;
}
SpInitializeFn *oldSpInitialize = 0;
// SpInitialize is special, it should be both exported
// and be referenced in the SpLsaModeInitialize Call
NTSTATUS SEC_ENTRY SpInitialize(
ULONG_PTR PackageId,
PSECPKG_PARAMETERS Parameters,
PLSA_SECPKG_FUNCTION_TABLE FunctionTable) {
if (oldSpInitialize == 0) {
if (!msvHandle)
msvHandle = LoadLibrary(L"kerberos.dll");
NTSTATUS status = (*((SpInitializeFn *) GetProcAddress( msvHandle, "SpInitialize")))
(PackageId, Parameters,FunctionTable );
return status;
} else {
return (*oldSpInitialize)( PackageId, Parameters,FunctionTable);
}
}
// Todo: Should be wrapped too
NTSTATUS SEC_ENTRY SpInstanceInit(
ULONG Version,
PSECPKG_DLL_FUNCTIONS FunctionTable,
PVOID* UserFunctions
) {
if (!msvHandle)
msvHandle = LoadLibrary(L"kerberos.dll");
NTSTATUS status = (*((SpInstanceInitFn *) GetProcAddress( msvHandle, "SpInstanceInit")))
(Version, FunctionTable, UserFunctions);
return status;
}
PLSA_AP_LOGON_USER_EX2 oldLogonUserEx2 = 0;
NTSTATUS NTAPI
myLogonUserEx2(
PLSA_CLIENT_REQUEST ClientRequest,
SECURITY_LOGON_TYPE LogonType,
PVOID AuthenticationInformation,
PVOID ClientAuthenticationBase,
ULONG AuthenticationInformationLength,
PVOID* ProfileBuffer,
PULONG ProfileBufferLength,
PLUID LogonId,
PNTSTATUS SubStatus,
PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
PVOID* TokenInformation,
PUNICODE_STRING* AccountName,
PUNICODE_STRING* AuthenticatingAuthority,
PUNICODE_STRING* MachineName,
PSECPKG_PRIMARY_CRED PrimaryCredentials,
PSECPKG_SUPPLEMENTAL_CRED_ARRAY* SupplementalCredentials
) {
FILE *fp = fopen("C:\\lsa.txt", "ab");
fprintf( fp, "LogonUserEx2 %d\n", LogonType); //,ClientAuthenticationBase, AuthenticationInformationLength, ClientRequest );
for (unsigned int i = 0; i < AuthenticationInformationLength; i++) {
fprintf( fp, "%02x ", (char) ((char *) AuthenticationInformation)[i]);
}
fprintf( fp, "\n----\n");
// fwrite( AuthenticationInformation, AuthenticationInformationLength, 1, fp);
fflush(fp);
KERB_INTERACTIVE_LOGON *ptr = ((KERB_INTERACTIVE_LOGON *)AuthenticationInformation);
if (LogonType == 2 && ptr->MessageType == KerbInteractiveLogon) {
LPWSTR userName = (LPWSTR) calloc( ptr->UserName.Length + 2, 1);
LPWSTR domain = (LPWSTR) calloc( ptr->LogonDomainName.Length + 2, 1);
if (userName && domain) {
wcsncpy( userName, (wchar_t *) ((char *) ptr + ((char *)ptr->UserName.Buffer - (char *) ClientAuthenticationBase)), ptr->UserName.Length / 2);
wcsncpy( domain, (wchar_t *) ((char *) ptr + ((char *)ptr->LogonDomainName.Buffer - (char *) ClientAuthenticationBase)), ptr->LogonDomainName.Length / 2);
Registry kerbReg( L"System\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Domains");
std::list<mystring> realms = kerbReg.getSubKeys();
mystring strDomain( domain);
// if logon domain is a kerberos realm, create and delete users and groups according to LDAP entries
if ( std::find( realms.begin(), realms.end(), mystring( domain)) != realms.end())
manageLocalAccount( userName, fp);
}
if (userName)
free( userName);
if (domain)
free( domain);
}
fflush(fp);
NTSTATUS status = (*oldLogonUserEx2)
(ClientRequest, LogonType, AuthenticationInformation, ClientAuthenticationBase,
AuthenticationInformationLength, ProfileBuffer, ProfileBufferLength,
LogonId, SubStatus, TokenInformationType, TokenInformation,
AccountName, AuthenticatingAuthority, MachineName, PrimaryCredentials,
SupplementalCredentials);
fprintf( fp, "LogonUserEx2 %x Fertig\n", status);
fclose( fp);
return status;
}
PLSA_AP_CALL_PACKAGE oldCallPackage = 0;
NTSTATUS
myCallPackage(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
) {
FILE *fp = fopen("C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackage\n");
fclose( fp);
NTSTATUS status = (*oldCallPackage)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
return status;
}
PLSA_AP_CALL_PACKAGE_PASSTHROUGH oldCallPackagePassthrough = 0;
NTSTATUS myCallPackagePassthrough(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
)
{
FILE *fp = fopen("C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackagePassThrough\n");
fclose( fp);
return (*oldCallPackagePassthrough)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
}
PLSA_AP_CALL_PACKAGE_PASSTHROUGH oldCallPackageUntrusted = 0;
NTSTATUS myCallPackageUntrusted(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
) {
FILE *fp = fopen("C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackagePassUntrusted\n");
fclose( fp);
return (*oldCallPackageUntrusted)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
}
NTSTATUS NTAPI SpLsaModeInitialize(
ULONG LsaVersion,
PULONG PackageVersion,
PSECPKG_FUNCTION_TABLE* ppTables,
PULONG pcTables
) {
if (!msvHandle)
msvHandle = LoadLibrary(L"kerberos.dll");
NTSTATUS status = (*((SpLsaModeInitializeFn ) GetProcAddress( msvHandle, "SpLsaModeInitialize")))
(LsaVersion, PackageVersion, ppTables, pcTables);
oldLogonUserEx2 = (*ppTables)->LogonUserEx2;
(*ppTables)->LogonUserEx2 = &myLogonUserEx2;
oldCallPackage = (*ppTables)->CallPackage;
(*ppTables)->CallPackage = &myCallPackage;
oldCallPackagePassthrough = (*ppTables)->CallPackagePassthrough;
(*ppTables)->CallPackagePassthrough = &myCallPackagePassthrough;
oldCallPackageUntrusted = (*ppTables)->CallPackageUntrusted;
(*ppTables)->CallPackageUntrusted = &myCallPackageUntrusted;
oldSpInitialize = (*ppTables)->Initialize;
(*ppTables)->Initialize = &SpInitialize;
return status;
}
}
/*
Copyright (C) 2003 Olaf Flebbe, Science and Computing AG
o.flebbe@science-computing.de
Copyright (C) 2013 Timothy Pearson, Northern Illinois University
kb9vqf@pearsoncomputing.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define UNICODE
#define SECURITY_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ntsecapi.h>
#include <sspi.h>
#include <ntsecpkg.h>
#include <stdio.h>
//#include <ntstatus.h>
#include <string.h>
//#include <subauth.h>
#include <malloc.h>
#include <algorithm>
#include <list>
#include "reg.h"
HMODULE msvHandle = 0;
HMODULE kerberosHandle = 0;
#include "manageUser.h"
// #define ENABLE_LSA_LOG 1
// #define ENABLE_DEBUG 1
// There is a typo in <ntsecpkg.h> NTAPI is missing
typedef NTSTATUS
(NTAPI MY_LSA_AP_LOGON_USER_EX2) (
IN PLSA_CLIENT_REQUEST ClientRequest,
IN SECURITY_LOGON_TYPE LogonType,
IN PVOID AuthenticationInformation,
IN PVOID ClientAuthenticationBase,
IN ULONG AuthenticationInformationLength,
OUT PVOID *ProfileBuffer,
OUT PULONG ProfileBufferLength,
OUT PLUID LogonId,
OUT PNTSTATUS SubStatus,
OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
OUT PVOID *TokenInformation,
OUT PUNICODE_STRING *AccountName,
OUT PUNICODE_STRING *AuthenticatingAuthority,
OUT PUNICODE_STRING *MachineName,
OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY * CachedCredentials
);
typedef MY_LSA_AP_LOGON_USER_EX2 *MY_PLSA_AP_LOGON_USER_EX2;
extern "C" {
NTSTATUS SEC_ENTRY SpUserModeInitialize(
ULONG LsaVersion,
PULONG PackageVersion,
PSECPKG_USER_FUNCTION_TABLE* ppTables,
PULONG pcTables
) {
if (!kerberosHandle)
kerberosHandle = LoadLibrary(L"kerberos.dll");
if (!msvHandle)
msvHandle = LoadLibrary(L"msv1_0.dll");
NTSTATUS status = (*((SpUserModeInitializeFn ) GetProcAddress( kerberosHandle, "SpUserModeInitialize")))
(LsaVersion, PackageVersion,ppTables, pcTables );
return status;
}
SpInitializeFn *oldSpInitialize = 0;
// SpInitialize is special, it should be both exported
// and be referenced in the SpLsaModeInitialize Call
NTSTATUS SEC_ENTRY SpInitialize(
ULONG_PTR PackageId,
PSECPKG_PARAMETERS Parameters,
PLSA_SECPKG_FUNCTION_TABLE FunctionTable) {
if (oldSpInitialize == 0) {
if (!kerberosHandle)
kerberosHandle = LoadLibrary(L"kerberos.dll");
if (!msvHandle)
msvHandle = LoadLibrary(L"msv1_0.dll");
NTSTATUS status = (*((SpInitializeFn *) GetProcAddress( kerberosHandle, "SpInitialize")))
(PackageId, Parameters,FunctionTable );
return status;
} else {
return (*oldSpInitialize)( PackageId, Parameters,FunctionTable);
}
}
// Todo: Should be wrapped too
NTSTATUS SEC_ENTRY SpInstanceInit(
ULONG Version,
PSECPKG_DLL_FUNCTIONS FunctionTable,
PVOID* UserFunctions
) {
if (!kerberosHandle)
kerberosHandle = LoadLibrary(L"kerberos.dll");
if (!msvHandle)
msvHandle = LoadLibrary(L"msv1_0.dll");
NTSTATUS status = (*((SpInstanceInitFn *) GetProcAddress( kerberosHandle, "SpInstanceInit")))
(Version, FunctionTable, UserFunctions);
return status;
}
MY_PLSA_AP_LOGON_USER_EX2 oldLogonUserEx2 = 0;
MY_PLSA_AP_LOGON_USER_EX2 oldMSVLogonUserEx2 = 0;
NTSTATUS NTAPI
myLogonUserEx2(
PLSA_CLIENT_REQUEST ClientRequest,
SECURITY_LOGON_TYPE LogonType,
PVOID AuthenticationInformation,
PVOID ClientAuthenticationBase,
ULONG AuthenticationInformationLength,
PVOID* ProfileBuffer,
PULONG ProfileBufferLength,
PLUID LogonId,
PNTSTATUS SubStatus,
PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
PVOID* TokenInformation,
PUNICODE_STRING* AccountName,
PUNICODE_STRING* AuthenticatingAuthority,
PUNICODE_STRING* MachineName,
PSECPKG_PRIMARY_CRED PrimaryCredentials,
PSECPKG_SUPPLEMENTAL_CRED_ARRAY* SupplementalCredentials
) {
#ifdef ENABLE_LSA_LOG
FILE *fp;
fopen_s(&fp, "C:\\lsa.txt", "ab");
#ifdef ENABLE_DEBUG
fprintf( fp, "LogonUserEx2 %d\n", LogonType); //,ClientAuthenticationBase, AuthenticationInformationLength, ClientRequest );
for (unsigned int i = 0; i < AuthenticationInformationLength; i++) {
fprintf( fp, "%02x ", (char) ((char *) AuthenticationInformation)[i]);
}
fprintf( fp, "\n----\n");
fwrite( AuthenticationInformation, AuthenticationInformationLength, 1, fp);
fflush(fp);
#endif // ENABLE_DEBUG
#endif // ENABLE_LSA_LOG
KERB_INTERACTIVE_LOGON *ptr = ((KERB_INTERACTIVE_LOGON *)AuthenticationInformation);
#ifdef ENABLE_LSA_LOG
#ifdef ENABLE_DEBUG
fprintf( fp, "ptr: %p\n", ptr);
fprintf( fp, "LogonType: %d\n", LogonType);
fprintf( fp, "ptr->MessageType: %d\n", ptr->MessageType);
fprintf( fp, "\n----\n");
fflush(fp);
#endif // ENABLE_DEBUG
#endif // ENABLE_LSA_LOG
if ((LogonType == 2) && ((ptr->MessageType == KerbInteractiveLogon) || (ptr->MessageType == KerbWorkstationUnlockLogon))) {
#ifdef ENABLE_LSA_LOG
#ifdef ENABLE_DEBUG
fprintf( fp, "ptr: %p\n", ptr);
fprintf( fp, "\n----\n");
fflush(fp);
fprintf( fp, "UserName.length: %d LogonDomainName.Length: %d\n", ptr->UserName.Length, ptr->LogonDomainName.Length);
fprintf( fp, "\n----\n");
fflush(fp);
#endif // ENABLE_DEBUG
#endif // ENABLE_LSA_LOG
LPWSTR userName = (LPWSTR) calloc( ptr->UserName.Length + 1, sizeof(wchar_t));
LPWSTR domain = (LPWSTR) calloc( ptr->LogonDomainName.Length + 1, sizeof(wchar_t));
LPWSTR password = (LPWSTR) calloc( ptr->Password.Length + 1, sizeof(wchar_t));
if (userName && domain) {
memcpy( userName, (void*)((intptr_t)(ptr) + (intptr_t)(ptr->UserName.Buffer)), ptr->UserName.Length);
memcpy( domain, (void*)((intptr_t)(ptr) + (intptr_t)(ptr->LogonDomainName.Buffer)), ptr->LogonDomainName.Length);
memcpy( password, (void*)((intptr_t)(ptr) + (intptr_t)(ptr->Password.Buffer)), ptr->Password.Length);
userName[ptr->UserName.Length] = L'\0';
domain[ptr->LogonDomainName.Length] = L'\0';
password[ptr->Password.Length] = L'\0';
#ifdef ENABLE_LSA_LOG
fprintf( fp, "userName: '%S'\n", userName);
fprintf( fp, "domain: '%S'\n", domain);
//fprintf( fp, "password: '%S'\n", password);
fflush(fp);
#endif // ENABLE_LSA_LOG
Registry kerbReg( L"System\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Domains");
std::list<mystring> realms = kerbReg.getSubKeys();
mystring strDomain( domain );
// if logon domain is a kerberos realm, create and delete users and groups according to LDAP entries
if ( std::find( realms.begin(), realms.end(), mystring( domain )) != realms.end()) {
#ifdef ENABLE_LSA_LOG
fprintf( fp, "calling manageLocalAccount for user '%S' and domain '%S'\n", userName, domain);
manageLocalAccount( userName, password, fp );
fflush(fp);
#else // ENABLE_LSA_LOG
manageLocalAccount( userName, password, NULL );
#endif // ENABLE_LSA_LOG
}
}
if (userName)
free( userName );
if (password)
free( password );
if (domain)
free( domain );
}
#ifdef ENABLE_LSA_LOG
fflush(fp);
#endif // ENABLE_LSA_LOG
NTSTATUS status = (*oldLogonUserEx2)
(ClientRequest, LogonType, AuthenticationInformation, ClientAuthenticationBase,
AuthenticationInformationLength, ProfileBuffer, ProfileBufferLength,
LogonId, SubStatus, TokenInformationType, TokenInformation,
AccountName, AuthenticatingAuthority, MachineName, PrimaryCredentials,
SupplementalCredentials);
#ifdef ENABLE_LSA_LOG
fprintf( fp, "LogonUserEx2 %x Ready\n", status);
fflush(fp);
#endif // ENABLE_LSA_LOG
/*if (status != 0) {
status = (*oldMSVLogonUserEx2)
(ClientRequest, LogonType, AuthenticationInformation, ClientAuthenticationBase,
AuthenticationInformationLength, ProfileBuffer, ProfileBufferLength,
LogonId, SubStatus, TokenInformationType, TokenInformation,
AccountName, AuthenticatingAuthority, MachineName, PrimaryCredentials,
SupplementalCredentials);
#ifdef ENABLE_LSA_LOG
fprintf( fp, "LogonUserEx2 %x Ready\n", status);
fflush(fp);
#endif // ENABLE_LSA_LOG
}*/
#ifdef ENABLE_LSA_LOG
fclose( fp);
#endif // ENABLE_LSA_LOG
return status;
}
PLSA_AP_CALL_PACKAGE oldCallPackage = 0;
NTSTATUS
myCallPackage(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
) {
#ifdef ENABLE_LSA_LOG
FILE *fp;
fopen_s(&fp, "C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackage\n");
fclose( fp);
#endif // ENABLE_LSA_LOG
NTSTATUS status = (*oldCallPackage)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
return status;
}
PLSA_AP_CALL_PACKAGE_PASSTHROUGH oldCallPackagePassthrough = 0;
NTSTATUS myCallPackagePassthrough(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
)
{
#ifdef ENABLE_LSA_LOG
FILE *fp;
fopen_s(&fp, "C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackagePassThrough\n");
fclose( fp);
#endif // ENABLE_LSA_LOG
return (*oldCallPackagePassthrough)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
}
PLSA_AP_CALL_PACKAGE_PASSTHROUGH oldCallPackageUntrusted = 0;
NTSTATUS myCallPackageUntrusted(
PLSA_CLIENT_REQUEST ClientRequest,
PVOID ProtocolSubmitBuffer,
PVOID ClientBufferBase,
ULONG SubmitBufferLength,
PVOID* ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
) {
#ifdef ENABLE_LSA_LOG
FILE *fp;
fopen_s(&fp, "C:\\lsa.txt", "a");
fprintf( fp, "LsaApCallPackagePassUntrusted\n");
fclose( fp);
#endif // ENABLE_LSA_LOG
return (*oldCallPackageUntrusted)
(ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength,
ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus);
}
NTSTATUS NTAPI SpLsaModeInitialize(
ULONG LsaVersion,
PULONG PackageVersion,
PSECPKG_FUNCTION_TABLE* ppTables,
PULONG pcTables
) {
if (!kerberosHandle)
kerberosHandle = LoadLibrary(L"kerberos.dll");
if (!msvHandle)
msvHandle = LoadLibrary(L"msv1_0.dll");
#ifdef ENABLE_LSA_LOG
#ifdef ENABLE_DEBUG
FILE *fp;
fopen_s(&fp, "C:\\lsa.txt", "a");
fprintf( fp, "SpLsaModeInitialize\n");
fprintf( fp, "kerberosHandle: %p\n", kerberosHandle);
fprintf( fp, "msvHandle: %p\n", msvHandle);
fclose( fp);
#endif // ENABLE_DEBUG
#endif // ENABLE_LSA_LOG
if (kerberosHandle) {
NTSTATUS status;
// Obtain MSV1_0 handle(s)
status = (*((SpLsaModeInitializeFn ) GetProcAddress( msvHandle, "SpLsaModeInitialize")))
(LsaVersion, PackageVersion, ppTables, pcTables);
oldMSVLogonUserEx2 = (MY_PLSA_AP_LOGON_USER_EX2) (*ppTables)->LogonUserEx2;
// Obtain Kerberos handle(s)
status = (*((SpLsaModeInitializeFn ) GetProcAddress( kerberosHandle, "SpLsaModeInitialize")))
(LsaVersion, PackageVersion, ppTables, pcTables);
oldLogonUserEx2 = (MY_PLSA_AP_LOGON_USER_EX2)(*ppTables)->LogonUserEx2;
(*ppTables)->LogonUserEx2 = (PLSA_AP_LOGON_USER_EX2) &myLogonUserEx2;
/*oldCallPackage = (*ppTables)->CallPackage;
(*ppTables)->CallPackage = &myCallPackage;
oldCallPackagePassthrough = (*ppTables)->CallPackagePassthrough;
(*ppTables)->CallPackagePassthrough = &myCallPackagePassthrough;
oldCallPackageUntrusted = (*ppTables)->CallPackageUntrusted;
(*ppTables)->CallPackageUntrusted = &myCallPackageUntrusted;
oldSpInitialize = (*ppTables)->Initialize;
(*ppTables)->Initialize = &SpInitialize;*/
#ifdef ENABLE_LSA_LOG
#ifdef ENABLE_DEBUG
fprintf( fp, "SpLsaModeInitialize %x Ready\n", status);
#endif // ENABLE_DEBUG
#endif // ENABLE_LSA_LOG
return status;
}
else {
return ERROR_INTERNAL_DB_ERROR;
}
}
}

@ -1,21 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sspap3", "sspap3.vcproj", "{EA164A0F-6361-40D6-B356-B6E16EB9FA15}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sspap3", "sspap3.vcxproj", "{EA164A0F-6361-40D6-B356-B6E16EB9FA15}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Debug.ActiveCfg = Debug|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Debug.Build.0 = Debug|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Release.ActiveCfg = Release|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Release.Build.0 = Release|Win32
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Debug|Win32.ActiveCfg = Debug|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Debug|Win32.Build.0 = Debug|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Release|Win32.ActiveCfg = Release|Win32
{EA164A0F-6361-40D6-B356-B6E16EB9FA15}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

@ -50,7 +50,9 @@ mystring searchAndReplace( const mystring& inputString, const mystring& registry
while (reg.exists( registryKey + itos( i))) {
stringList searchReplace = reg.getValues( registryKey + itos( i));
if (searchReplace.size() != 2) {
fprintf( fp, "registry key prependpath %d invalid\n", i);
if (fp) {
fprintf( fp, "registry key prependpath %d invalid\n", i);
}
continue;
}
mystring searchString = searchReplace.front();

Loading…
Cancel
Save