Main Page | Class List | File List | Class Members | File Members

ldapauth_plus.cpp

Go to the documentation of this file.
00001 
00006 
00007 
00033 /*
00034 TODO (in no particular order):
00035 - SASL
00036 - LDAP v3: believed to be done, but not tested
00037 - ldap tests by attributes (for group membership testing)
00038 */
00039 
00040 #include "stdafx.h"
00041 #include "ctype.h"
00042 #include "ldapauth_plus.h"
00043 #include "ConfigureDialog.h"
00044 #include ".\ldapauth_plus.h"
00045 
00046 #ifdef _DEBUG
00047 #define new DEBUG_NEW
00048 #endif
00049 //                      AFX_MANAGE_STATE(AfxGetStaticModuleState());
00050 
00051 #ifdef _DEBUG
00052 // Log a debug string to a file in the c:\ root
00053 void debugOut(WCHAR *string,...)
00054 {
00055         WCHAR filename[256];
00056         int number = 0;
00057         va_list argList;
00058         time_t ltime;
00059         FILE *debugFile = NULL;                       
00060         WCHAR strForConcat[512] = {L"pgina.ldapauth->trace: "};
00061 
00062         time(&ltime);
00063 
00064         if(debugFile == NULL)
00065         {
00066                 number = (int) time(NULL);
00067                 swprintf(filename,L"c:\\pgina_debug%d.txt",number);
00068                 debugFile = _wfopen(filename,L"a+");
00069         }
00070 
00071         va_start(argList,string);
00072         fwprintf(debugFile,L"@%.*s: ",24,ctime(&ltime));
00073         vfwprintf(debugFile,string,argList);
00074         fwprintf(debugFile,L"\n");
00075         fflush(debugFile);
00076         wcscat(strForConcat,string);
00077         wcscat(strForConcat,L"\n");
00078         OutputDebugString(strForConcat);
00079 }
00080 #endif
00081 
00082 // Enter a message into the event viewer
00083 void plugError(LPCWSTR * errorStr, LPVOID rawData, DWORD eventID)
00084 {
00085 // function to record errors to the system event log
00086         HANDLE logH;
00087         DWORD rawSize;
00088 
00089         //logH = OpenEventLog(NULL, L"ldapAuth"); // open handle to event log
00090         logH = RegisterEventSource(NULL, L"ldapAuth");
00091         if (logH == NULL)
00092                 return;
00093 
00094         rawSize = sizeof(rawData);
00095 
00096         ReportEvent(
00097                                 logH, // previous handle
00098                                 EVENTLOG_ERROR_TYPE, //it's an error (not a warning)
00099                                 0, // something about the category in the message file
00100                                 eventID, // something about the event in the message file
00101                                 NULL, // we don't need the user's security id
00102                                 1, // number of strings we'll pass -- we only want the one
00103                                 rawSize, // bytes of raw data to put in the log
00104                                 errorStr, //the error string
00105                                 rawData); // raw data == error
00106 
00107         DeregisterEventSource(logH);
00108 }
00109 
00110 LONG regLookup(WCHAR * lookee, WCHAR * value)
00111 {
00112         // regLookup handles querying the registry for values. lookee is the registry key and value is the value of that key.
00113         // Registry context is assumed.
00114         // Yes, this function treats everything as text, so numeric values must be text. Blood pain to put all this code
00115         // all over one's source, so it needs a friend
00116         LONG lResult;
00117         HKEY hKey;
00118         WCHAR valuetoGet[2048];
00119         DWORD dwValue = 2048;
00120 
00121         lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SOFTWARE\\pGina\\ldapauth"),
00122                                                    0,
00123                                                    KEY_QUERY_VALUE,
00124                                                    &hKey);
00125 
00126         if(lResult == ERROR_SUCCESS)
00127         {
00128                 lResult = RegQueryValueEx(      hKey,
00129                                                                         lookee,
00130                                                                         NULL,
00131                                                                         NULL,
00132                                                                         (LPBYTE) &valuetoGet,
00133                                                                         &dwValue);
00134                 if (lResult == ERROR_SUCCESS)
00135                         wcscpy(value, valuetoGet);  // put the _tcscpy in the if statement, Micah you idiot
00136         }
00137     RegCloseKey(hKey);
00138 
00139         return lResult;
00140 }
00141 
00142 bool regSet(WCHAR * settee, WCHAR * value)
00143 {
00144         long lResult;
00145         HKEY hKey;
00146 
00147         lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
00148                                                          TEXT("SOFTWARE\\pGina\\ldapauth"),
00149                                                          0,
00150                                                          NULL,
00151                                                          REG_OPTION_NON_VOLATILE,
00152                                                          KEY_ALL_ACCESS,
00153                                                          NULL,   // This field can be used to set Security..?
00154                                                          &hKey,
00155                                                          NULL);  // This value can be used to determine if the key existed or not..
00156                                                                          //  but we dont care as long as it opens.. i guess.
00157 
00158         if(lResult == ERROR_SUCCESS)
00159         {
00160                 lResult = RegSetValueEx(hKey,settee,0,REG_SZ,
00161                                                                 (CONST BYTE *) value,
00162                                                                 sizeof(value));
00163         }
00164 
00165         if (lResult == ERROR_SUCCESS)
00166                 return true;
00167         else return false;
00168 
00169 }
00170 
00171 bool ldapDoBindTest(LPTSTR dn, LPTSTR Password, LPTSTR ldapServer, LDAP *gloLdapStruct)
00172 {
00173         // function that actually does the work -- I found that I was calling this same code several places, so I've consolidated
00174         // we accept ldapServer so that multimap only looks it up once instead of every time -- a little optimization ;)
00175         ULONG ldapStat;
00176         WCHAR useSSL[256];
00177 
00178         // Check valid LDAP structure given
00179         if (gloLdapStruct == NULL)
00180                 return false;
00181 
00182         if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL)==1))
00183                 ldapStat = ldap_bind_s(gloLdapStruct, dn, Password, 128);
00184         else
00185                 ldapStat = ldap_simple_bind_s(gloLdapStruct, dn, Password); // We use _s to that it will be synchronous & we can find out NOW
00186 
00187         if (ldapStat == LDAP_SUCCESS)
00188                 return (true);
00189         else {
00190 #ifdef _DEBUG
00191                 WCHAR debug[256];
00192                 swprintf(debug, L"LDAP bind failed with error: 0x%x.", ldapStat);
00193                 debugOut(debug);
00194 #endif
00195                 return (false);
00196         }
00197 }
00198 
00199 bool ldapTestMap(LPTSTR Username, LPTSTR Password, WCHAR * ldapServer, WCHAR * ldpContext, LDAP *gloLdapStruct, WCHAR * dn)
00200 {
00201         // the original ldap auth method -- and still the simplest!
00202         WCHAR ldapPrePend[256];
00203         WCHAR ldapAppend[256];
00204 
00205         // get some variables from the registry for added fun
00206         if (ERROR_SUCCESS != regLookup(L"ldapPrePend", ldapPrePend))
00207                 return false;
00208         if (ERROR_SUCCESS != regLookup(L"ldapAppend", ldapAppend)) {
00209                 if (ERROR_SUCCESS != regLookup(L"ldapContext0", ldapAppend)) // you can set ldapAppend or ldapContext0
00210             return false;
00211         }
00212 
00213         // construct our dn string of cn=Username,ou=users,o=mu
00214         wcscpy(dn, ldapPrePend);
00215         wcscat(dn, Username);
00216         wcscat(dn, L",");
00217         wcscat(dn, ldapAppend);
00218 
00219         // copy our ldapAppend into ldapContext
00220         wcscpy(ldpContext, ldapAppend);
00221 
00222         return ldapDoBindTest(dn, Password, ldapServer, gloLdapStruct);
00223 }
00224 
00225 bool ldapMapGo(LPTSTR Username, LPTSTR Password, LPTSTR ldapPrePend, LPTSTR ldapServer, LPTSTR ldapContext, LDAP * gloLdapStruct, WCHAR * dn)
00226 {
00227         // This function no longer does anything more exciting that ldapBindTest() and should be removed
00228         LPCWSTR myError = _wcsdup(L"ldapMapGo failed");
00229 
00230         // construct our dn string of cn=Username,ou=users,o=mu
00231         wcscpy(dn, ldapPrePend);
00232         wcscat(dn, Username);
00233         wcscat(dn, L",");
00234         wcscat(dn, ldapContext);
00235 
00236 #ifdef _DEBUG
00237         WCHAR debug[256];
00238         swprintf(debug, L"full username is %s.", dn);
00239         debugOut(debug);
00240         debugOut(L"Calling ldapDoBindTest");
00241 #endif
00242 
00243         return ldapDoBindTest(dn, Password, ldapServer, gloLdapStruct);
00244 
00245 }
00246 
00247 WCHAR * getContext(WCHAR * DN)
00248 {
00249         UINT i = 0;
00250         WCHAR * pdest;
00251 
00252 //  wcschr returns the position of the first comma in the string
00253         pdest = wcschr(DN, ',');
00254 //  We then need to increment that because we want what comes AFTER the comma
00255         pdest++;
00256 
00257 #ifdef DEBUG
00258         WCHAR debug[256];
00259         swprintf(debug, L"Context determined to be: %s", pdest);
00260         debugOut(debug);
00261 #endif
00262         return pdest;
00263 }
00264 
00265 bool ldapSearchForDN(LPTSTR Username, WCHAR * DN, WCHAR * ldpContext, LDAP *gloLdapStruct)
00266 {
00267         /* vars needed */
00268         ULONG ldapStat;
00269         int ldapVer = LDAP_VERSION3;
00270         WCHAR ldapFilter[256];
00271         WCHAR ldapFilterOrig[128];
00272         WCHAR ldapContext1[256];
00273         WCHAR ldapAdminUsername[256];
00274         WCHAR ldapAdminPassword[256];
00275 
00276         LDAPMessage* pMsg;
00277         LDAPMessage* ldapFirstEntry;
00278         WCHAR * userDN;
00279         WCHAR useSSL[128];
00280         WCHAR * localLdapContext;
00281 
00282         LPCWSTR myError = L"The data is the return code.";
00283 
00284         if (regLookup(L"ldapContext0", ldapContext1) != ERROR_SUCCESS)
00285                 return false;
00286         if (regLookup(L"ldapAdminUsername", ldapAdminUsername) != ERROR_SUCCESS)
00287                 *ldapAdminUsername = NULL;
00288         if (regLookup(L"ldapAdminPassword", ldapAdminPassword) != ERROR_SUCCESS)
00289                 *ldapAdminPassword = NULL;
00290 
00291         // let's set our ldap options
00292         //ldap_set_option(myLdapStruct, LDAP_OPT_DEREF, LDAP_DEREF_NEVER); // never dereference aliases
00293         ldap_set_option(gloLdapStruct, LDAP_OPT_VERSION, &ldapVer); // be picky -- insist on the best
00294 
00295         // construct filter -- consult the registry for ldapFilter key. If populated, attempt to use it. 
00296         // Otherwise, assume a filter (that works at Miami, at least) of uid=%s
00297         // Filters should be something like (&(objectClass=person)(cn=%s)) -- the %s will be needed b/c this string
00298         // is passed into an sprintf and the %s is changed to the user's name; hopefully this works in the registry
00299         // but on the safe side, reg_expand_string should NOT be used!
00300         if (regLookup(L"ldapFilter", ldapFilterOrig) != ERROR_SUCCESS)
00301                 wcscpy(ldapFilterOrig, L"(uid=%s)");
00302     
00303         swprintf(ldapFilter, ldapFilterOrig, Username);
00304 
00305         //simple bind passes password in plain text
00306         if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL) == 1))
00307                 ldapStat = ldap_bind_s(gloLdapStruct, ldapAdminUsername, ldapAdminPassword, 128);
00308         else
00309                 ldapStat = ldap_simple_bind_s(gloLdapStruct, ldapAdminUsername, ldapAdminPassword); // We use _s to that it will be synchronous & we can find out NOW
00310 
00311         if (ldapStat != LDAP_SUCCESS)
00312         {
00313                 //printf(TEXT("ldap_simple_bind_s failed with error: 0x%x\n"), ldapStat);
00314                 return false;
00315         }
00316 
00317         // perform a synchronous search using previously built filter and put results in pMsg
00318         //ldapStat = ldap_search_s(myLdapStruct, ldapContext1, LDAP_SCOPE_SUBTREE, ldapFilter, ldapAttrs, 0, &pMsg);
00319         ldapStat = ldap_search_ext_s(gloLdapStruct, ldapContext1, LDAP_SCOPE_SUBTREE, ldapFilter, NULL, 0, NULL, NULL, NULL, 0, &pMsg);
00320         if (ldapStat != LDAP_SUCCESS)
00321         {
00322                 wprintf(L"ldap_search_s failed with error: 0x%x\n", ldapStat);
00323                 return false;
00324         }
00325 
00326         // Get the first entry returned in pMsg
00327     ldapFirstEntry = ldap_first_entry(gloLdapStruct, pMsg);
00328         if (ldapFirstEntry == NULL)
00329         {
00330                 wprintf(L"ldap_first_entry failed with error: 0x%x\n", ldapStat);
00331                 return false;
00332         }
00333         // Get the dn of the first entry returned in pMsg -- why didn't anyone tell me it was this simple????
00334         userDN = ldap_get_dn(gloLdapStruct, pMsg);
00335         if (userDN == NULL)
00336                 return false;
00337 
00338         wcscpy(DN, userDN);
00339 
00340         ldap_memfree(userDN);
00341     ldap_msgfree(pMsg);
00342 
00343         // we have the dn, but let's explode it so that we're sure it matches the other
00344         //explodedDN = ldap_explode_dn(DN, false);
00345         // now take this value and search for the first "," indicating cn=uniqueID,ou=users,o=mu 
00346         // hopefully wcstok will strip off the first comma and everything before it, leaving us only the context
00347         //ldpContext = wcstok(DN,L",");
00348         localLdapContext = getContext(DN);
00349         // clean up our exploded DN value
00350         //ldap_value_free(explodedDN);
00351 
00352         wcscpy(ldpContext, localLdapContext);
00353 
00354         return true;
00355 }
00356 
00357 bool ldapTestMultiMap(LPTSTR Username, LPTSTR Password, WCHAR * ldapServer, WCHAR * ldpContext, LDAP * gloLdapStruct, WCHAR * dn)
00358 {
00359         // The premise of this function is to loop through registry entries with ldap contexts.
00360         // We do this by creating a text string ldapContextx where x is 0-2^LONG. When the registry lookup
00361         // for a given ldapContextx fails, we believe we've reached the end and we terminate the loop.
00362 
00363         WCHAR ldapPrePend[256];
00364         WCHAR ldapContext[256];
00365 #ifdef _DEBUG
00366         WCHAR debug[256];
00367 #endif
00368 
00369         WCHAR ldapContextChooser[256] = L"ldapContext0";
00370         WCHAR temp[10];
00371         LPCWSTR myError = L"ldapTestMultiMap failed";
00372 
00373         // lookup our server and prepend (cn=) stuff from registry
00374         if (ERROR_SUCCESS != regLookup(L"ldapPrePend", ldapPrePend)) //error checking
00375         {
00376 #ifdef _DEBUG
00377                 debugOut(L"ldapPrePend not filled out");
00378 #endif
00379                 return false;
00380         }
00381         if (ERROR_SUCCESS != regLookup(L"ldapContext0", ldapContext)) //safety check -- if we don't have the first context filled in, just return
00382         {
00383 #ifdef _DEBUG
00384                 debugOut(L"ldapContext0 not filled out");
00385 #endif
00386                 plugError(&myError, NULL, LDAPREGFAIL);
00387                 return false;
00388         }
00389 
00390         for(LONG i = 0; i < 255; i++)
00391         {
00392 #ifdef _DEBUG
00393                 swprintf(debug, L"Starting testMultiMap run %i...", i);
00394                 debugOut(debug);
00395 #endif
00396                 wcscpy(ldapContextChooser, L"ldapContext");
00397                 _itow(i, temp, 10);
00398                 wcscat(ldapContextChooser, temp);
00399                 if (regLookup(ldapContextChooser, ldapContext) == ERROR_SUCCESS)
00400                 {
00401                         if (ldapMapGo(Username, Password, ldapPrePend, ldapServer, ldapContext, gloLdapStruct, dn))
00402                         {
00403                                 wcscpy(ldpContext, ldapContext);
00404 #ifdef _DEBUG
00405                                 wsprintf(debug,L"ldapMapGo found user %s at context %s",Username,ldapContext);
00406                                 debugOut(debug);
00407 #endif
00408                                 return true;
00409                         }
00410 #ifdef _DEBUG
00411                         else
00412                         {
00413                                 swprintf(debug, TEXT("ldapMapGo failed with Username: %s,  ldapPrePend: %s, ldapServer: %s, ldapContext: %s"), Username, ldapPrePend, ldapServer, ldapContext);
00414                                 debugOut(debug);
00415                         }
00416 #endif
00417                 }
00418                 else break;
00419         }
00420         return false;
00421 }
00422 
00423 bool ldapTestSearch(LPTSTR Username, LPTSTR Password, WCHAR * ldpContext, LDAP *gloLdapStruct, WCHAR * dn)
00424 {
00425         // vars needed
00426         ULONG ldapStat;
00427         int ldapVer = LDAP_VERSION3;
00428 
00429         WCHAR ldapServer[256];
00430         WCHAR ldapContext1[256];
00431         WCHAR useSSL[128];
00432 
00433         LPCWSTR myError = TEXT("The data is the return code.");
00434 
00435         if (regLookup(L"ldapServer", ldapServer) != ERROR_SUCCESS)
00436                 return false;
00437         if (regLookup(L"ldapContext0", ldapContext1) != ERROR_SUCCESS)
00438                 return false;
00439 
00440         if(!ldapSearchForDN(Username, dn, ldpContext, gloLdapStruct))
00441                 return false;
00442 
00443         ldap_set_option(gloLdapStruct, LDAP_OPT_VERSION, &ldapVer); // be picky -- insist on the best
00444 
00445         if ((regLookup(TEXT("useSSL"), useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL)==1))
00446                 ldapStat = ldap_bind_s(gloLdapStruct, dn, Password, 128);
00447         else
00448                 ldapStat = ldap_simple_bind_s(gloLdapStruct, dn, Password); // We use _s to that it will be synchronous & we can find out NOW
00449 
00450         if (ldapStat == LDAP_SUCCESS)
00451                 return (true);
00452         else
00453                 return (false);
00454 }
00455 
00456 DWORD determineLdap(void) // do we wish to use mapping or searching?
00457 {
00458         WCHAR strDapMethod[2048];
00459 
00460         if (ERROR_SUCCESS == regLookup(TEXT("ldapMethod"), strDapMethod))
00461                 return (DWORD) _wtoi(strDapMethod);
00462         else return -1;
00463 }
00464 
00466 
00469 void doLdapSearch(WCHAR ldapFilter[256])
00470 {
00471         /* vars needed */
00472         ULONG ldapStat;
00473         int ldapVer = LDAP_VERSION3;
00474         WCHAR ldapContext[256];
00475         WCHAR ldapAdminUsername[256];
00476         WCHAR ldapAdminPassword[256];
00477 
00478         LDAPMessage* pMsg;
00479         LDAPMessage* ldapFirstEntry;
00480         WCHAR * userDN;
00481         WCHAR useSSL[128];
00482         WCHAR * localLdapContext;
00483 
00484         LPCWSTR myError = L"The data is the return code.";
00485 
00486         if (regLookup(L"ldapContext0", ldapContext) != ERROR_SUCCESS)
00487                 return false;
00488         if (regLookup(L"ldapAdminUsername", ldapAdminUsername) != ERROR_SUCCESS)
00489                 *ldapAdminUsername = NULL;
00490         if (regLookup(L"ldapAdminPassword", ldapAdminPassword) != ERROR_SUCCESS)
00491                 *ldapAdminPassword = NULL;
00492 
00493         // let's set our ldap options
00494         ldap_set_option(gloLdapStruct, LDAP_OPT_VERSION, &ldapVer); // be picky -- insist on the best 
00495         
00496         // standard bind calls
00497         // We use _s to that it will be synchronous & we can find out NOW
00498         if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL) == 1))
00499                 ldapStat = ldap_bind_s(gloLdapStruct, ldapAdminUsername, ldapAdminPassword, 128);
00500         else    //simple bind passes password in plain text
00501                 ldapStat = ldap_simple_bind_s(gloLdapStruct, ldapAdminUsername, ldapAdminPassword); 
00502 
00503         if (ldapStat != LDAP_SUCCESS)
00504         {
00505                 //printf(TEXT("ldap_simple_bind_s failed with error: 0x%x\n"), ldapStat);
00506                 return false;
00507         }
00508 
00509         // perform a synchronous search using previously built filter and put results in pMsg
00510         //ldapStat = ldap_search_s(myLdapStruct, ldapContext1, LDAP_SCOPE_SUBTREE, ldapFilter, ldapAttrs, 0, &pMsg);
00511         ldapStat = ldap_search_ext_s(gloLdapStruct, ldapContext1, LDAP_SCOPE_SUBTREE, ldapFilter, NULL, 0, NULL, NULL, NULL, 0, &pMsg);
00512         if (ldapStat != LDAP_SUCCESS)
00513         {
00514                 wprintf(L"ldap_search_s failed with error: 0x%x\n", ldapStat);
00515                 return false;
00516         }
00517 
00518         // Get the first entry returned in pMsg
00519     ldapFirstEntry = ldap_first_entry(gloLdapStruct, pMsg);
00520         if (ldapFirstEntry == NULL)
00521         {
00522                 wprintf(L"ldap_first_entry failed with error: 0x%x\n", ldapStat);
00523                 return false;
00524         }
00525 
00526 
00527         ldap_memfree(userDN);
00528     ldap_msgfree(pMsg);
00529 
00530         // we have the dn, but let's explode it so that we're sure it matches the other
00531         //explodedDN = ldap_explode_dn(DN, false);
00532         // now take this value and search for the first "," indicating cn=uniqueID,ou=users,o=mu 
00533         // hopefully wcstok will strip off the first comma and everything before it, leaving us only the context
00534         //ldpContext = wcstok(DN,L",");
00535         localLdapContext = getContext(DN);
00536         // clean up our exploded DN value
00537         //ldap_value_free(explodedDN);
00538 
00539         wcscpy(ldpContext, localLdapContext);
00540 }       
00541 
00542 
00543 
00544 bool ldapGroupCheck(WCHAR * username, WCHAR * group, LDAP *gloLdapStruct,WCHAR * ldpContext)
00545 {
00546         // function to determine if user is a member of the specified group
00547         //takes in name of group: returns true or false
00548         PWCHAR * groupMembership;
00549         WCHAR groupMembershipAttr[256];
00550         UINT i = 0;
00551         bool member = false;
00552 #ifdef _DEBUG
00553         WCHAR debug[256];
00554 #endif
00555 
00556 #ifdef _DEBUG
00557         wsprintf(debug,L"ldapGroupCheck->Group name passed in: %s",group);
00558         debugOut(debug);
00559 #endif
00560         // Determine what attribute contains what I call groupMembership
00561         // needed for inferior schemas ;)
00562         if (regLookup(L"ldapGroupAttr", groupMembershipAttr) != ERROR_SUCCESS)
00563                 wcscpy(groupMembershipAttr, L"groupMembership");
00564 
00565         // loop through all values of the groupMembership attribute and compare with passed in groupname
00566         // if we match, set member to true, else loop again
00567         groupMembership = ldapSearchAttr(username, groupMembershipAttr, gloLdapStruct, ldpContext, false);
00568         if (groupMembership == NULL)
00569         {
00570 #ifdef _DEBUG
00571                 debugOut(L"NULL groupMembership");
00572 #endif
00573                 return false;
00574         }
00575 
00576         while (groupMembership[i])
00577         {
00578 #ifdef _DEBUG
00579                 wsprintf(debug,L"Group Member %i: %s",i,groupMembership[i]);
00580                 debugOut(debug);
00581 #endif
00582                 if (_wcsicmp(group, groupMembership[i]) == 0)
00583                 {
00584                         member = true;
00585 #ifdef _DEBUG
00586                         debugOut(TEXT("ldapGroupCheck: will be returning true"));
00587 #endif
00588                         break;
00589                 }
00590                 else i++;
00591         }
00592         ldap_value_free(groupMembership);
00593         return member;
00594 }
00595 
00596 bool okToLogin(WCHAR * username, LDAP *gloLdapStruct, WCHAR * ldpContext)
00597 {
00598         // allows locking workstation to specified users
00599         // if values are empty, allows everyone to log in
00600         // otherwise, allows only those with group set
00601         WCHAR testGroup[256];
00602         WCHAR groupRegEntry[256];
00603         WCHAR temp[16];
00604         UINT i = 0;
00605 
00606         if (ERROR_SUCCESS != regLookup(TEXT("userOK0"), testGroup)) // failsafe: if the registry key isn't filled in, let the user in
00607                 return true;
00608         else if (wcsicmp(testGroup, TEXT("all")) == 0) //if the first key is set to all, let the user in
00609                 return true;
00610 
00611         wcscpy(groupRegEntry, TEXT("userOK0"));
00612 
00613         while(regLookup(groupRegEntry, testGroup) == ERROR_SUCCESS) // go through all registry keys beginning with userOK
00614         {
00615                 if (ldapGroupCheck(username, testGroup, gloLdapStruct, ldpContext)) // if the user is in the group, return true, else keep going
00616                         return true;
00617                 else
00618                 {
00619                         i++;
00620                         _itow(i, temp, 10);
00621                         wcscpy(groupRegEntry, TEXT("userOK"));
00622                         wcscat(groupRegEntry, temp); //eg: userOK27
00623                 }
00624         }
00625         return false;
00626 }
00627 
00628 bool createAsAdmin(WCHAR * username, LDAP *gloLdapStruct, WCHAR * ldpContext)
00629 {
00630         WCHAR testGroup[256];
00631         WCHAR groupRegEntry[256];
00632         WCHAR temp[16];
00633         UINT i = 0;
00634 #ifdef _DEBUG
00635         WCHAR debug[256];
00636 #endif
00637 
00638         if (ERROR_SUCCESS != regLookup(TEXT("adminOK0"), testGroup)) // failsafe: if the registry key isn't filled in, they shouldn't be admins!
00639                 return false;
00640         else if (wcsicmp(testGroup, TEXT("all")) == 0) //if the first key is set to all, let all the users in as admins!
00641         {
00642 #ifdef _DEBUG
00643                 debugOut(TEXT("userOK0 set to all, so returning true"));
00644 #endif
00645                 return true;
00646         }
00647 #ifdef _DEBUG
00648         else debugOut(testGroup);
00649 #endif
00650 
00651         wcscpy(groupRegEntry, TEXT("adminOK0"));
00652 
00653         while(regLookup(groupRegEntry, testGroup) == ERROR_SUCCESS) // go through all registry keys beginning with userOK
00654         {
00655                 if (ldapGroupCheck(username, testGroup, gloLdapStruct,ldpContext)) // if the user is in the group, return true, else keep going
00656                         return true;
00657                 else
00658                 {
00659                         i++;
00660                         _itow(i, temp, 10);
00661                         wcscpy(groupRegEntry, L"adminOK");
00662                         wcscat(groupRegEntry, temp); //eg: userOK27
00663 #ifdef _DEBUG
00664                         wsprintf(debug,L"RegEntry: %s; Value: ",groupRegEntry, testGroup);
00665             debugOut(debug);    
00666 #endif
00667                 }
00668         }
00669 #ifdef _DEBUG
00670         debugOut(TEXT("createAsAdmin: about to return false"));
00671 #endif
00672         return false;
00673 }
00674 
00675 PWCHAR * ldapSearchAttr(LPTSTR Username, WCHAR * attr, LDAP *gloLdapStruct, WCHAR * ldpContext, bool ldpOverride)
00676 {
00677 /*      pass ldapSearchAttr the username and the attribute name and it returns
00678         a pointer to an array of strings with the attributes. You shouldn't use it with
00679         attributes with binary values, but as a quick & dirty query, it does the job.
00680         Really, though, it should be rewritten to take a dn (retrieved with a previous call)
00681         to minimize search operations. It works on the first entry returned ONLY, so if you have more
00682         than one, make sure the one you want would get returned first.
00683 */
00684 // 7/3/03 ldpOverride added to make function more useful
00685 // ldpOverride tells us to do our filter raw w/o modification (in other words, this isn't an auth check
00686 
00687         /* vars needed */
00688         //LDAP *myLdapStruct; //an ldap structure thing
00689         ULONG ldapStat;
00690         int ldapVer = LDAP_VERSION3;
00691         WCHAR ldapFilter[256];
00692         WCHAR ldapFilterOrig[128];
00693         WCHAR ldapContext1[256];
00694 
00695         LDAPMessage* pMsg;
00696         LDAPMessage* ldapFirstEntry;
00697         PWCHAR * userAttrPtr;
00698         WCHAR * a;
00699         BerElement *ber;
00700         PWCHAR ldapAttrs[] = {attr, NULL};
00701 #ifdef _DEBUG
00702         WCHAR debug[256];
00703 #endif
00704 
00705         LPCWSTR myError = L"The data is the return code.";
00706 
00707         if (ERROR_SUCCESS != regLookup(TEXT("ldapFilter"), ldapFilter))
00708                 swprintf(ldapFilter, TEXT("(uid=%s)"), Username);
00709 
00710         if (ldpOverride == false)
00711         {
00712                 if (regLookup(L"ldapFilter", ldapFilterOrig) != ERROR_SUCCESS)
00713                         wcscpy(ldapFilterOrig, L"(uid=%s)");
00714                 swprintf(ldapFilter, ldapFilterOrig, Username);
00715         }
00716         else wcscpy(ldapFilter, Username);
00717 
00718         if (ldpContext == NULL)
00719         {
00720                 if (regLookup(L"ldapContext0", ldapContext1) != ERROR_SUCCESS)
00721 #ifdef _DEBUG
00722                         debugOut(L"ldapSearchAttr could not find first LDAP context");
00723 #endif
00724                         return NULL;
00725         }
00726         else wcscpy(ldapContext1,ldpContext);
00727 
00728         // perform a synchronous search using previously built filter and put results in pMsg
00729         ldapStat = ldap_search_ext_s(gloLdapStruct, ldapContext1, LDAP_SCOPE_SUBTREE, ldapFilter, ldapAttrs, 0, NULL, NULL, NULL, 0, &pMsg);
00730         //debugOut(TEXT("executed search"));
00731         if (ldapStat != LDAP_SUCCESS)
00732         {
00733 #ifdef _DEBUG
00734                 swprintf(debug,L"ldap_search_s failed with error: 0x%x\n", ldapStat);
00735                 debugOut(debug);
00736 #endif
00737                 return NULL;
00738         }
00739 
00740         // Get the first entry returned in pMsg
00741     ldapFirstEntry = ldap_first_entry(gloLdapStruct, pMsg);
00742         //debugOut(TEXT("got first entry"));
00743         if (ldapFirstEntry == NULL)
00744         {
00745                 ldapStat = LdapGetLastError();
00746 
00747 #ifdef _DEBUG
00748                 swprintf(debug,L"ldap_first_entry failed with error: 0x%x\n", ldapStat);
00749 #endif
00750                 return NULL;
00751         }
00752 
00753         // before we can get the values, we must get the attributes
00754         a = ldap_first_attribute( gloLdapStruct, ldapFirstEntry, &ber);
00755         //debugOut(TEXT("got first attribute"));
00756 
00757         userAttrPtr = ldap_get_values(gloLdapStruct, ldapFirstEntry, a);
00758         //debugOut(TEXT("got values"));
00759 
00760         ber_free(ber, 0);
00761     ldap_msgfree(pMsg);
00762         return userAttrPtr;
00763 }
00764 
00765 void populateUserInfo(pGinaInfo *settingsInfo, LDAP *gloLdapStruct, WCHAR * ldpContext)
00766 {
00767         // This is where we set attributes on the Windows user based upon
00768         // what we find in LDAP-land
00769         // Note that we only use the first description attribute
00770 
00771         PWCHAR * fullName;
00772         PWCHAR * description;
00773 
00774         WCHAR homeAutomount[10];
00775 
00776         fullName = ldapSearchAttr(settingsInfo->Username, TEXT("fullName"), gloLdapStruct, ldpContext, false);
00777         if (fullName)
00778         {
00779                 settingsInfo->userFullName = wcsdup(fullName[0]);
00780                 ldap_value_free(fullName);
00781         }
00782         description = ldapSearchAttr(settingsInfo->Username, TEXT("description"), gloLdapStruct, ldpContext, false);
00783         if (description)
00784         {
00785                 settingsInfo->userDescription = _wcsdup(description[0]);
00786                 ldap_value_free(description);
00787         }
00788 
00789         // begin Nate code for home directory support
00790         if(regLookup(L"homeAutomount",homeAutomount) != ERROR_SUCCESS)
00791                 homeAutomount[0] = TEXT('0');
00792 
00793         if(_wtoi(homeAutomount) >= 1)
00794         {
00795                 // Auto home directory mounting
00796                 PWCHAR *homeDirectory;
00797                 LPTSTR parsedDirectory;
00798                 WCHAR stripMe[10000];
00799                 WCHAR appendMe[10000];
00800                 WCHAR driveLetter[10];
00801                 WCHAR homeAttribute[1024];
00802                 TCHAR buffer[30000];
00803                 TCHAR *this_char = NULL;
00804                 int i = 0, y=0;
00805 
00806                 WCHAR volObjCtx[256];
00807                 WCHAR volObjCN[256];
00808                 WCHAR volObj[256];
00809                 WCHAR homeSubDir[256];
00810                 WCHAR * token;
00811                 WCHAR ndsHomeDirVals[5][256];
00812 
00813                 if(regLookup(L"homeAttribute", homeAttribute) != ERROR_SUCCESS)
00814                         swprintf(homeAttribute,L"homeDirectory");
00815                 if(regLookup(L"homeAppendString", appendMe) != ERROR_SUCCESS)
00816                         appendMe[0] = TEXT('\0');                                                       // Don't append anything by default
00817                 if(regLookup(L"homeDriveLetter", driveLetter) != ERROR_SUCCESS)
00818                         swprintf(driveLetter,L"I");
00819 
00820                 switch (_wtoi(homeAutomount))
00821                 {
00822                         // 7/1/03 Switched to switch to allow for multiple methods of home directories
00823 
00824                 case 1: // MacOSX (pronounce it and it sounds funny)
00825                         if(regLookup(L"homeStripString", stripMe) != ERROR_SUCCESS)
00826                                 swprintf(stripMe,TEXT("/Network/Servers/"));            // MacOSX returns /Network/Servers/%server%...
00827                         
00828                         homeDirectory = ldapSearchAttr(settingsInfo->Username,homeAttribute,gloLdapStruct,ldpContext, false);
00829                         
00830                         // Now we have something like /Network/Servers/Servername/sharepoint/username
00831                         break;
00832 
00833                 case 2: // that NDS thing: much, much uglier than what you just saw
00834                         wcscpy(stripMe,L"");
00835                         // now get the homedir value
00836                         homeDirectory = ldapSearchAttr(settingsInfo->Username,homeAttribute,gloLdapStruct,ldpContext, false);
00837                         if (homeDirectory == NULL)
00838                                 break;
00839                         // this will be something ugly like cn=SAS1-Users,ou=SAS,o=mu#0#SAS/COOPERMJ
00840                         // so begin to parse
00841                         if(regLookup(L"homeDriveLetter", driveLetter) != ERROR_SUCCESS)
00842                                 swprintf(driveLetter,TEXT("I"));
00843                         // pull apart ldapContext and configure as NDS context
00844                         token = wcstok(*homeDirectory,L"#");
00845                         while (token != NULL)
00846                         {
00847                                 wcscpy(ndsHomeDirVals[i],token);
00848                                 token = wcstok(NULL,L"#");
00849                                 i++;
00850                         }
00851                         // this should give us [0] = SAS1-Users, [1] = 0, [2] = SAS/COOPERMJ
00852                         // we'll copy these values to variables with real names
00853                         wcscpy(volObj, ndsHomeDirVals[0]);
00854                         wcscpy(homeSubDir, ndsHomeDirVals[2]);
00855                         // now we need to find out what SAS1-Users is
00856                         // first we need to end the string at the comma...
00857                         token = wcstok(volObj,L",");
00858                         wcscpy(volObjCN, token);
00859                         // then we establish our search base with what came after the comma
00860                         //wcscpy(ndsHomeDirVals[1], L""); // zero out the string
00861                         // commence ugly, ugly code -- someone give me a hand here?
00862                         wcscpy(volObjCtx, L"");
00863                         while (token != NULL)
00864                         {
00865                                 token = wcstok(NULL,L","); // search for ,
00866                                 if (token != NULL)
00867                                 {
00868                                         wcscat(volObjCtx, token);
00869                                         wcscat(volObjCtx, L",");
00870                                 }
00871                         }
00872                         y = (int) wcslen(volObjCtx);
00873                         volObjCtx[y-1] = NULL;
00874                         // end ugly, ugly code -- resume normal ugly code
00875                         // now volObjCN contains the CN and volObjCtx contains the context
00876                         // then query for hostServer
00877                         PWCHAR * store;
00878                         store = ldapSearchAttr(volObjCN, L"hostServer", gloLdapStruct, volObjCtx, true);
00879                         WCHAR volServDN[256];
00880                         WCHAR ndsDNSDomain[256];
00881                         WCHAR volObjVol[256];
00882                         WCHAR volObjFullPath[256];
00883                         wcscpy(volServDN,*store);
00884                         // okay, so now ndsHomeDirVals[3] has the dn of the server, but stupid Novell doesn't store
00885                         // dns name as an attribute, but gives us silly things labelled networkAddress that I can figure out
00886                         // so we'll cheat and get the CN and append a "common" dns suffix.
00887                         token = wcstok(volServDN,L",");
00888                         wcscpy(volServDN,token);
00889                         token = wcstok(volServDN,L"=");
00890                         token = wcstok(NULL,L"=");
00891                         wcscpy(volServDN,token);
00892                         // ndsHomeDirVals[1] now has the pure cn of the server
00893                         regLookup(L"ndsServerDomain", ndsDNSDomain);
00894                         wcscat(volServDN, ndsDNSDomain);
00895                         // then get volume
00896                         store = ldapSearchAttr(volObjCN, L"hostResourceName", gloLdapStruct, volObjCtx, true);
00897                         wcscpy(volObjVol,*store);
00898                         //wcscpy(volObjFullPath, L"\\\\");
00899                         wcscpy(volObjFullPath, volServDN);
00900                         wcscat(volObjFullPath, L"\\");
00901                         wcscat(volObjFullPath, volObjVol);
00902                         wcscat(volObjFullPath, L"\\");
00903                         wcscat(volObjFullPath, homeSubDir);
00904                         // ndsHomeDirVals[0] should now be a UNC path to home dir
00905                         *homeDirectory = wcsdup(volObjFullPath);
00906                         break;
00907 
00908                 default: // assume nothing
00909                         break;
00910 
00911                 }
00912 
00913                 if(homeDirectory)
00914                 {
00915                         parsedDirectory = homeDirectory[0];
00916                         
00917                         if(stripMe[0] != TEXT('\0'))
00918                         {
00919                                 // We could just move ahead X characters: parsedDirectory += wcslen(stripMe);
00920                                 //  but we should probably do this the *smart* way. Check to see if the string in
00921                                 //  stripMe is there first, then move past it if it is
00922                                 if(wcsncmp(stripMe,parsedDirectory,wcslen(stripMe))==0)
00923                                         parsedDirectory+=wcslen(stripMe);
00924                         }
00925                         memset(buffer,'\0',sizeof(buffer));                             
00926                         if(settingsInfo->mapPaths)
00927                                 if(appendMe[0] != TEXT('\0'))
00928                                         swprintf(buffer,L"%s:\\\\%s%s;%s",driveLetter,parsedDirectory,appendMe,settingsInfo->mapPaths);
00929                                 else
00930                                         swprintf(buffer,L"%s:\\\\%s;%s",driveLetter,parsedDirectory,settingsInfo->mapPaths);
00931                         else
00932                                 if(appendMe[0] != TEXT('\0'))
00933                                         swprintf(buffer,L"%s:\\\\%s%s",driveLetter,parsedDirectory,appendMe);
00934                                 else
00935                                         swprintf(buffer,L"%s:\\\\%s",driveLetter,parsedDirectory);
00936                         
00937                         do {
00938                                 this_char = wcsstr(buffer,L"/");
00939                                 if(this_char)
00940                                         *this_char = TEXT('\\');
00941                         } while(this_char!=NULL);
00942                         
00943                         settingsInfo->mapPaths = _tcsdup(buffer);
00944                         //end nate code
00945                 }
00946         }       
00947 }
00948 
00949 void setNDSReg(WCHAR * ndsTree, WCHAR * strNDSContext)
00950 {
00951         LONG lResult;
00952         HKEY hKey;
00953 
00954         lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
00955                                                          L"SYSTEM\\CurrentControlSet\\Services\\NetwareWorkstation\\Parameters\\Trees",
00956                                                          0,
00957                                                          NULL,
00958                                                          REG_OPTION_NON_VOLATILE,
00959                                                          KEY_ALL_ACCESS,
00960                                                          NULL,   // This field can be used to set Security..?
00961                                                          &hKey,
00962                                                          NULL);  // This value can be used to determine if the key existed or not..
00963                                                                          //  but we dont care as long as it opens.. i guess.
00964 
00965         if(lResult == ERROR_SUCCESS)
00966         {
00967                 lResult = RegSetValueEx(hKey,ndsTree,0,REG_SZ,
00968                                                                 (CONST BYTE *) strNDSContext,
00969                                                                 (DWORD)wcslen(strNDSContext) * 4);
00970         }
00971         
00972 #ifdef _DEBUG
00973         if (lResult != ERROR_SUCCESS)
00974                 debugOut(L"Failed to set registry for Novell client");
00975 #endif
00976 }
00977 
00978 void confNDSClient(WCHAR * ndsTree, WCHAR * ldpContext, WCHAR * Username)
00979 {
00980         WCHAR strWrkContext[256]; // copy of ldpContext that was passed in
00981         WCHAR strNDSContext[256] = {L""}; // context in NDS form
00982         WCHAR * token;
00983         UINT intCntxLen;
00984 #ifdef _DEBUG
00985         WCHAR debug[256];
00986 #endif
00987 
00988         wcscpy(strWrkContext,ldpContext);
00989         // pull apart ldapContext and configure as NDS context
00990         token = wcstok(strWrkContext,L",");
00991         while (token != NULL)
00992         {
00993                 wcscat(strNDSContext,token);
00994                 wcscat(strNDSContext,L".");
00995                 token = wcstok(NULL,L",");
00996         }
00997         intCntxLen = (UINT) wcslen(strNDSContext);
00998         strNDSContext[intCntxLen - 1] = NULL;
00999 #ifdef _DEBUG
01000         wsprintf(debug,L"NDS Context: %s",strNDSContext);
01001         debugOut(debug);
01002 #endif
01003 
01004         // set registry to NDS context
01005         setNDSReg(ndsTree,strNDSContext);
01006 }
01007 
01008 BOOL whoIsGroup(WCHAR * strAdminGroup, DWORD rid)
01009 {
01010         // Much of the following code is from 
01011         // http://support.microsoft.com/default.aspx?scid=KB;en-us;q157234
01012         // I've left much of the cruft in as reference for future needs
01013 
01014 //      PUSER_MODALS_INFO_2 umi2;
01015 //      NET_API_STATUS nas;
01016 
01017 //      UCHAR SubAuthorityCount;
01018         PSID pSid;
01019         SID_NAME_USE snu;
01020 
01021         WCHAR DomainName[DNLEN+1];
01022         DWORD cchDomainName = DNLEN;
01023         BOOL bSuccess = FALSE; // assume failure
01024         WCHAR computerName[256];
01025         DWORD cnSize;
01026         DWORD cchName = UNLEN;
01027 
01028         GetComputerName(computerName, &cnSize);
01029 
01030 
01031         SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
01032         // 
01033         // Sid is the same regardless of machine, since the well-known
01034         // BUILTIN domain is referenced.
01035         // 
01036 
01037         if(AllocateAndInitializeSid(
01038                         &sia,
01039                         2,
01040                         SECURITY_BUILTIN_DOMAIN_RID,
01041                         rid,
01042                         0, 0, 0, 0, 0, 0,
01043                         &pSid
01044                         )) {
01045 
01046                 bSuccess = LookupAccountSidW(
01047                                 computerName,
01048                                 pSid,
01049                                 strAdminGroup,
01050                                 &cchName,
01051                                 DomainName,
01052                                 &cchDomainName,
01053                                 &snu
01054                                 );
01055 
01056                 FreeSid(pSid);
01057         }
01058 
01059         return bSuccess;
01060 }
01061 
01062 // ldapNegotiate is to configure LDAP settings after the connection is made.
01063 void ldapNegotiate(LDAP *ld)
01064 {
01065         DWORD dwdLdapTimeout;
01066         ULONG ldpError;
01067         WCHAR debug[256];
01068 
01069         // default timeout for ldap failure is 120 seconds -- ouch! We'll set our default to 30 and allow
01070         // an override in ldapTimeout
01071         dwdLdapTimeout = regReadDword(L"ldapTimeout");
01072         if (dwdLdapTimeout = 0)
01073                 dwdLdapTimeout = 30;
01074         ldpError = ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &dwdLdapTimeout);
01075 #ifdef _DEBUG
01076         if (ldpError != LDAP_SUCCESS)
01077         {
01078                 swprintf(debug, TEXT("LDAP error in ldapNegotiate: %i"), ldpError);
01079                 debugOut(debug);
01080         }
01081 #endif
01082 
01083 
01084 }
01085 LDAPAUTH_API BOOL IsRequired(void)
01086 {
01087         WCHAR required[10];
01088         DWORD perhaps = 0;
01089         if (ERROR_SUCCESS != regLookup(L"am_i_required", required))
01090                 perhaps = _wtoi(required);
01091 
01092         if(perhaps)
01093                 return true;
01094 
01095         return false;
01096 }
01097 
01098 LDAPAUTH_API void ChangePluginSettings(void)
01099 {
01100         // DO NOT PUT CODE BEFORE THIS!
01101         AFX_MANAGE_STATE(AfxGetStaticModuleState());
01102         // All code must follow this statement or crashing will ensue ;)
01103         CConfigureDialog *myDlg = new CConfigureDialog();
01104         myDlg->DoModal();
01105 }
01106 
01107 LDAPAUTH_API void LoginHook(pGinaInfo *settingsInfo)
01108 {
01109         //system(TEXT("cmd /q /c c:\\pgina\\login.cmd >> c:\\pgina\\logincmd.log"));
01110         WCHAR loginHook[256];
01111         WCHAR loginHookChooser[256] = L"loginHook0";
01112         WCHAR temp[10];
01113 #ifdef _DEBUG
01114         WCHAR debug[256];
01115 #endif
01116 
01117         for(LONG i = 0; i < 255; i++)
01118         {
01119 #ifdef _DEBUG
01120                 swprintf(debug, L"Performing login hook %i...", i);
01121                 debugOut(debug);
01122 #endif
01123                 wcscpy(loginHookChooser, L"loginHook");
01124                 _itow(i, temp, 10);
01125                 wcscat(loginHookChooser, temp);
01126                 if (regLookup(loginHookChooser, loginHook) == ERROR_SUCCESS)
01127                 {
01128                         _wsystem(loginHook);
01129                 }
01130                 else break;
01131         }
01132 }
01133 
01134 LDAPAUTH_API void LogoutHook(pGinaInfo *settingsInfo)
01135 {
01136         //system(TEXT("cmd /q /c c:\\pgina\\logout.cmd >> c:\\pgina\\logoutcmd.log"));
01137         WCHAR logoutHook[256];
01138         WCHAR logoutHookChooser[256] = L"logoutHook0";
01139         WCHAR temp[10];
01140 #ifdef _DEBUG
01141         WCHAR debug[256];
01142 #endif
01143 
01144         for(LONG i = 0; i < 255; i++)
01145         {
01146 #ifdef _DEBUG
01147                 swprintf(debug, L"Performing logout hook %i...", i);
01148                 debugOut(debug);
01149 #endif
01150                 wcscpy(logoutHookChooser, L"logoutHook");
01151                 _itow(i, temp, 10);
01152                 wcscat(logoutHookChooser, temp);
01153                 if (regLookup(logoutHookChooser, logoutHook) == ERROR_SUCCESS)
01154                 {
01155                         _wsystem(logoutHook);
01156                 }
01157                 else break;
01158         }
01159 }
01160 
01161 LDAPAUTH_API BOOL ChangeUserPassword(LPTSTR Username,PWCHAR OldPassword,PWCHAR NewPassword)
01162 {
01163         int modResult = 0, newLength = 0, total_chars = 0;
01164         int upper_case_char = 0, lower_case_char = 0;
01165         int numeric_char = 0, special_char = 0;
01166         int pwdMinLength = 0;
01167         BOOL reqUpper = 0, reqLower = 0, reqNum = 0, reqSpecial = 0;
01168         WCHAR cMinLength[256], cRestrictedChars[256];
01169         WCHAR cReqUpper[256], cReqLower[256], cReqNum[256], cReqSpecial[256];
01170         LDAP * pwLdapStruct = NULL; //an ldap structure thing
01171         WCHAR useSSL[256];
01172         WCHAR ldapServer[256];
01173         WCHAR ldpContext[256];
01174         LDAPMod *modStruct[3];
01175         LDAPMod pwNew; // LDAP on NDS requires delete then add
01176         WCHAR *newModValues[2];
01177         BOOL result;
01178         BOOL authenticated;
01179         WCHAR dn[256];
01180 #ifdef _DEBUG
01181         WCHAR debug[256];
01182 #endif
01183         const wchar_t *endNewPassword = NewPassword;
01184 
01185         if (wcslen(OldPassword) == 0) { // will not accept null old password
01186 #ifdef _DEBUG
01187                 debugOut(L"Empty old password");
01188 #endif
01189                 return false;
01190         }
01191 
01192         // Retrieve password requirements from registry
01193         if (regLookup(L"pwdMinLength", cMinLength) == ERROR_SUCCESS) {
01194                 pwdMinLength = _wtoi(cMinLength);
01195         }
01196         else {
01197                 // default to 8 minimum character
01198                 pwdMinLength = 8;
01199         }
01200 
01201         if (regLookup(L"requireLower", cReqLower) == ERROR_SUCCESS) {
01202                 if (_wtoi(cReqLower) == 1)
01203                         reqLower = true;
01204                 else
01205                         reqLower = false;
01206         }
01207 
01208         if (regLookup(L"requireUpper", cReqUpper) == ERROR_SUCCESS) {
01209                 if (_wtoi(cReqUpper) == 1)
01210                         reqUpper = true;
01211                 else
01212                         reqUpper = false;
01213         }
01214 
01215         if (regLookup(L"requireNumeric", cReqNum) == ERROR_SUCCESS) {
01216                 if (_wtoi(cReqNum) == 1)
01217                         reqNum = true;
01218                 else
01219                         reqNum = false;
01220         }
01221 
01222         if (regLookup(L"requireSpecial", cReqSpecial) == ERROR_SUCCESS) {
01223                 if (_wtoi(cReqSpecial) == 1)
01224                         reqSpecial = true;
01225                 else
01226                         reqSpecial = false;
01227         }
01228 
01229         regLookup(L"restrictedChars", cRestrictedChars);
01230         
01231         // Now check for requirements for password
01232         do {
01233                 if (wcschr(cRestrictedChars, *endNewPassword) != NULL) {
01234                         WCHAR errMsg[256];
01235                         wsprintf(errMsg,L"Password cannot contain the character(s): %s", cRestrictedChars);
01236                         AfxMessageBox(errMsg, MB_ICONERROR | MB_OK, 0);
01237                         return false;
01238                 }
01239 
01240                 if (isprint(*endNewPassword) == 0) {
01241                         if (endNewPassword == NewPassword) {
01242                                 AfxMessageBox(L"Password is too short");
01243                         }
01244                         else {
01245                                 AfxMessageBox(L"Password cannot contain unprintable characters");
01246                         }
01247                         return false;
01248                 }
01249 
01250                 if (isupper(*endNewPassword) != 0) {
01251                         upper_case_char = 1;
01252                         continue;
01253                 }
01254 
01255                 if (islower(*endNewPassword) != 0) {
01256                         lower_case_char = 1;
01257                         continue;
01258                 }
01259 
01260                 if (isdigit(*endNewPassword) != 0) {
01261                         numeric_char = 1;
01262                         continue;
01263                 }
01264 
01265                 special_char = 1;
01266         } while(*(++endNewPassword));
01267 
01268         if ((endNewPassword - NewPassword - 1) < pwdMinLength) { // must be at least 8 characters
01269                 AfxMessageBox(L"Password too short.", MB_ICONERROR | MB_OK, 0);
01270                 return false;
01271         }
01272 
01273         if (reqLower && !lower_case_char) {
01274                 AfxMessageBox(L"Password must contain a lowercase character.", MB_ICONERROR | MB_OK, 0);
01275                 return false;
01276         }
01277 
01278         if (reqUpper && !upper_case_char) {
01279                 AfxMessageBox(L"Password must contain a uppercase character.", MB_ICONERROR | MB_OK, 0);
01280                 return false;
01281         }
01282 
01283         if (reqNum && !numeric_char) {
01284                 AfxMessageBox(L"Password must contain a numeric character.", MB_ICONERROR | MB_OK, 0);
01285                 return false;
01286         }
01287 
01288         if (reqSpecial && !special_char) {
01289                 AfxMessageBox(L"Password must contain a special character.", MB_ICONERROR | MB_OK, 0);
01290                 return false;
01291         }
01292 
01293         if (regLookup(L"ldapServer", ldapServer) != ERROR_SUCCESS) // is ldapserver defined?
01294                 return false;
01295 
01296 #ifdef _DEBUG
01297         wsprintf(debug,L"LDAP Server: %s",ldapServer);
01298         debugOut(debug);
01299 #endif
01300 
01301         if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL) == 1))
01302                 pwLdapStruct = ldap_sslinit(ldapServer, LDAP_SSL_PORT, 1);
01303         else
01304                 pwLdapStruct = ldap_init(ldapServer, LDAP_PORT);
01305 
01306 #ifdef _DEBUG
01307         if (!pwLdapStruct)
01308         {
01309                 debugOut(TEXT("NULL gloLdapStruct"));
01310                 swprintf(debug, TEXT("LDAP error: %i"), LdapGetLastError());
01311                 debugOut(debug);
01312         }
01313 #endif
01314         switch(determineLdap())
01315         {
01316                 case MULTIMAP:
01317                         authenticated = ldapTestMultiMap(Username, OldPassword, ldapServer, ldpContext, pwLdapStruct, dn);
01318                         break;
01319 
01320                 case SEARCH:
01321                         authenticated = ldapTestSearch(Username, OldPassword, ldpContext, pwLdapStruct, dn); // if yes, let 'em in; if no, don't
01322                         break;
01323 
01324                 case STRMAP:
01325                         authenticated = ldapTestMap(Username, OldPassword, ldapServer, ldpContext, pwLdapStruct, dn);
01326                         *ldpContext = NULL;
01327                         break;
01328 
01329                 default: //error happened with determine ldap, so we'll just deny the user for safety
01330                         authenticated = false;
01331                         break;
01332         }
01333 
01334         // check that old password is what is in LDAP
01335         /*
01336         const PWCHAR attrPwd = L"userPassword";
01337         ULONG ldapStat;
01338         ldapStat = ldap_compare_s(pwLdapStruct, dn, attrPwd, OldPassword);
01339         if (ldapStat != LDAP_COMPARE_TRUE) {
01340 #ifdef _DEBUG
01341                 debugOut(L"Old password not correct");
01342 #endif
01343                 return false;
01344         }
01345         */
01346 
01347         pwNew.mod_op = LDAP_MOD_REPLACE;
01348         pwNew.mod_type = L"userPassword";
01349         newModValues[0] = NewPassword;
01350         newModValues[1] = NULL;
01351         pwNew.mod_vals.modv_strvals = newModValues;
01352 
01353         modStruct[0] = &pwNew;
01354         modStruct[1] = NULL;
01355 
01356         if (authenticated)
01357         {
01358                 modResult = ldap_modify_s(pwLdapStruct, dn, modStruct);
01359                 if (modResult == LDAP_SUCCESS)
01360                         result = true;
01361                 else result = false;
01362         }
01363         else result = false;
01364 
01365         return result; 
01366 }
01367 
01368 LDAPAUTH_API LPCTSTR AboutPlugin(void)
01369 {
01370         WCHAR temp[2048];
01371 
01372         _tcscpy(temp,LDAPAUTHVERSION);
01373         _tcscat(temp,TEXT(" "));
01374         // Return a sample descriptions string
01375         switch(determineLdap())
01376         {
01377                 case MULTIMAP:
01378             //return TEXT("LDAP auth plugin in multimap mode");
01379                         _tcscat(temp,TEXT("in multimap mode"));
01380                         break;
01381 
01382                 case SEARCH:
01383                         //return TEXT("LDAP auth plugin in search mode");
01384                         _tcscat(temp,TEXT("in search mode"));
01385                         break;
01386 
01387                 case STRMAP:
01388                         //return TEXT("LDAP auth plugin in straight map mode");
01389                         _tcscat(temp,TEXT("in straight map mode"));
01390                         break;
01391 
01392                 default:
01393                         _tcscat(temp,TEXT("is currently not configured correctly."));
01394                         //return TEXT("It does not appear ldapMethod is set correctly");
01395                         break;
01396         }
01397         return (TEXT("%s"), temp);
01398 }
01399 
01400 LDAPAUTH_API BOOL UserLogin(LPTSTR Username, LPTSTR Password, pGinaInfo *settingsInfo)
01401 {
01402         BOOL authenticated = false;
01403         LDAP * gloLdapStruct = NULL; //an ldap structure thing
01404         WCHAR useSSL[256], disablePwd[256];
01405         WCHAR ldapServer[256];
01406         WCHAR ndsTree[256]; // name of tree if using with NDS
01407         WCHAR ldpContext[256];
01408         WCHAR dn[256];
01409         WCHAR strGroupLookup[256] = {L"Adminbozos"};
01410         WCHAR strGroupNames[1024];
01411         WCHAR stzLdapPort[64];
01412         ULONG ldapVer = LDAP_VERSION3;
01413         DWORD ldapPort;
01414         WCHAR debug[256];
01415         DWORD dwdLdapTimeout;
01416         ULONG ldpError;
01417 
01418         if (wcslen(Password) == 0) // if LDAP attempts to authenticate w/ a NULL password, it will succeed as anonymous
01419                 authenticated = false;
01420         else
01421         {
01422                 if (regLookup(L"ldapServer", ldapServer) != ERROR_SUCCESS)
01423                         return false;
01424                 if (regLookup(L"ldapPort", stzLdapPort) == ERROR_SUCCESS)
01425                         ldapPort = (DWORD) _wtoi(stzLdapPort);
01426                 else if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL) == 1))
01427                         ldapPort = LDAP_SSL_PORT;
01428                 else
01429                         ldapPort = LDAP_PORT;
01430 
01431                 if ((regLookup(L"useSSL", useSSL) == ERROR_SUCCESS) && (_wtoi(useSSL) == 1))
01432                         gloLdapStruct = ldap_sslinit(ldapServer, ldapPort, 1);
01433                 else
01434                         gloLdapStruct = ldap_init(ldapServer, ldapPort);
01435 
01436         
01437                 // default timeout for ldap failure is 120 seconds -- ouch! We'll set our default to 30 and allow
01438                 // an override in ldapTimeout
01439                 dwdLdapTimeout = regReadDword(L"ldapTimeout");
01440                 if (dwdLdapTimeout = 0)
01441                         dwdLdapTimeout = 30;
01442                 ldpError = ldap_set_option(gloLdapStruct, LDAP_OPT_TIMELIMIT, &dwdLdapTimeout);
01443 #ifdef _DEBUG
01444                 if (ldpError != LDAP_SUCCESS)
01445                 {
01446                         swprintf(debug, TEXT("LDAP error in ldapNegotiate: %i"), ldpError);
01447                         debugOut(debug);
01448                 }
01449 #endif
01450 
01451 
01452         }
01453 #ifdef _DEBUG
01454         if (gloLdapStruct == NULL)
01455         {
01456                 debugOut(TEXT("NULL gloLdapStruct"));
01457                 swprintf(debug, TEXT("LDAP error: %i"), LdapGetLastError());
01458                 debugOut(debug);
01459         }
01460 
01461         debugOut(TEXT("starting run..."));
01462 #endif
01463 
01464         if (gloLdapStruct != NULL)
01465         {
01466                 ldap_set_option(gloLdapStruct,LDAP_OPT_VERSION,&ldapVer);
01467                 switch(determineLdap())
01468                 {
01469                         case MULTIMAP:
01470 #ifdef _DEBUG
01471                                 swprintf(debug, TEXT("Username: %s"), Username);
01472                 debugOut(debug);
01473 #endif
01474                                 authenticated = ldapTestMultiMap(Username, Password, ldapServer, ldpContext, gloLdapStruct, dn);
01475                                 break;
01476 
01477                         case SEARCH:
01478                                 authenticated = ldapTestSearch(Username, Password, ldpContext, gloLdapStruct, dn); // if yes, let 'em in; if no, don't
01479                                 break;
01480 
01481                         case STRMAP:
01482                                 authenticated = ldapTestMap(Username, Password, ldapServer, ldpContext, gloLdapStruct, dn);
01483                                 *ldpContext = NULL;
01484                                 break;
01485 
01486                         default: //error happened with determine ldap, so we'll just deny the user for safety
01487                                 authenticated = false;
01488                                 break;
01489                 }
01490 #ifdef _DEBUG
01491                 if (authenticated == false)
01492                 {
01493                         swprintf(debug, TEXT("Authentication via %i failed."), determineLdap());
01494                         debugOut(debug);
01495                 }
01496 #endif
01497 
01498                 if (authenticated)
01499                 {
01500                         authenticated = okToLogin(Username, gloLdapStruct, ldpContext);
01501                         if (createAsAdmin(Username, gloLdapStruct,ldpContext))
01502                         {
01503 #ifdef _DEBUG
01504                                 debugOut(L"CreateAsAdmin returned true");
01505 #endif
01506                                 whoIsGroup(strGroupLookup, DOMAIN_ALIAS_RID_ADMINS);
01507                                 wcscpy(strGroupNames, strGroupLookup);
01508                                 whoIsGroup(strGroupLookup, DOMAIN_ALIAS_RID_USERS);
01509                                 wcscat(strGroupNames, L";");
01510                                 wcscat(strGroupNames, strGroupLookup);
01511                                 settingsInfo->isAdmin = true;
01512                                 settingsInfo->userGroups = wcsdup(strGroupNames);
01513                         }
01514                         else 
01515                         {
01516 #ifdef _DEBUG
01517                                 debugOut(L"CreateAsAdmin returned false");
01518 #endif                  
01519                                 whoIsGroup(strGroupLookup, DOMAIN_ALIAS_RID_USERS);
01520                                 settingsInfo->userGroups = wcsdup(strGroupLookup);
01521                         }
01522                         populateUserInfo(settingsInfo, gloLdapStruct, ldpContext);
01523 
01524                         if (regLookup(TEXT("disablePwd"), disablePwd) == ERROR_SUCCESS) {
01525                                 if (_wtoi(disablePwd) == 1)
01526                                         settingsInfo->allowPassChange = 0;
01527                                 else
01528                                         settingsInfo->allowPassChange = 1;
01529                         }
01530 #ifdef _DEBUG
01531                         swprintf(debug, TEXT("Change password set to : %d"), settingsInfo->allowPassChange);
01532                         debugOut(debug);
01533 #endif
01534 
01535                         if (regLookup(L"ndsTree",ndsTree) == ERROR_SUCCESS)
01536                                 confNDSClient(ndsTree, ldpContext, Username);
01537 #ifdef _DEBUG
01538                         else debugOut(L"No NDS tree set");
01539 #endif
01540                 }
01541 
01542                 ldap_unbind(gloLdapStruct); // clean up & go home
01543         }
01544         
01545         if(!authenticated) {
01546                 ULONG error_num;
01547                         // Set the error message accordingly
01548                         error_num = LdapGetLastError();
01549                         if(error_num == LDAP_SERVER_DOWN || error_num == LDAP_UNAVAILABLE)
01550                                 settingsInfo->errorString = _tcsdup(TEXT("Unable to connect to or contact the server, please contact an Administrator or check your network connection and try again"));
01551         }
01552         return authenticated;
01553 }
01554 
01555 
01556 
01557 
01559 // Cldapauth_plusApp
01560 
01561 BEGIN_MESSAGE_MAP(Cldapauth_plusApp, CWinApp)
01562 END_MESSAGE_MAP()
01563 
01564 
01565 // Cldapauth_plusApp construction
01566 Cldapauth_plusApp::Cldapauth_plusApp()
01567 {
01568         // TODO: add construction code here,
01569         // Place all significant initialization in InitInstance
01570 }
01571 
01572 
01573 // The one and only Cldapauth_plusApp object
01574 Cldapauth_plusApp theApp;
01575 
01576 
01577 // Cldapauth_plusApp initialization
01578 
01579 BOOL Cldapauth_plusApp::InitInstance()
01580 {
01581         CWinApp::InitInstance();
01582 
01583         return TRUE;
01584 }
01585 
01586 TCHAR * regReadString(LPCTSTR location)
01587 {
01588     LONG lResult;
01589         HKEY hKey;
01590     DWORD dwBytesRead = 2048;
01591     TCHAR result[2048];
01592     TCHAR *ret;
01593         
01594         lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\pGina\\ldapauth"),0,KEY_QUERY_VALUE,&hKey);
01595     
01596     if(lResult == ERROR_SUCCESS)
01597     {
01598         lResult = RegQueryValueEx(hKey,location,NULL,NULL,(LPBYTE)&result,&dwBytesRead);
01599         
01600         if(lResult == ERROR_SUCCESS)
01601         {
01602             if(dwBytesRead > 0)
01603             {
01604                                 if(!_tcscmp(result,TEXT(""))) // If its just a space
01605                                 {
01606                                     return NULL;                                                                                 
01607                                 }
01608                                 else
01609                                 {
01610                                         ret = (TCHAR *)malloc((sizeof(TCHAR) * dwBytesRead) + 1);
01611                                         ret = _tcsdup(result);
01612                                         RegCloseKey(hKey);
01613                                         return ret;
01614                                 }
01615             }
01616             else
01617             {
01618                 return NULL;
01619             }
01620         }
01621     }
01622     RegCloseKey(hKey);
01623     return NULL;
01624 }
01625 
01626 BOOL regWriteString(LPTSTR value,LPCTSTR location)
01627 {
01628     HKEY hKey;
01629     
01630     if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\pGina\\ldapauth"),0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,NULL) == ERROR_SUCCESS)
01631     {
01632         if(value != NULL)
01633             if(RegSetValueEx(hKey,location,0,REG_SZ,(CONST BYTE *) value, (DWORD)(_tcslen(value)*sizeof(TCHAR))) == ERROR_SUCCESS)
01634             {
01635                 RegFlushKey(hKey);
01636                 RegCloseKey(hKey);
01637                 return true;
01638             }
01639     }
01640     
01641     RegFlushKey(hKey);
01642     RegCloseKey(hKey);
01643     return false;
01644 }
01645 
01646 BOOL regWriteDword(DWORD value,LPCTSTR location)
01647 {
01648     HKEY hKey;
01649     DWORD write;
01650         
01651     write = value;
01652         
01653         if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\pGina\\ldapauth"),0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,  &hKey,NULL) == ERROR_SUCCESS)
01654         if(RegSetValueEx(hKey,location,0,REG_DWORD,(LPBYTE)&write,sizeof(DWORD)) == ERROR_SUCCESS)
01655         {
01656             RegFlushKey(hKey);
01657             RegCloseKey(hKey);
01658             return true;
01659         }
01660     RegFlushKey(hKey);
01661     RegCloseKey(hKey);
01662     return false;
01663 }
01664 
01665 DWORD regReadDword(LPCTSTR location)
01666 {
01667     LONG lResult;
01668         HKEY hKey;
01669     DWORD value = 0;
01670     DWORD size = sizeof(DWORD);
01671 
01672     lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\pGina\\ldapauth"),0,KEY_QUERY_VALUE,&hKey);
01673     
01674     if(lResult == ERROR_SUCCESS)
01675     {
01676         lResult = RegQueryValueEx(hKey,location,NULL,NULL,(LPBYTE)&value,&size);
01677         
01678         if(lResult == ERROR_SUCCESS)
01679         {
01680             RegCloseKey(hKey);
01681             return value;
01682         }
01683     }
01684     RegCloseKey(hKey);
01685     return 0;
01686 }
01687 
01688 void regDelValue(LPCTSTR location)
01689 {
01690         HKEY    hKey;
01691         LONG    lResult;
01692         
01693         lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
01694                                                         _T("SOFTWARE\\pGina\\ldapauth"),
01695                                                         0, KEY_WRITE, &hKey);
01696 
01697         if(lResult == ERROR_SUCCESS)
01698         {
01699                 lResult = RegDeleteValue(hKey,location);
01700                 RegFlushKey(hKey);
01701         }
01702 
01703         RegCloseKey(hKey);
01704 }

Generated on Fri Feb 20 12:03:41 2004 for ldapauth plugin for pGina by doxygen 1.3.5