ldapconnection.cpp 202 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. // LDAP prototypes use char* where they should be using const char *, resulting in lots of spurious warnings
  14. #pragma warning( disable : 4786 )
  15. #ifdef __GNUC__
  16. #pragma GCC diagnostic ignored "-Wwrite-strings"
  17. #endif
  18. #include "permissions.ipp"
  19. #include "aci.ipp"
  20. #include "ldapsecurity.ipp"
  21. #include "jsmartsock.hpp"
  22. #include "jrespool.tpp"
  23. #include "mpbase.hpp"
  24. #include "dautils.hpp"
  25. #include "dasds.hpp"
  26. #undef new
  27. #include <map>
  28. #include <string>
  29. #include <set>
  30. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  31. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  32. #endif
  33. #ifdef _WIN32
  34. #include <lm.h>
  35. #define LdapRename ldap_rename_ext_s
  36. LDAPMessage* (*LdapFirstEntry)(LDAP*, LDAPMessage*) = &ldap_first_entry;
  37. LDAPMessage* (*LdapNextEntry)(LDAP* ld, LDAPMessage* entry) = &ldap_next_entry;
  38. #else
  39. #define LdapRename ldap_rename_s
  40. LDAPMessage* (__stdcall *LdapFirstEntry)(LDAP*, LDAPMessage*) = &ldap_first_message;
  41. LDAPMessage* (__stdcall *LdapNextEntry)(LDAP* ld, LDAPMessage* entry) = &ldap_next_message;
  42. #endif
  43. #define LDAPSEC_MAX_RETRIES 2
  44. #define LDAPSEC_RETRY_WAIT 3
  45. #ifdef _WIN32
  46. #define LDAP_NO_ATTRS "1.1"
  47. #endif
  48. #define PWD_NEVER_EXPIRES (__int64)0x8000000000000000
  49. const char* UserFieldNames[] = { "@id", "@name", "@fullname", "@passwordexpiration" };
  50. extern __declspec(dllimport) const char* getUserFieldNames(UserField field)
  51. {
  52. if (field < UFterm)
  53. return UserFieldNames[field];
  54. return NULL;
  55. }
  56. const char* GroupFieldNames[] = { "@name", "@managedby", "@desc" };
  57. extern __declspec(dllimport) const char* getGroupFieldNames(GroupField field)
  58. {
  59. if (field < GFterm)
  60. return GroupFieldNames[field];
  61. return NULL;
  62. }
  63. const char* ResourceFieldNames[] = { "@name", "@desc" };
  64. extern __declspec(dllimport) const char* getResourceFieldNames(ResourceField field)
  65. {
  66. if (field < RFterm)
  67. return ResourceFieldNames[field];
  68. return NULL;
  69. }
  70. class CSecItemIterator: public CInterfaceOf<ISecItemIterator>
  71. {
  72. IArrayOf<IPropertyTree> attrs;
  73. unsigned index;
  74. public:
  75. CSecItemIterator(IArrayOf<IPropertyTree>& trees)
  76. {
  77. ForEachItemIn(t, trees)
  78. attrs.append(*LINK(&trees.item(t)));
  79. index = 0;
  80. }
  81. virtual ~CSecItemIterator()
  82. {
  83. attrs.kill();
  84. }
  85. bool first()
  86. {
  87. index = 0;
  88. return (attrs.ordinality()!=0);
  89. }
  90. bool next()
  91. {
  92. index++;
  93. return (index<attrs.ordinality());
  94. }
  95. bool isValid()
  96. {
  97. return (index<attrs.ordinality());
  98. }
  99. IPropertyTree & query()
  100. {
  101. return attrs.item(index);
  102. }
  103. };
  104. class CLoadBalancer : public CInterface, implements IInterface
  105. {
  106. private:
  107. StringArray hostArray;
  108. unsigned nextIndex;
  109. Mutex m_mutex;
  110. public:
  111. IMPLEMENT_IINTERFACE
  112. CLoadBalancer(const char* addrlist)
  113. {
  114. char *copyFullText = strdup(addrlist);
  115. char *saveptr;
  116. char *ip = strtok_r(copyFullText, "|", &saveptr);
  117. while (ip != NULL)
  118. {
  119. if (isdigit(*ip))
  120. {
  121. char *dash = strrchr(ip, '-');
  122. if (dash)
  123. {
  124. *dash = 0;
  125. int last = atoi(dash+1);
  126. char *dot = strrchr(ip, '.');
  127. *dot = 0;
  128. int first = atoi(dot+1);
  129. for (int i = first; i <= last; i++)
  130. {
  131. StringBuffer t;
  132. t.append(ip).append('.').append(i);
  133. hostArray.append(t.str());
  134. }
  135. }
  136. else
  137. {
  138. hostArray.append(ip);
  139. }
  140. }
  141. else
  142. {
  143. hostArray.append(ip);
  144. }
  145. ip = strtok_r(NULL, "|", &saveptr);
  146. }
  147. free(copyFullText);
  148. if(hostArray.length() == 0)
  149. {
  150. throw MakeStringException(-1, "No valid ldap server address specified");
  151. }
  152. Owned<IRandomNumberGenerator> random = createRandomNumberGenerator();
  153. random->seed((unsigned)get_cycles_now());
  154. unsigned i = hostArray.ordinality();
  155. while (i > 1)
  156. {
  157. unsigned j = random->next() % i;
  158. i--;
  159. hostArray.swap(i, j);
  160. }
  161. nextIndex = 0;
  162. for(unsigned ind = 0; ind < hostArray.length(); ind++)
  163. {
  164. DBGLOG("Added ldap server %s", hostArray.item(ind));
  165. }
  166. }
  167. virtual ~CLoadBalancer()
  168. {
  169. }
  170. const char* next()
  171. {
  172. unsigned curindex = 0;
  173. {
  174. synchronized block(m_mutex);
  175. curindex = nextIndex;
  176. ++nextIndex %= hostArray.ordinality();
  177. }
  178. return (hostArray.item(curindex));
  179. }
  180. };
  181. inline bool LdapServerDown(int rc)
  182. {
  183. return rc==LDAP_SERVER_DOWN||rc==LDAP_UNAVAILABLE||rc==LDAP_TIMEOUT;
  184. }
  185. class CLdapConfig : public CInterface, implements ILdapConfig
  186. {
  187. private:
  188. LdapServerType m_serverType;
  189. StringAttr m_cfgServerType;//LDAP Server type name (ActiveDirectory, Fedora389, etc)
  190. Owned<IPropertyTree> m_cfg;
  191. Owned<CLoadBalancer> m_ldaphosts;
  192. int m_ldapport;
  193. int m_ldap_secure_port;
  194. StringBuffer m_protocol;
  195. StringBuffer m_basedn;
  196. StringBuffer m_domain;
  197. StringBuffer m_authmethod;
  198. StringBuffer m_user_basedn;
  199. StringBuffer m_group_basedn;
  200. StringBuffer m_resource_basedn;
  201. StringBuffer m_filescope_basedn;
  202. StringBuffer m_workunitscope_basedn;
  203. StringBuffer m_sudoers_basedn;
  204. StringBuffer m_template_name;
  205. StringBuffer m_sysuser;
  206. StringBuffer m_sysuser_commonname;
  207. StringBuffer m_sysuser_password;
  208. StringBuffer m_sysuser_basedn;
  209. bool m_sysuser_specified;
  210. StringBuffer m_sysuser_dn;
  211. int m_maxConnections;
  212. StringBuffer m_sdfieldname;
  213. public:
  214. IMPLEMENT_IINTERFACE
  215. CLdapConfig(IPropertyTree* cfg)
  216. {
  217. int version = LDAP_VERSION3;
  218. ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
  219. m_cfg.set(cfg);
  220. //Check for LDAP Server type in config
  221. m_serverType = LDAPSERVER_UNKNOWN;
  222. m_cfgServerType.set(cfg->queryProp(".//@serverType"));
  223. if (m_cfgServerType.length())
  224. {
  225. if (0 == stricmp(m_cfgServerType, "ActiveDirectory"))
  226. m_serverType = ACTIVE_DIRECTORY;
  227. else if (0 == stricmp(m_cfgServerType, "389DirectoryServer"))//uses iPlanet style ACI
  228. m_serverType = OPEN_LDAP;
  229. else if (0 == stricmp(m_cfgServerType, "OpenLDAP"))
  230. m_serverType = OPEN_LDAP;
  231. else if (0 == stricmp(m_cfgServerType, "Fedora389"))
  232. m_serverType = OPEN_LDAP;
  233. else if (0 == stricmp(m_cfgServerType, "iPlanet"))
  234. m_serverType = IPLANET;
  235. else
  236. throw MakeStringException(-1, "Unknown LDAP serverType '%s' specified",m_cfgServerType.get());
  237. }
  238. else
  239. {
  240. DBGLOG("LDAP serverType not specified, will try to deduce");
  241. }
  242. StringBuffer hostsbuf;
  243. cfg->getProp(".//@ldapAddress", hostsbuf);
  244. if(hostsbuf.length() == 0)
  245. {
  246. throw MakeStringException(-1, "ldapAddress not found in config");
  247. }
  248. m_ldaphosts.setown(new CLoadBalancer(hostsbuf.str()));
  249. cfg->getProp(".//@ldapProtocol", m_protocol);
  250. if(m_protocol.length() == 0)
  251. {
  252. m_protocol.append("ldap");
  253. }
  254. StringBuffer portbuf;
  255. cfg->getProp(".//@ldapPort", portbuf);
  256. if(portbuf.length() == 0)
  257. m_ldapport = 389;
  258. else
  259. m_ldapport = atoi(portbuf.str());
  260. portbuf.clear();
  261. cfg->getProp(".//@ldapSecurePort", portbuf);
  262. if(portbuf.length() == 0)
  263. m_ldap_secure_port = 636;
  264. else
  265. m_ldap_secure_port = atoi(portbuf.str());
  266. StringBuffer hostbuf, dcbuf;
  267. int rc = 0;
  268. getLdapHost(hostbuf);
  269. for(int retries = 0; retries <= LDAPSEC_MAX_RETRIES; retries++)
  270. {
  271. rc = LdapUtils::getServerInfo(hostbuf.str(), m_ldapport, dcbuf, m_serverType, cfg->queryProp(".//@ldapDomain"));
  272. if(!LdapServerDown(rc) || retries > LDAPSEC_MAX_RETRIES)
  273. break;
  274. sleep(LDAPSEC_RETRY_WAIT);
  275. if(retries < LDAPSEC_MAX_RETRIES)
  276. {
  277. DBGLOG("Server %s temporarily unreachable.", hostbuf.str());
  278. // Retrying next ldap sever, might be the same server
  279. hostbuf.clear();
  280. getLdapHost(hostbuf);
  281. DBGLOG("Retrying with %s...", hostbuf.str());
  282. }
  283. }
  284. if(rc != LDAP_SUCCESS)
  285. {
  286. throw MakeStringException(-1, "getServerInfo error - %s", ldap_err2string(rc));
  287. }
  288. const char* basedn = cfg->queryProp(".//@commonBasedn");
  289. if(basedn == NULL || *basedn == '\0')
  290. {
  291. basedn = dcbuf.str();
  292. }
  293. LdapUtils::cleanupDn(basedn, m_basedn);
  294. StringBuffer user_basedn;
  295. cfg->getProp(".//@usersBasedn", user_basedn);
  296. if(user_basedn.length() == 0)
  297. {
  298. throw MakeStringException(-1, "users basedn not found in config");
  299. }
  300. LdapUtils::normalizeDn(user_basedn.str(), m_basedn.str(), m_user_basedn);
  301. StringBuffer group_basedn;
  302. cfg->getProp(".//@groupsBasedn", group_basedn);
  303. if(group_basedn.length() == 0)
  304. {
  305. throw MakeStringException(-1, "groups basedn not found in config");
  306. }
  307. LdapUtils::normalizeDn(group_basedn.str(), m_basedn.str(), m_group_basedn);
  308. StringBuffer dnbuf;
  309. cfg->getProp(".//@modulesBasedn", dnbuf);
  310. if(dnbuf.length() == 0)
  311. cfg->getProp(".//@resourcesBasedn", dnbuf);
  312. if(dnbuf.length() > 0)
  313. LdapUtils::normalizeDn(dnbuf.str(), m_basedn.str(), m_resource_basedn);
  314. dnbuf.clear();
  315. cfg->getProp(".//@filesBasedn", dnbuf);
  316. if(dnbuf.length() > 0)
  317. LdapUtils::normalizeDn(dnbuf.str(), m_basedn.str(), m_filescope_basedn);
  318. dnbuf.clear();
  319. cfg->getProp(".//@workunitsBasedn", dnbuf);
  320. if(dnbuf.length() > 0)
  321. LdapUtils::normalizeDn(dnbuf.str(), m_basedn.str(), m_workunitscope_basedn);
  322. if(m_resource_basedn.length() + m_filescope_basedn.length() + m_workunitscope_basedn.length() == 0)
  323. {
  324. throw MakeStringException(-1, "One of the following basedns need to be defined: modulesBasedn, resourcesBasedn, filesBasedn or workunitScopesBasedn.");
  325. }
  326. dnbuf.clear();
  327. cfg->getProp(".//@sudoersBasedn", dnbuf);
  328. if(dnbuf.length() == 0)
  329. dnbuf.append("ou=SUDOers");
  330. LdapUtils::normalizeDn(dnbuf.str(), m_basedn.str(), m_sudoers_basedn);
  331. cfg->getProp(".//@templateName", m_template_name);
  332. cfg->getProp(".//@authMethod", m_authmethod);
  333. cfg->getProp(".//@ldapDomain", m_domain);
  334. if(m_domain.length() == 0)
  335. {
  336. const char* dptr = strchr(m_basedn.str(), '=');
  337. if(dptr != NULL)
  338. {
  339. dptr++;
  340. while(*dptr != 0 && *dptr != ',')
  341. {
  342. char c = *dptr++;
  343. m_domain.append(c);
  344. }
  345. }
  346. }
  347. m_sysuser_specified = true;
  348. cfg->getProp(".//@systemUser", m_sysuser);
  349. if(m_sysuser.length() == 0)
  350. {
  351. m_sysuser_specified = false;
  352. }
  353. cfg->getProp(".//@systemCommonName", m_sysuser_commonname);
  354. if(m_sysuser_specified && (m_sysuser_commonname.length() == 0))
  355. {
  356. throw MakeStringException(-1, "SystemUser commonname is empty");
  357. }
  358. StringBuffer passbuf;
  359. cfg->getProp(".//@systemPassword", passbuf);
  360. decrypt(m_sysuser_password, passbuf.str());
  361. StringBuffer sysuser_basedn;
  362. cfg->getProp(".//@systemBasedn", sysuser_basedn);
  363. if(sysuser_basedn.length() == 0)
  364. {
  365. if(m_serverType == ACTIVE_DIRECTORY)
  366. LdapUtils::normalizeDn( "cn=Users", m_basedn.str(), m_sysuser_basedn);
  367. else if(m_serverType == IPLANET)
  368. m_sysuser_basedn.append("ou=administrators,ou=topologymanagement,o=netscaperoot");
  369. else if(m_serverType == OPEN_LDAP)
  370. m_sysuser_basedn.append(m_basedn.str());
  371. }
  372. else
  373. {
  374. if(m_serverType == ACTIVE_DIRECTORY)
  375. LdapUtils::normalizeDn(sysuser_basedn.str(), m_basedn.str(), m_sysuser_basedn);
  376. else
  377. m_sysuser_basedn.append(sysuser_basedn.str());
  378. }
  379. if(m_sysuser_specified)
  380. {
  381. if(m_serverType == IPLANET)
  382. m_sysuser_dn.append("uid=").append(m_sysuser.str()).append(",").append(m_sysuser_basedn.str());
  383. else if(m_serverType == ACTIVE_DIRECTORY)
  384. m_sysuser_dn.append("cn=").append(m_sysuser_commonname.str()).append(",").append(m_sysuser_basedn.str());
  385. else if(m_serverType == OPEN_LDAP)
  386. {
  387. if (0==strcmp("Directory Manager",m_sysuser_commonname.str()))
  388. m_sysuser_dn.append("cn=").append(m_sysuser_commonname.str()).append(",").append(m_sysuser_basedn.str());
  389. else
  390. m_sysuser_dn.append("uid=").append(m_sysuser_commonname.str()).append(",").append(m_sysuser_basedn.str()).append(",").append(m_basedn.str());
  391. }
  392. }
  393. m_maxConnections = cfg->getPropInt(".//@maxConnections", DEFAULT_LDAP_POOL_SIZE);
  394. if(m_maxConnections <= 0)
  395. m_maxConnections = DEFAULT_LDAP_POOL_SIZE;
  396. if(m_serverType == ACTIVE_DIRECTORY)
  397. m_sdfieldname.append("ntSecurityDescriptor");
  398. else if(m_serverType == IPLANET)
  399. m_sdfieldname.append("aci");
  400. else if(m_serverType == OPEN_LDAP)
  401. m_sdfieldname.append("aci");
  402. }
  403. virtual LdapServerType getServerType()
  404. {
  405. return m_serverType;
  406. }
  407. virtual const char * getCfgServerType() const
  408. {
  409. return m_cfgServerType.get();
  410. }
  411. virtual const char* getSdFieldName()
  412. {
  413. return m_sdfieldname.str();
  414. }
  415. virtual StringBuffer& getLdapHost(StringBuffer& hostbuf)
  416. {
  417. hostbuf.clear();
  418. try
  419. {
  420. hostbuf.append(m_ldaphosts->next());
  421. }
  422. catch(IException* e)
  423. {
  424. StringBuffer emsg;
  425. e->errorMessage(emsg);
  426. DBGLOG("getLdapHost exception - %s", emsg.str());
  427. e->Release();
  428. }
  429. catch(...)
  430. {
  431. DBGLOG("getLdapHost unknown exception");
  432. }
  433. return hostbuf;
  434. }
  435. virtual void markDown(const char* ldaphost)
  436. {
  437. //SocketEndpoint ep(ldaphost, 0);
  438. //m_ldaphosts->setStatus(ep, false);
  439. }
  440. virtual int getLdapPort()
  441. {
  442. return m_ldapport;
  443. }
  444. virtual int getLdapSecurePort()
  445. {
  446. return m_ldap_secure_port;
  447. }
  448. virtual const char* getProtocol()
  449. {
  450. return m_protocol.str();
  451. }
  452. virtual const char* getBasedn()
  453. {
  454. return m_basedn.str();
  455. }
  456. virtual const char* getDomain()
  457. {
  458. return m_domain.str();
  459. }
  460. virtual const char* getAuthMethod()
  461. {
  462. return m_authmethod.str();
  463. }
  464. virtual const char* getUserBasedn()
  465. {
  466. return m_user_basedn.str();
  467. }
  468. virtual const char* getGroupBasedn()
  469. {
  470. return m_group_basedn.str();
  471. }
  472. virtual const char* getResourceBasedn(SecResourceType rtype)
  473. {
  474. if(rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE)
  475. return m_resource_basedn.str();
  476. else if(rtype == RT_FILE_SCOPE)
  477. return m_filescope_basedn.str();
  478. else if(rtype == RT_WORKUNIT_SCOPE)
  479. return m_workunitscope_basedn.str();
  480. else if(rtype == RT_SUDOERS)
  481. return m_sudoers_basedn.str();
  482. else
  483. return m_resource_basedn.str();
  484. }
  485. virtual const char* getTemplateName()
  486. {
  487. return m_template_name.str();
  488. }
  489. virtual const char* getSysUser()
  490. {
  491. return m_sysuser.str();
  492. }
  493. virtual const char* getSysUserDn()
  494. {
  495. return m_sysuser_dn.str();
  496. }
  497. virtual const char* getSysUserCommonName()
  498. {
  499. return m_sysuser_commonname.str();
  500. }
  501. virtual const char* getSysUserPassword()
  502. {
  503. return m_sysuser_password.str();
  504. }
  505. virtual const char* getSysUserBasedn()
  506. {
  507. return m_sysuser_basedn.str();
  508. }
  509. virtual bool sysuserSpecified()
  510. {
  511. return m_sysuser_specified;
  512. }
  513. virtual int getMaxConnections()
  514. {
  515. return m_maxConnections;
  516. }
  517. // For now, only sets default resourcebasedn, since it's only used by ESP services
  518. virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype)
  519. {
  520. if(rbasedn == NULL || rbasedn[0] == '\0')
  521. return;
  522. if(rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE)
  523. {
  524. LdapUtils::normalizeDn(rbasedn, m_basedn.str(), m_resource_basedn);
  525. }
  526. else if(rtype == RT_FILE_SCOPE)
  527. {
  528. LdapUtils::normalizeDn(rbasedn, m_basedn.str(), m_filescope_basedn);
  529. }
  530. else if(rtype == RT_WORKUNIT_SCOPE)
  531. {
  532. LdapUtils::normalizeDn(rbasedn, m_basedn.str(), m_workunitscope_basedn);
  533. }
  534. else
  535. {
  536. LdapUtils::normalizeDn(rbasedn, m_basedn.str(), m_resource_basedn);
  537. }
  538. }
  539. virtual void getDefaultSysUserBasedn(StringBuffer& sysuser_basedn)
  540. {
  541. if(m_serverType == ACTIVE_DIRECTORY)
  542. LdapUtils::normalizeDn( "cn=Users", m_basedn.str(), sysuser_basedn);
  543. else if(m_serverType == IPLANET)
  544. sysuser_basedn.append("ou=administrators,ou=topologymanagement,o=netscaperoot");
  545. }
  546. };
  547. class CLdapConnection : public CInterface, implements ILdapConnection
  548. {
  549. private:
  550. LDAP *m_ld;
  551. Owned<CLdapConfig> m_ldapconfig;
  552. time_t m_lastaccesstime;
  553. bool m_connected;
  554. public:
  555. IMPLEMENT_IINTERFACE
  556. CLdapConnection(CLdapConfig* ldapconfig)
  557. {
  558. m_ldapconfig.setown(LINK(ldapconfig));
  559. m_ld = NULL;
  560. m_connected = false;
  561. m_lastaccesstime = 0;
  562. }
  563. ~CLdapConnection()
  564. {
  565. if(m_ld != NULL)
  566. {
  567. LDAP_UNBIND(m_ld);
  568. }
  569. }
  570. virtual int connect(const char* ldapserver, const char* protocol)
  571. {
  572. if(!ldapserver || *ldapserver == '\0')
  573. return -1;
  574. m_ld = LdapUtils::LdapInit(protocol, ldapserver, m_ldapconfig->getLdapPort(), m_ldapconfig->getLdapSecurePort());
  575. int rc = LDAP_SUCCESS;
  576. if(m_ldapconfig->sysuserSpecified())
  577. rc = LdapUtils::LdapBind(m_ld, m_ldapconfig->getDomain(), m_ldapconfig->getSysUser(), m_ldapconfig->getSysUserPassword(), m_ldapconfig->getSysUserDn(), m_ldapconfig->getServerType(), m_ldapconfig->getAuthMethod());
  578. else
  579. rc = LdapUtils::LdapBind(m_ld, m_ldapconfig->getDomain(), NULL, NULL, NULL, m_ldapconfig->getServerType(), m_ldapconfig->getAuthMethod());
  580. if(rc == LDAP_SUCCESS)
  581. {
  582. time(&m_lastaccesstime);
  583. m_connected = true;
  584. const char * ldap = NULL;
  585. switch (m_ldapconfig->getServerType())
  586. {
  587. case ACTIVE_DIRECTORY:
  588. ldap = "Active Directory";
  589. break;
  590. case OPEN_LDAP:
  591. ldap = "OpenLDAP";
  592. break;
  593. case IPLANET:
  594. ldap = "iplanet";
  595. break;
  596. default:
  597. ldap = "unknown";
  598. break;
  599. }
  600. DBGLOG("Connected to '%s' LdapServer %s using protocol %s", ldap, ldapserver, protocol);
  601. }
  602. else
  603. {
  604. DBGLOG("LDAP: sysuser bind failed - %s", ldap_err2string(rc));
  605. LDAP_UNBIND(m_ld);
  606. m_ld = NULL;
  607. }
  608. return rc;
  609. }
  610. virtual bool connect(bool force_ssl = false)
  611. {
  612. StringBuffer hostbuf;
  613. m_ldapconfig->getLdapHost(hostbuf);
  614. int rc = LDAP_SERVER_DOWN;
  615. const char* proto;
  616. if(force_ssl)
  617. proto = "ldaps";
  618. else
  619. proto = m_ldapconfig->getProtocol();
  620. for(int retries = 0; retries <= LDAPSEC_MAX_RETRIES; retries++)
  621. {
  622. rc = connect(hostbuf.str(), proto);
  623. if(!LdapServerDown(rc) || retries > LDAPSEC_MAX_RETRIES)
  624. break;
  625. sleep(LDAPSEC_RETRY_WAIT);
  626. if(retries < LDAPSEC_MAX_RETRIES)
  627. DBGLOG("Server temporarily unreachable, retrying ...");
  628. // Retrying next ldap sever, might be the same server
  629. hostbuf.clear();
  630. m_ldapconfig->getLdapHost(hostbuf);
  631. }
  632. if(rc == LDAP_SERVER_DOWN)
  633. {
  634. StringBuffer dc;
  635. LdapUtils::getDcName(m_ldapconfig->getDomain(), dc);
  636. if(dc.length() > 0)
  637. {
  638. WARNLOG("Using automatically obtained LDAP Server %s", dc.str());
  639. rc = connect(dc.str(), proto);
  640. }
  641. }
  642. if(rc == LDAP_SUCCESS)
  643. return true;
  644. else
  645. return false;
  646. }
  647. virtual LDAP* getLd()
  648. {
  649. return m_ld;
  650. }
  651. virtual bool validate()
  652. {
  653. time_t now;
  654. time(&now);
  655. if(!m_connected)
  656. return connect();
  657. else if(now - m_lastaccesstime <= 300)
  658. return true;
  659. else
  660. {
  661. bool ok = false;
  662. LDAPMessage* msg = NULL;
  663. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  664. int err = ldap_search_ext_s(m_ld, NULL, LDAP_SCOPE_BASE, "objectClass=*", NULL, 0, NULL, NULL, &timeOut, 1, &msg);
  665. if(err == LDAP_SUCCESS)
  666. {
  667. ok = true;
  668. }
  669. if(msg != NULL)
  670. ldap_msgfree(msg);
  671. if(!ok)
  672. {
  673. if(m_ld != NULL)
  674. {
  675. LDAP_UNBIND(m_ld);
  676. m_ld = NULL;
  677. m_connected = false;
  678. }
  679. DBGLOG("cached connection invalid, creating a new connection");
  680. return connect();
  681. }
  682. else
  683. {
  684. time(&m_lastaccesstime);
  685. }
  686. }
  687. return true;
  688. }
  689. };
  690. class CLdapConnectionPool : public CInterface, implements ILdapConnectionPool
  691. {
  692. private:
  693. int m_maxsize;
  694. int m_currentsize;
  695. IArrayOf<ILdapConnection> m_connections;
  696. Monitor m_monitor;
  697. Owned<CLdapConfig> m_ldapconfig;
  698. public:
  699. IMPLEMENT_IINTERFACE
  700. CLdapConnectionPool(CLdapConfig* ldapconfig)
  701. {
  702. m_ldapconfig.setown(LINK(ldapconfig));
  703. m_maxsize = m_ldapconfig->getMaxConnections();
  704. m_currentsize = 0;
  705. // Set LDAP version to 3
  706. int version = LDAP_VERSION3;
  707. ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
  708. }
  709. virtual ILdapConnection* getConnection()
  710. {
  711. synchronized block(m_monitor);
  712. ForEachItemIn(x, m_connections)
  713. {
  714. CLdapConnection* curcon = (CLdapConnection*)&(m_connections.item(x));
  715. if(curcon != NULL && !curcon->IsShared())
  716. {
  717. //PrintLog("Reusing an LDAP connection");
  718. if(curcon->validate())
  719. return LINK(curcon);
  720. else
  721. throw MakeStringException(-1, "Connecting/authenticating to ldap server in re-validation failed");
  722. }
  723. }
  724. //PrintLog("Creating new connection");
  725. CLdapConnection* newcon = new CLdapConnection(m_ldapconfig.get());
  726. if(newcon != NULL)
  727. {
  728. if(!newcon->connect())
  729. {
  730. throw MakeStringException(-1, "Connecting/authenticating to ldap server failed");
  731. }
  732. if(m_currentsize <= m_maxsize)
  733. {
  734. m_connections.append(*newcon);
  735. m_currentsize++;
  736. return LINK(newcon);
  737. }
  738. else
  739. {
  740. return newcon;
  741. }
  742. }
  743. else
  744. {
  745. throw MakeStringException(-1, "Failed to create new ldap connection");
  746. }
  747. }
  748. virtual ILdapConnection* getSSLConnection()
  749. {
  750. CLdapConnection* newcon = new CLdapConnection(m_ldapconfig.get());
  751. if(newcon != NULL)
  752. {
  753. if(!newcon->connect(true))
  754. {
  755. throw MakeStringException(-1, "Connecting/authenticating to ldap server via ldaps failed");
  756. }
  757. return newcon;
  758. }
  759. else
  760. {
  761. throw MakeStringException(-1, "Failed to create new ldap connection");
  762. }
  763. }
  764. };
  765. #define LDAP_CONNECTION_TIMEOUT INFINITE
  766. //------------ New Connection Pool Implementation ------------//
  767. class CLdapConnectionManager : public CInterface, implements IResourceFactory<CLdapConnection>
  768. {
  769. Owned<CLdapConfig> m_ldapconfig;
  770. public:
  771. IMPLEMENT_IINTERFACE;
  772. CLdapConnectionManager(CLdapConfig* ldapconfig)
  773. {
  774. m_ldapconfig.setown(LINK(ldapconfig));
  775. }
  776. CLdapConnection* createResource()
  777. {
  778. CLdapConnection* newcon = new CLdapConnection(m_ldapconfig.get());
  779. if(newcon != NULL)
  780. {
  781. if(!newcon->connect())
  782. {
  783. throw MakeStringException(-1, "Connecting/authenticating to ldap server failed");
  784. }
  785. return newcon;
  786. }
  787. else
  788. {
  789. throw MakeStringException(-1, "Failed to create new ldap connection");
  790. }
  791. }
  792. };
  793. class CLdapConnectionPool2 : public CInterface, implements ILdapConnectionPool
  794. {
  795. private:
  796. int m_maxsize;
  797. Owned<CLdapConfig> m_ldapconfig;
  798. Owned<CResourcePool<CLdapConnection> > m_connections;
  799. public:
  800. IMPLEMENT_IINTERFACE
  801. CLdapConnectionPool2(CLdapConfig* ldapconfig)
  802. {
  803. m_ldapconfig.setown(LINK(ldapconfig));
  804. m_maxsize = m_ldapconfig->getMaxConnections();
  805. // Set LDAP version to 3
  806. int version = LDAP_VERSION3;
  807. ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
  808. m_connections.setown(new CResourcePool<CLdapConnection>);
  809. Owned<CLdapConnectionManager> poolMgr = new CLdapConnectionManager(ldapconfig);
  810. m_connections->init(m_maxsize, poolMgr.get());
  811. }
  812. virtual ILdapConnection* getConnection()
  813. {
  814. Owned<CLdapConnection> con;
  815. try
  816. {
  817. con.setown(m_connections->get(LDAP_CONNECTION_TIMEOUT));
  818. }
  819. catch(IException* e)
  820. {
  821. StringBuffer emsg;
  822. e->errorMessage(emsg);
  823. DBGLOG("getConnection exception - %s", emsg.str());
  824. e->Release();
  825. }
  826. catch(...)
  827. {
  828. DBGLOG("getConnection unknown exception");
  829. }
  830. if(con.get())
  831. {
  832. if(con->validate())
  833. return con.getLink();
  834. else
  835. throw MakeStringException(-1, "Connecting/authenticating to ldap server in re-validation failed");
  836. }
  837. else
  838. throw MakeStringException(-1, "Failed to get an LDAP Connection.");
  839. }
  840. virtual ILdapConnection* getSSLConnection()
  841. {
  842. CLdapConnection* newcon = new CLdapConnection(m_ldapconfig.get());
  843. if(newcon != NULL)
  844. {
  845. if(!newcon->connect(true))
  846. {
  847. throw MakeStringException(-1, "Connecting/authenticating to ldap server via ldaps failed");
  848. }
  849. return newcon;
  850. }
  851. else
  852. {
  853. throw MakeStringException(-1, "Failed to create new ldap connection");
  854. }
  855. }
  856. };
  857. struct ltstr
  858. {
  859. bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; }
  860. };
  861. //--------------------------------------------
  862. // This helper class ensures memory allocate by calls
  863. // to ldap_first_attribute/ldap_next_attribute gets freed
  864. //--------------------------------------------
  865. class CLDAPGetAttributesWrapper
  866. {
  867. private:
  868. LDAP * ld;
  869. LDAPMessage * entry;
  870. BerElement * elem;
  871. char * attribute;
  872. public:
  873. CLDAPGetAttributesWrapper(LDAP * _ld, LDAPMessage * _entry)
  874. : ld(_ld), entry(_entry)
  875. {
  876. elem = NULL;
  877. attribute = NULL;
  878. }
  879. ~CLDAPGetAttributesWrapper()
  880. {
  881. if (attribute)
  882. ldap_memfree(attribute);
  883. if (elem)
  884. ber_free(elem, 0);
  885. }
  886. inline char * getFirst()
  887. {
  888. return attribute = ldap_first_attribute(ld, entry, &elem);
  889. }
  890. inline char * getNext()
  891. {
  892. if (attribute)
  893. ldap_memfree(attribute);
  894. return attribute = ldap_next_attribute(ld, entry, elem);
  895. }
  896. };
  897. class CLDAPMessage
  898. {
  899. public:
  900. LDAPMessage *msg;
  901. CLDAPMessage() { msg = NULL; }
  902. ~CLDAPMessage() { ldapMsgFree(); }
  903. inline void ldapMsgFree() { if (msg) { ldap_msgfree(msg); msg = NULL;} }
  904. inline operator LDAPMessage *() const { return msg; }
  905. };
  906. //------------------------------------------------------
  907. // class CPagedLDAPSearch
  908. //
  909. // Performs a "paged" LDAP search, which allows for
  910. // searching when there are over 1000 matching entries. Also
  911. // works when there are less than 1000, but not as efficient as
  912. // simply calling ldap_search_ext_s()
  913. //------------------------------------------------------
  914. #define MAX_ENTRIES 1000
  915. class CPagedLDAPSearch
  916. {
  917. private:
  918. LDAP * m_pLdapConn;
  919. char * m_pszDN;
  920. unsigned long m_scope;
  921. char * m_pszFilter;
  922. char * * m_pszAttrs;
  923. bool m_morePages;
  924. struct berval * m_pCookie;
  925. LDAPMessage * m_pPageEntry;
  926. LDAPMessage * m_pPageBlock;
  927. //local helper class, ensures ldap Page Control memory freed
  928. class CPageControlMemWrapper
  929. {
  930. LDAPControl * m_pageControl;
  931. LDAPControl ** m_returnedCtrls;
  932. public:
  933. CPageControlMemWrapper() { m_pageControl = NULL; m_returnedCtrls = NULL; }
  934. void setPageControl(LDAPControl * _pageCtrl) { m_pageControl = _pageCtrl; }
  935. void setRetControls(LDAPControl ** _retCtrls) { m_returnedCtrls = _retCtrls; }
  936. virtual ~CPageControlMemWrapper()
  937. {
  938. if (m_pageControl)
  939. ldap_control_free(m_pageControl);
  940. if (m_returnedCtrls)
  941. ldap_controls_free(m_returnedCtrls);
  942. }
  943. };
  944. //---------------------------------------------------
  945. // Request next page of search results
  946. //---------------------------------------------------
  947. bool requestNextPage()
  948. {
  949. if (!m_morePages)
  950. return false;
  951. CPageControlMemWrapper pageCtrlMem;
  952. try
  953. {
  954. LDAPControl * pageControl = NULL;
  955. int rc = ldap_create_page_control(m_pLdapConn, MAX_ENTRIES, m_pCookie, false, &pageControl);//cookie gets set on first call to ldap_parse_page_control()
  956. if (rc != LDAP_SUCCESS)
  957. {
  958. int err = GetLastError();
  959. throw MakeStringException(-1, "ldap_create_page_control failed with 0x%x (%s)",err, ldap_err2string( err ));
  960. }
  961. pageCtrlMem.setPageControl(pageControl);
  962. LDAPControl * svrCtrls[] = { pageControl, NULL };
  963. if (m_pPageBlock)
  964. ldap_msgfree(m_pPageBlock);
  965. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  966. rc = ldap_search_ext_s(m_pLdapConn, m_pszDN, m_scope, m_pszFilter, m_pszAttrs, 0, svrCtrls, NULL, &timeOut, 0, &m_pPageBlock);
  967. if (rc != LDAP_SUCCESS)
  968. {
  969. int err = GetLastError();
  970. if (err && rc != LDAP_PARTIAL_RESULTS)//389DirectoryServer sometimes returns rc, but GetLastError returns 0. In this scenario continuing the query succeeds
  971. {
  972. if (m_pCookie)
  973. {
  974. ber_bvfree(m_pCookie);
  975. m_pCookie = NULL;
  976. }
  977. throw MakeStringException(-1, "ldap_search_ext_s failed with 0x%x (%s)",err, ldap_err2string( err ));
  978. }
  979. }
  980. int l_errcode;
  981. LDAPControl ** returnedCtrls = NULL;
  982. rc = ldap_parse_result(m_pLdapConn, m_pPageBlock, &l_errcode, NULL, NULL, NULL, &returnedCtrls, false);
  983. if (m_pCookie)
  984. {
  985. ber_bvfree(m_pCookie);
  986. m_pCookie = NULL;
  987. }
  988. if (rc != LDAP_SUCCESS)
  989. {
  990. int err = GetLastError();
  991. throw MakeStringException(-1, "ldap_parse_result failed with 0x%x (%s)",err, ldap_err2string( err ));
  992. }
  993. pageCtrlMem.setRetControls(returnedCtrls);
  994. int totCount;
  995. rc = ldap_parse_page_control(m_pLdapConn, returnedCtrls, &totCount, &m_pCookie);//sets cookie for next call to ldap_create_page_control()
  996. if (rc != LDAP_SUCCESS)
  997. {
  998. int err = GetLastError();
  999. throw MakeStringException(-1, "ldap_parse_page_control failed with 0x%x (%s)",err, ldap_err2string( err ));
  1000. }
  1001. if (!(m_pCookie && m_pCookie->bv_val != NULL && (strlen(m_pCookie->bv_val) > 0)))
  1002. m_morePages = false;
  1003. }
  1004. catch(IException* e)
  1005. {
  1006. StringBuffer emsg;
  1007. e->errorMessage(emsg);
  1008. throw MakeStringException(-1, "LDAP Paged Search - %s", emsg.str());
  1009. }
  1010. catch(...)
  1011. {
  1012. throw MakeStringException(-1, "Unknown Exception calling LDAP Paged Search");
  1013. }
  1014. return true;
  1015. }
  1016. public:
  1017. CPagedLDAPSearch(LDAP* _pLdapConn, char * _pszDN, unsigned long _scope, char * _pszFilter, char * _pszAttrs[])
  1018. {
  1019. m_pLdapConn =_pLdapConn;
  1020. m_pszDN = _pszDN;
  1021. m_scope = _scope;
  1022. m_pszFilter = _pszFilter;
  1023. m_pszAttrs = _pszAttrs;
  1024. m_pCookie = NULL;
  1025. m_morePages = true;
  1026. m_pPageEntry = NULL;
  1027. m_pPageBlock = NULL;
  1028. }
  1029. virtual ~CPagedLDAPSearch()
  1030. {
  1031. if (m_pPageBlock)
  1032. ldap_msgfree(m_pPageBlock);
  1033. if (m_pCookie)
  1034. ber_bvfree(m_pCookie);
  1035. }
  1036. //---------------------------------------------------
  1037. // Returns the count of the matching DN/filter/scope entries
  1038. //---------------------------------------------------
  1039. unsigned countEntries()
  1040. {
  1041. unsigned count = 0;
  1042. while (requestNextPage())
  1043. count += ldap_count_entries(m_pLdapConn, m_pPageBlock);
  1044. return count;
  1045. }
  1046. //---------------------------------------------------
  1047. // Get the first/next entry
  1048. // Returns NULL when no more
  1049. //---------------------------------------------------
  1050. LDAPMessage * getFirstEntry()
  1051. {
  1052. if (!requestNextPage())
  1053. {
  1054. m_morePages = false;
  1055. return NULL;
  1056. }
  1057. return getNextEntry();
  1058. }
  1059. LDAPMessage * getNextEntry()
  1060. {
  1061. if (!m_pPageEntry)
  1062. m_pPageEntry = LdapFirstEntry(m_pLdapConn, m_pPageBlock);
  1063. else
  1064. m_pPageEntry = LdapNextEntry(m_pLdapConn, m_pPageEntry);
  1065. if (!m_pPageEntry)
  1066. {
  1067. if (!requestNextPage())
  1068. return NULL;
  1069. m_pPageEntry = LdapFirstEntry(m_pLdapConn, m_pPageBlock);
  1070. }
  1071. return m_pPageEntry;
  1072. }
  1073. };
  1074. static CriticalSection mpaCrit;
  1075. static __int64 getMaxPwdAge(Owned<ILdapConnectionPool> _conns, const char * _baseDN)
  1076. {
  1077. static time_t lastPwdAgeCheck = 0;
  1078. static __int64 maxPwdAge = PWD_NEVER_EXPIRES;
  1079. #define HOURLY ((time_t)(60*60*1000))
  1080. CriticalBlock block(mpaCrit);
  1081. if (lastPwdAgeCheck != 0 && (((msTick() - lastPwdAgeCheck) < HOURLY)))//in case it was retrieved whilst this thread blocked
  1082. return maxPwdAge;
  1083. DBGLOG("Retrieving LDAP 'maxPwdAge'");
  1084. char* attrs[] = {"maxPwdAge", NULL};
  1085. CLDAPMessage searchResult;
  1086. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1087. Owned<ILdapConnection> lconn = _conns->getConnection();
  1088. LDAP* sys_ld = ((CLdapConnection*)lconn.get())->getLd();
  1089. int result = ldap_search_ext_s(sys_ld, (char*)_baseDN, LDAP_SCOPE_BASE, NULL,
  1090. attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg);
  1091. if(result != LDAP_SUCCESS)
  1092. {
  1093. DBGLOG("ldap_search_ext_s error: %s, when searching maxPwdAge", ldap_err2string( result ));
  1094. return 0;
  1095. }
  1096. unsigned entries = ldap_count_entries(sys_ld, searchResult);
  1097. if(entries == 0)
  1098. {
  1099. DBGLOG("ldap_search_ext_s error: Could not find maxPwdAge");
  1100. return 0;
  1101. }
  1102. maxPwdAge = 0;
  1103. CLDAPGetValuesLenWrapper vals(sys_ld, searchResult.msg, "maxPwdAge");
  1104. if (vals.hasValues())
  1105. {
  1106. const char *val = vals.queryCharValue(0);
  1107. if (val && *val)
  1108. {
  1109. if (*val == '-')
  1110. ++val;
  1111. for (int x=0; val[x]; x++)
  1112. maxPwdAge = maxPwdAge * 10 + ( (int)val[x] - '0');
  1113. }
  1114. }
  1115. else
  1116. maxPwdAge = PWD_NEVER_EXPIRES;
  1117. lastPwdAgeCheck = msTick();
  1118. return maxPwdAge;
  1119. }
  1120. class CLdapClient : public CInterface, implements ILdapClient
  1121. {
  1122. private:
  1123. Owned<ILdapConnectionPool> m_connections;
  1124. IPermissionProcessor* m_pp;
  1125. //int m_defaultFileScopePermission;
  1126. //int m_defaultWorkunitScopePermission;
  1127. Owned<CLdapConfig> m_ldapconfig;
  1128. StringBuffer m_pwscheme;
  1129. bool m_domainPwdsNeverExpire;//no domain policy for password expiration
  1130. public:
  1131. IMPLEMENT_IINTERFACE
  1132. CLdapClient(IPropertyTree* cfg)
  1133. {
  1134. m_ldapconfig.setown(new CLdapConfig(cfg));
  1135. if(cfg && cfg->getPropBool("@useRealConnectionPool", false))
  1136. m_connections.setown(new CLdapConnectionPool2(m_ldapconfig.get()));
  1137. else
  1138. m_connections.setown(new CLdapConnectionPool(m_ldapconfig.get()));
  1139. m_pp = NULL;
  1140. //m_defaultFileScopePermission = -2;
  1141. //m_defaultWorkunitScopePermission = -2;
  1142. }
  1143. virtual void init(IPermissionProcessor* pp)
  1144. {
  1145. m_pp = pp;
  1146. if(m_ldapconfig->getServerType() == OPEN_LDAP)
  1147. {
  1148. try
  1149. {
  1150. addDC(m_ldapconfig->getBasedn());
  1151. }
  1152. catch(...)
  1153. {
  1154. }
  1155. try
  1156. {
  1157. addGroup("Directory Administrators", NULL, NULL, m_ldapconfig->getBasedn());
  1158. }
  1159. catch(...)
  1160. {
  1161. }
  1162. }
  1163. createLdapBasedn(NULL, m_ldapconfig->getResourceBasedn(RT_DEFAULT), PT_DEFAULT);
  1164. createLdapBasedn(NULL, m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE), PT_DEFAULT);
  1165. createLdapBasedn(NULL, m_ldapconfig->getResourceBasedn(RT_WORKUNIT_SCOPE), PT_DEFAULT);
  1166. createLdapBasedn(NULL, m_ldapconfig->getResourceBasedn(RT_SUDOERS), PT_DEFAULT);
  1167. createLdapBasedn(NULL, m_ldapconfig->getUserBasedn(), PT_DEFAULT);
  1168. createLdapBasedn(NULL, m_ldapconfig->getGroupBasedn(), PT_DEFAULT);
  1169. }
  1170. virtual LdapServerType getServerType()
  1171. {
  1172. return m_ldapconfig->getServerType();
  1173. }
  1174. virtual ILdapConfig* getLdapConfig()
  1175. {
  1176. return m_ldapconfig.get();
  1177. }
  1178. virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype)
  1179. {
  1180. m_ldapconfig->setResourceBasedn(rbasedn, rtype);
  1181. createLdapBasedn(NULL, m_ldapconfig->getResourceBasedn(rtype), PT_DEFAULT);
  1182. }
  1183. void calcPWExpiry(CDateTime &dt, unsigned len, char * val)
  1184. {
  1185. __int64 time = 0;
  1186. for (unsigned x=0; x < len; x++)
  1187. time = time * 10 + ( (int)val[x] - '0');
  1188. time += getMaxPwdAge(m_connections,(char*)m_ldapconfig->getBasedn() );
  1189. dt.setFromFILETIME(time);
  1190. dt.adjustTime(dt.queryUtcToLocalDelta());
  1191. }
  1192. virtual bool authenticate(ISecUser& user)
  1193. {
  1194. {
  1195. char *attribute;
  1196. user.setAuthenticateStatus(AS_UNEXPECTED_ERROR);//assume the worst
  1197. const char* username = user.getName();
  1198. const char* password = user.credentials().getPassword();
  1199. if(!username || !*username || !password || !*password)
  1200. return false;
  1201. if (getMaxPwdAge(m_connections,(char*)m_ldapconfig->getBasedn()) != PWD_NEVER_EXPIRES)
  1202. m_domainPwdsNeverExpire = false;
  1203. else
  1204. m_domainPwdsNeverExpire = true;
  1205. const char* sysuser = m_ldapconfig->getSysUser();
  1206. bool sysUser = false;
  1207. if(sysuser && *sysuser && (strcmp(username, sysuser) == 0))
  1208. {
  1209. if(strcmp(password, m_ldapconfig->getSysUserPassword()) == 0)
  1210. {
  1211. user.setFullName(m_ldapconfig->getSysUserCommonName());
  1212. user.setAuthenticateStatus(AS_AUTHENTICATED);
  1213. if (m_ldapconfig->getServerType() != ACTIVE_DIRECTORY)
  1214. return true;
  1215. sysUser = true;
  1216. }
  1217. else
  1218. {
  1219. user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
  1220. return false;
  1221. }
  1222. }
  1223. StringBuffer filter;
  1224. // Retrieve user's dn with system connection
  1225. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1226. filter.append("sAMAccountName=");
  1227. else
  1228. filter.append("uid=");
  1229. filter.append(username);
  1230. char* attrs[] = {"cn", "userAccountControl", "pwdLastSet", "givenName", "sn", NULL};
  1231. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1232. LDAP* sys_ld = ((CLdapConnection*)lconn.get())->getLd();
  1233. CLDAPMessage searchResult;
  1234. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1235. int result = ldap_search_ext_s(sys_ld,
  1236. (char*)m_ldapconfig->getUserBasedn(), //distinguished name of the entry at which to start the search
  1237. LDAP_SCOPE_SUBTREE,
  1238. (char*)filter.str(), //search filter
  1239. attrs,
  1240. 0, //attribute types and values are to be returned, nonzero if only types are required
  1241. NULL,
  1242. NULL,
  1243. &timeOut,
  1244. LDAP_NO_LIMIT,
  1245. &searchResult.msg);
  1246. if(result != LDAP_SUCCESS)
  1247. {
  1248. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( result ), filter.str(), m_ldapconfig->getUserBasedn());
  1249. return false;
  1250. }
  1251. unsigned entries = ldap_count_entries(sys_ld, searchResult);
  1252. if(entries == 0)
  1253. {
  1254. searchResult.ldapMsgFree();
  1255. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1256. result = ldap_search_ext_s(sys_ld, (char*)m_ldapconfig->getSysUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg);
  1257. if(result != LDAP_SUCCESS)
  1258. {
  1259. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( result ), filter.str(), m_ldapconfig->getSysUserBasedn());
  1260. user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
  1261. return false;
  1262. }
  1263. entries = ldap_count_entries(sys_ld, searchResult);
  1264. if(entries == 0)
  1265. {
  1266. DBGLOG("LDAP: User %s not found", username);
  1267. user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
  1268. return false;
  1269. }
  1270. }
  1271. LDAPMessage *entry = LdapFirstEntry(sys_ld, searchResult);
  1272. if(entry == NULL)
  1273. {
  1274. DBGLOG("LDAP: Can't find entry for user %s", username);
  1275. return false;
  1276. }
  1277. bool accountPwdNeverExpires = false;
  1278. CLDAPGetAttributesWrapper atts(sys_ld, searchResult);
  1279. for ( attribute = atts.getFirst();
  1280. attribute != NULL;
  1281. attribute = atts.getNext())
  1282. {
  1283. if(stricmp(attribute, "cn") == 0)
  1284. {
  1285. CLDAPGetValuesLenWrapper vals(sys_ld, entry, attribute);
  1286. if (vals.hasValues())
  1287. user.setFullName(vals.queryCharValue(0));
  1288. }
  1289. else if((stricmp(attribute, "givenName") == 0))
  1290. {
  1291. CLDAPGetValuesLenWrapper vals(sys_ld, entry, attribute);
  1292. if (vals.hasValues())
  1293. user.setFirstName(vals.queryCharValue(0));
  1294. }
  1295. else if((stricmp(attribute, "sn") == 0))
  1296. {
  1297. CLDAPGetValuesLenWrapper vals(sys_ld, entry, attribute);
  1298. if (vals.hasValues())
  1299. user.setLastName(vals.queryCharValue(0));
  1300. }
  1301. else if((stricmp(attribute, "userAccountControl") == 0))
  1302. {
  1303. //UF_DONT_EXPIRE_PASSWD 0x10000
  1304. CLDAPGetValuesLenWrapper vals(sys_ld, entry, attribute);
  1305. if (vals.hasValues())
  1306. if (atoi((char*)vals.queryCharValue(0)) & 0x10000)//this can be true at the account level, even if domain policy requires password
  1307. accountPwdNeverExpires = true;
  1308. }
  1309. else if((stricmp(attribute, "pwdLastSet") == 0))
  1310. {
  1311. /*pwdLastSet is the date and time that the password for this account was last changed. This
  1312. value is stored as a large integer that represents the number of 100 nanosecond intervals
  1313. since January 1, 1601 (UTC), also known as a FILETIME value. If this value is set
  1314. to 0 and the User-Account-Control attribute does not contain the UF_DONT_EXPIRE_PASSWD
  1315. flag, then the user must set the password at the next logon.
  1316. */
  1317. CLDAPGetValuesLenWrapper valsLen(sys_ld, entry, attribute);
  1318. if (valsLen.hasValues())
  1319. {
  1320. CDateTime expiry;
  1321. if (!m_domainPwdsNeverExpire && !accountPwdNeverExpires)
  1322. {
  1323. char * val = (char*)valsLen.queryCharValue(0);
  1324. calcPWExpiry(expiry, (unsigned)strlen(val), val);
  1325. }
  1326. else
  1327. {
  1328. expiry.clear();
  1329. DBGLOG("LDAP: Password never expires for user %s", username);
  1330. }
  1331. user.setPasswordExpiration(expiry);
  1332. }
  1333. }
  1334. }
  1335. char *userdn = ldap_get_dn(sys_ld, entry);
  1336. if(userdn == NULL || strlen(userdn) == 0)
  1337. {
  1338. DBGLOG("LDAP: dn not found for user %s", username);
  1339. return false;
  1340. }
  1341. StringBuffer userdnbuf;
  1342. userdnbuf.append(userdn);
  1343. ldap_memfree(userdn);
  1344. if (sysUser)
  1345. return true;//sysuser authenticated above
  1346. StringBuffer hostbuf;
  1347. m_ldapconfig->getLdapHost(hostbuf);
  1348. int rc = LDAP_SERVER_DOWN;
  1349. char *ldap_errstring=NULL;
  1350. for(int retries = 0; retries <= LDAPSEC_MAX_RETRIES; retries++)
  1351. {
  1352. DBGLOG("LdapBind for user %s (retries=%d).", username, retries);
  1353. {
  1354. #ifdef NULL_DALIUSER_STACKTRACE
  1355. //following debug code to be removed
  1356. if (!username)
  1357. {
  1358. DBGLOG("UNEXPECTED USER (NULL) in ldapconnection.cpp authenticate() line %d", __LINE__);
  1359. PrintStackReport();
  1360. }
  1361. #endif
  1362. LDAP* user_ld = LdapUtils::LdapInit(m_ldapconfig->getProtocol(), hostbuf.str(), m_ldapconfig->getLdapPort(), m_ldapconfig->getLdapSecurePort());
  1363. rc = LdapUtils::LdapBind(user_ld, m_ldapconfig->getDomain(), username, password, userdnbuf.str(), m_ldapconfig->getServerType(), m_ldapconfig->getAuthMethod());
  1364. if(rc != LDAP_SUCCESS)
  1365. ldap_get_option(user_ld, LDAP_OPT_ERROR_STRING, &ldap_errstring);
  1366. LDAP_UNBIND(user_ld);
  1367. }
  1368. DBGLOG("finished LdapBind for user %s, rc=%d", username, rc);
  1369. if(!LdapServerDown(rc) || retries > LDAPSEC_MAX_RETRIES)
  1370. break;
  1371. sleep(LDAPSEC_RETRY_WAIT);
  1372. if(retries < LDAPSEC_MAX_RETRIES)
  1373. DBGLOG("Server temporarily unreachable, retrying ...");
  1374. // Retrying next ldap sever, might be the same server
  1375. hostbuf.clear();
  1376. m_ldapconfig->getLdapHost(hostbuf);
  1377. }
  1378. if(rc == LDAP_SERVER_DOWN)
  1379. {
  1380. StringBuffer dc;
  1381. LdapUtils::getDcName(NULL, dc);
  1382. if(dc.length() > 0)
  1383. {
  1384. WARNLOG("Using automatically obtained LDAP Server %s", dc.str());
  1385. LDAP* user_ld = LdapUtils::LdapInit(m_ldapconfig->getProtocol(), dc.str(), m_ldapconfig->getLdapPort(), m_ldapconfig->getLdapSecurePort());
  1386. rc = LdapUtils::LdapBind(user_ld, m_ldapconfig->getDomain(), username, password, userdnbuf.str(), m_ldapconfig->getServerType(), m_ldapconfig->getAuthMethod());
  1387. if(rc != LDAP_SUCCESS)
  1388. ldap_get_option(user_ld, LDAP_OPT_ERROR_STRING, &ldap_errstring);
  1389. LDAP_UNBIND(user_ld);
  1390. }
  1391. }
  1392. if(rc != LDAP_SUCCESS)
  1393. {
  1394. if (ldap_errstring && *ldap_errstring && strstr(ldap_errstring, " data "))//if extended error strings are available (they are not in windows clients)
  1395. {
  1396. #ifdef _DEBUG
  1397. DBGLOG("LDAPBIND ERR: RC=%d, - '%s'", rc, ldap_errstring);
  1398. #endif
  1399. if (strstr(ldap_errstring, "data 532"))//80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 532, v1db0.
  1400. {
  1401. DBGLOG("LDAP: Password Expired(1) for user %s", username);
  1402. user.setAuthenticateStatus(AS_PASSWORD_VALID_BUT_EXPIRED);
  1403. }
  1404. else if (strstr(ldap_errstring, "data 773"))//User must reset password "80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 773, v1db1'
  1405. {
  1406. DBGLOG("LDAP: User %s Must Reset Password", username);
  1407. user.setAuthenticateStatus(AS_PASSWORD_VALID_BUT_EXPIRED);
  1408. }
  1409. else
  1410. {
  1411. DBGLOG("LDAP: Authentication(1) for user %s failed - %s", username, ldap_err2string(rc));
  1412. user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
  1413. }
  1414. }
  1415. else
  1416. {
  1417. //This path is typical if running ESP on Windows. We have no way
  1418. //to determine if password entered is valid but expired
  1419. if (user.getPasswordDaysRemaining() == scPasswordExpired)
  1420. {
  1421. DBGLOG("LDAP: Password Expired(2) for user %s", username);
  1422. user.setAuthenticateStatus(AS_PASSWORD_EXPIRED);
  1423. }
  1424. else
  1425. {
  1426. DBGLOG("LDAP: Authentication(2) for user %s failed - %s", username, ldap_err2string(rc));
  1427. user.setAuthenticateStatus(AS_INVALID_CREDENTIALS);
  1428. }
  1429. }
  1430. return false;
  1431. }
  1432. user.setAuthenticateStatus(AS_AUTHENTICATED);
  1433. }
  1434. //Always retrieve user info(SID, UID, fullname, etc) for Active Directory, when the user first logs in.
  1435. if((m_ldapconfig->getServerType() == ACTIVE_DIRECTORY) && (m_pp != NULL))
  1436. m_pp->retrieveUserInfo(user);
  1437. return true;
  1438. };
  1439. virtual bool authorize(SecResourceType rtype, ISecUser& user, IArrayOf<ISecResource>& resources)
  1440. {
  1441. bool ok = false;
  1442. const char* basedn = m_ldapconfig->getResourceBasedn(rtype);
  1443. if(basedn == NULL || *basedn == '\0')
  1444. {
  1445. DBGLOG("corresponding basedn is not defined for authorize");
  1446. return false;
  1447. }
  1448. const char* username = user.getName();
  1449. if(!username || !*username)
  1450. return false;
  1451. const char* sysuser = m_ldapconfig->getSysUser();
  1452. if(sysuser && *sysuser && (strcmp(username, sysuser) == 0))
  1453. {
  1454. ForEachItemIn(x, resources)
  1455. {
  1456. ISecResource* res = &resources.item(x);
  1457. if(!res)
  1458. continue;
  1459. if(rtype == RT_MODULE)
  1460. {
  1461. StringBuffer filter;
  1462. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1463. filter.append("name=");
  1464. else
  1465. filter.append("ou=");
  1466. filter.append(res->getName());
  1467. int count = countEntries(m_ldapconfig->getResourceBasedn(rtype), (char*)filter.str(), 10);
  1468. if(count != 0)
  1469. res->setAccessFlags(SecAccess_Full);
  1470. else
  1471. res->setAccessFlags(-1);
  1472. }
  1473. else
  1474. res->setAccessFlags(SecAccess_Full);
  1475. }
  1476. return true;
  1477. }
  1478. if(rtype == RT_FILE_SCOPE)
  1479. {
  1480. int defaultFileScopePermission = queryDefaultPermission(user);
  1481. IArrayOf<ISecResource> non_emptylist;
  1482. ForEachItemIn(x, resources)
  1483. {
  1484. ISecResource& res = resources.item(x);
  1485. const char* res_name = res.getName();
  1486. if(res_name == NULL || *res_name == '\0')
  1487. res.setAccessFlags(defaultFileScopePermission); //res.setAccessFlags(m_defaultFileScopePermission);
  1488. else
  1489. non_emptylist.append(*LINK(&res));
  1490. }
  1491. ok = authorizeScope(user, non_emptylist, basedn);
  1492. //if(ok && m_defaultFileScopePermission != -2)
  1493. if(ok && defaultFileScopePermission != -2)
  1494. {
  1495. ForEachItemIn(x, non_emptylist)
  1496. {
  1497. ISecResource& res = non_emptylist.item(x);
  1498. if(res.getAccessFlags() == -1)
  1499. res.setAccessFlags(defaultFileScopePermission); //res.setAccessFlags(m_defaultFileScopePermission);
  1500. }
  1501. }
  1502. return ok;
  1503. }
  1504. else if(rtype == RT_WORKUNIT_SCOPE)
  1505. {
  1506. int defaultWorkunitScopePermission = -2;
  1507. //if(m_defaultWorkunitScopePermission == -2)
  1508. {
  1509. const char* basebasedn = strchr(basedn, ',') + 1;
  1510. StringBuffer baseresource;
  1511. baseresource.append(basebasedn-basedn-4, basedn+3);
  1512. IArrayOf<ISecResource> base_resources;
  1513. base_resources.append(*(new CLdapSecResource(baseresource.str())));
  1514. bool baseok = authorizeScope(user, base_resources, basebasedn);
  1515. if(baseok)
  1516. {
  1517. defaultWorkunitScopePermission = base_resources.item(0).getAccessFlags();
  1518. }
  1519. }
  1520. IArrayOf<ISecResource> non_emptylist;
  1521. ForEachItemIn(x, resources)
  1522. {
  1523. ISecResource& res = resources.item(x);
  1524. const char* res_name = res.getName();
  1525. if(res_name == NULL || *res_name == '\0')
  1526. res.setAccessFlags(defaultWorkunitScopePermission);
  1527. else
  1528. non_emptylist.append(*LINK(&res));
  1529. }
  1530. ok = authorizeScope(user, non_emptylist, basedn);
  1531. if(ok && defaultWorkunitScopePermission != -2)
  1532. {
  1533. ForEachItemIn(x, non_emptylist)
  1534. {
  1535. ISecResource& res = non_emptylist.item(x);
  1536. if(res.getAccessFlags() == -1)
  1537. res.setAccessFlags(defaultWorkunitScopePermission);
  1538. }
  1539. }
  1540. return ok;
  1541. }
  1542. else
  1543. {
  1544. IArrayOf<CSecurityDescriptor> sdlist;
  1545. ForEachItemIn(x, resources)
  1546. {
  1547. ISecResource& res = resources.item(x);
  1548. const char* resourcename = res.getName();
  1549. CSecurityDescriptor* sd = new CSecurityDescriptor(resourcename);
  1550. sdlist.append(*sd);
  1551. }
  1552. getSecurityDescriptors(rtype, sdlist);
  1553. if(m_pp != NULL)
  1554. ok = m_pp->getPermissions(user, sdlist, resources);
  1555. return ok;
  1556. }
  1557. }
  1558. // Returns true if all resources are correctly added, otherwise returns false.
  1559. virtual bool addResources(SecResourceType rtype, ISecUser& user, IArrayOf<ISecResource>& resources, SecPermissionType ptype, const char* basedn)
  1560. {
  1561. bool ret = true;
  1562. for(unsigned i = 0; i < resources.length(); i++)
  1563. {
  1564. ISecResource* resource = &resources.item(i);
  1565. if(resource != NULL)
  1566. {
  1567. bool oneret = addResource(rtype, user, resource, ptype, basedn);
  1568. ret = ret && oneret;
  1569. }
  1570. }
  1571. return ret;
  1572. }
  1573. virtual bool getUserInfo(ISecUser& user, const char* infotype)
  1574. {
  1575. char *attribute;
  1576. LDAPMessage *message;
  1577. const char* username = user.getName();
  1578. if(username == NULL || strlen(username) == 0)
  1579. {
  1580. DBGLOG("LDAP: getUserInfo : username is empty");
  1581. return false;
  1582. }
  1583. if(infotype && stricmp(infotype, "sudoers") == 0)
  1584. {
  1585. CLdapSecUser* ldapuser = dynamic_cast<CLdapSecUser*>(&user);
  1586. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1587. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1588. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  1589. StringBuffer filter("sudoUser=");
  1590. filter.append(username);
  1591. char *attrs[] = {"sudoHost", "sudoCommand", "sudoOption", NULL};
  1592. const char* basedn = m_ldapconfig->getResourceBasedn(RT_SUDOERS);
  1593. CLDAPMessage searchResult;
  1594. int rc = ldap_search_ext_s(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg);
  1595. if ( rc != LDAP_SUCCESS )
  1596. {
  1597. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), basedn);
  1598. ldapuser->setSudoersEnabled(false);
  1599. ldapuser->setInSudoers(false);
  1600. return false;
  1601. }
  1602. ldapuser->setSudoersEnabled(true);
  1603. unsigned entries = ldap_count_entries(ld, searchResult);
  1604. if(entries == 0)
  1605. {
  1606. ldapuser->setInSudoers(false);
  1607. return true;
  1608. }
  1609. message = LdapFirstEntry(ld, searchResult);
  1610. if(message == NULL)
  1611. {
  1612. ldapuser->setInSudoers(false);
  1613. return true;
  1614. }
  1615. ldapuser->setInSudoers(true);
  1616. CLDAPGetAttributesWrapper atts(ld, searchResult);
  1617. for ( attribute = atts.getFirst();
  1618. attribute != NULL;
  1619. attribute = atts.getNext())
  1620. {
  1621. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  1622. if (vals.hasValues())
  1623. {
  1624. if(stricmp(attribute, "sudoHost") == 0)
  1625. ldapuser->setSudoHost(vals.queryCharValue(0));
  1626. else if(stricmp(attribute, "sudoCommand") == 0)
  1627. ldapuser->setSudoCommand(vals.queryCharValue(0));
  1628. else if(stricmp(attribute, "sudoOption") == 0)
  1629. ldapuser->setSudoOption(vals.queryCharValue(0));
  1630. }
  1631. }
  1632. return true;
  1633. }
  1634. else
  1635. {
  1636. StringBuffer filter;
  1637. const char* basedn = m_ldapconfig->getUserBasedn();
  1638. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1639. {
  1640. filter.append("sAMAccountName=");
  1641. }
  1642. else
  1643. {
  1644. filter.append("uid=");
  1645. if(stricmp(username, m_ldapconfig->getSysUser()) == 0)
  1646. basedn = m_ldapconfig->getSysUserBasedn();
  1647. }
  1648. filter.append(user.getName());
  1649. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1650. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1651. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  1652. char *attrs[] = {"cn", "givenName", "sn", "gidnumber", "uidnumber", "homedirectory", "loginshell", "objectClass", NULL};
  1653. CLDAPMessage searchResult;
  1654. int rc = ldap_search_ext_s(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1655. if ( rc != LDAP_SUCCESS )
  1656. {
  1657. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), basedn);
  1658. return false;
  1659. }
  1660. ((CLdapSecUser*)&user)->setPosixenabled(false);
  1661. // Go through the search results by checking message types
  1662. for(message = LdapFirstEntry( ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  1663. {
  1664. CLDAPGetAttributesWrapper atts(ld, searchResult);
  1665. for ( attribute = atts.getFirst();
  1666. attribute != NULL;
  1667. attribute = atts.getNext())
  1668. {
  1669. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  1670. if (vals.hasValues())
  1671. {
  1672. if(stricmp(attribute, "cn") == 0)
  1673. user.setFullName(vals.queryCharValue(0));
  1674. else if(stricmp(attribute, "givenName") == 0)
  1675. user.setFirstName(vals.queryCharValue(0));
  1676. else if(stricmp(attribute, "sn") == 0)
  1677. user.setLastName(vals.queryCharValue(0));
  1678. else if(stricmp(attribute, "gidnumber") == 0)
  1679. ((CLdapSecUser*)&user)->setGidnumber(vals.queryCharValue(0));
  1680. else if(stricmp(attribute, "uidnumber") == 0)
  1681. ((CLdapSecUser*)&user)->setUidnumber(vals.queryCharValue(0));
  1682. else if(stricmp(attribute, "homedirectory") == 0)
  1683. ((CLdapSecUser*)&user)->setHomedirectory(vals.queryCharValue(0));
  1684. else if(stricmp(attribute, "loginshell") == 0)
  1685. ((CLdapSecUser*)&user)->setLoginshell(vals.queryCharValue(0));
  1686. else if(stricmp(attribute, "objectClass") == 0)
  1687. {
  1688. int valind = 0;
  1689. while(vals.queryCharValue(valind))
  1690. {
  1691. if(stricmp(vals.queryCharValue(valind), "posixAccount") == 0)
  1692. {
  1693. ((CLdapSecUser*)&user)->setPosixenabled(true);
  1694. break;
  1695. }
  1696. valind++;
  1697. }
  1698. }
  1699. }
  1700. }
  1701. }
  1702. return true;
  1703. }
  1704. }
  1705. ISecUser* lookupUser(unsigned uid)
  1706. {
  1707. StringBuffer sysuser;
  1708. sysuser.append(m_ldapconfig->getSysUser());
  1709. if(sysuser.length() == 0)
  1710. {
  1711. #ifdef _WIN32
  1712. char uname[128];
  1713. unsigned long len = 128;
  1714. int rc = GetUserName(uname, &len);
  1715. if(rc != 0)
  1716. sysuser.append(len, uname);
  1717. else
  1718. throw MakeStringException(-1, "Error getting current user's username, error code = %d", rc);
  1719. #else
  1720. throw MakeStringException(-1, "systemUser not found in config");
  1721. #endif
  1722. }
  1723. MemoryBuffer usersidbuf;
  1724. StringBuffer usersidstr;
  1725. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1726. {
  1727. if(m_pp != NULL)
  1728. m_pp->lookupSid(sysuser.str(), usersidbuf);
  1729. if(usersidbuf.length() == 0)
  1730. {
  1731. throw MakeStringException(-1, "system user %s's SID not found", sysuser.str());
  1732. }
  1733. int sidlen = usersidbuf.length();
  1734. char* uidbuf = (char*)&uid;
  1735. for(int i = 0; i < 4; i++)
  1736. {
  1737. usersidbuf.writeDirect(sidlen -4 + i, 1, (uidbuf + 3 - i));
  1738. }
  1739. LdapUtils::bin2str(usersidbuf, usersidstr);
  1740. }
  1741. else
  1742. {
  1743. usersidbuf.append(uid);
  1744. }
  1745. char *attribute;
  1746. LDAPMessage *message;
  1747. StringBuffer filter;
  1748. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1749. {
  1750. filter.append("objectSid=").append(usersidstr.str());
  1751. }
  1752. else
  1753. {
  1754. filter.appendf("entryid=%d", uid);
  1755. }
  1756. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1757. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1758. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  1759. char* act_fieldname;
  1760. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1761. {
  1762. act_fieldname = "sAMAccountName";
  1763. }
  1764. else
  1765. {
  1766. act_fieldname = "uid";
  1767. }
  1768. char *attrs[] = {"cn", act_fieldname, NULL};
  1769. CLDAPMessage searchResult;
  1770. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1771. if ( rc != LDAP_SUCCESS )
  1772. {
  1773. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  1774. return NULL;
  1775. }
  1776. if(ldap_count_entries(ld, searchResult) < 1)
  1777. {
  1778. DBGLOG("No entries are found for user with uid %0X", uid);
  1779. return NULL;
  1780. }
  1781. CLdapSecUser* ldapuser = new CLdapSecUser("", "");
  1782. // Go through the search results by checking message types
  1783. for(message = LdapFirstEntry( ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  1784. {
  1785. CLDAPGetAttributesWrapper atts(ld, searchResult);
  1786. for ( attribute = atts.getFirst();
  1787. attribute != NULL;
  1788. attribute = atts.getNext())
  1789. {
  1790. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  1791. if (vals.hasValues())
  1792. {
  1793. if(stricmp(attribute, "cn") == 0)
  1794. ldapuser->setFullName(vals.queryCharValue(0));
  1795. else if(stricmp(attribute, act_fieldname) == 0)
  1796. ldapuser->setName(vals.queryCharValue(0));
  1797. }
  1798. }
  1799. }
  1800. ldapuser->setUserID(uid);
  1801. ldapuser->setUserSid(usersidbuf.length(), usersidbuf.toByteArray());
  1802. // Since we've got the SID for the user, cache it for later uses.
  1803. MemoryBuffer mb;
  1804. if(m_pp != NULL)
  1805. m_pp->getCachedSid(ldapuser->getName(), mb);
  1806. if(mb.length() == 0)
  1807. {
  1808. m_pp->cacheSid(ldapuser->getName(), usersidbuf.length(), usersidbuf.toByteArray());
  1809. }
  1810. return ldapuser;
  1811. }
  1812. bool lookupAccount(MemoryBuffer& sidbuf, StringBuffer& account_name, ACT_TYPE& act_type)
  1813. {
  1814. char *attribute;
  1815. LDAPMessage *message;
  1816. char* act_fieldname;
  1817. StringBuffer filter;
  1818. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1819. {
  1820. act_fieldname = "sAMAccountName";
  1821. StringBuffer usersidstr;
  1822. LdapUtils::bin2str(sidbuf, usersidstr);
  1823. filter.append("objectSid=").append(usersidstr.str());
  1824. }
  1825. else
  1826. {
  1827. unsigned* uid = (unsigned*)sidbuf.toByteArray();
  1828. filter.appendf("entryid=%d", *uid);
  1829. act_fieldname = "uid";
  1830. }
  1831. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1832. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1833. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  1834. char *attrs[] = {"cn", act_fieldname, "objectClass", NULL};
  1835. CLDAPMessage searchResult;
  1836. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1837. if ( rc != LDAP_SUCCESS )
  1838. {
  1839. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  1840. return false;
  1841. }
  1842. if(ldap_count_entries(ld, searchResult) < 1)
  1843. {
  1844. searchResult.ldapMsgFree();
  1845. rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getGroupBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1846. if(ldap_count_entries(ld, searchResult) < 1)
  1847. {
  1848. searchResult.ldapMsgFree();
  1849. rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getSysUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1850. //DBGLOG("No entries are found");
  1851. return false;
  1852. }
  1853. }
  1854. StringBuffer act_name;
  1855. StringBuffer cnbuf;
  1856. // Go through the search results by checking message types
  1857. for(message = LdapFirstEntry( ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  1858. {
  1859. CLDAPGetAttributesWrapper atts(ld, searchResult);
  1860. for ( attribute = atts.getFirst();
  1861. attribute != NULL;
  1862. attribute = atts.getNext())
  1863. {
  1864. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  1865. if (vals.hasValues())
  1866. {
  1867. if(stricmp(attribute, act_fieldname) == 0)
  1868. act_name.clear().append(vals.queryCharValue(0));
  1869. else if(stricmp(attribute, "cn") == 0)
  1870. cnbuf.clear().append(vals.queryCharValue(0));
  1871. else if(stricmp(attribute, "objectClass") == 0)
  1872. {
  1873. int i = 0;
  1874. while(vals.queryCharValue(i) != NULL)
  1875. {
  1876. if(stricmp(vals.queryCharValue(i), "person") == 0)
  1877. act_type = USER_ACT;
  1878. else if(stricmp(vals.queryCharValue(i), "group") == 0)
  1879. act_type = GROUP_ACT;
  1880. i++;
  1881. }
  1882. }
  1883. }
  1884. }
  1885. }
  1886. if(act_type == USER_ACT)
  1887. account_name.append(act_name.str());
  1888. else
  1889. account_name.append(cnbuf.str());
  1890. return true;
  1891. }
  1892. virtual void lookupSid(const char* basedn, const char* filter, MemoryBuffer& act_sid)
  1893. {
  1894. char *attribute;
  1895. LDAPMessage *message;
  1896. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1897. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1898. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  1899. char* fieldname;
  1900. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1901. fieldname = "objectSid";
  1902. else
  1903. fieldname = "entryid";
  1904. char *attrs[] = {fieldname, NULL};
  1905. CLDAPMessage searchResult;
  1906. int rc = ldap_search_ext_s(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter, attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  1907. if ( rc != LDAP_SUCCESS )
  1908. {
  1909. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter, basedn);
  1910. return;
  1911. }
  1912. message = LdapFirstEntry( ld, searchResult);
  1913. if(message != NULL)
  1914. {
  1915. CLDAPGetAttributesWrapper atts(ld, searchResult);
  1916. for ( attribute = atts.getFirst();
  1917. attribute != NULL;
  1918. attribute = atts.getNext())
  1919. {
  1920. if(0 == stricmp(attribute, fieldname))
  1921. {
  1922. CLDAPGetValuesLenWrapper valsLen(ld, message, attribute);
  1923. if (valsLen.hasValues())
  1924. {
  1925. struct berval* val = valsLen.queryBValues()[0];
  1926. if(val != NULL)
  1927. {
  1928. int len = val->bv_len;
  1929. act_sid.append(val->bv_len, val->bv_val);
  1930. }
  1931. }
  1932. break;
  1933. }
  1934. }
  1935. }
  1936. }
  1937. virtual void lookupSid(const char* act_name, MemoryBuffer& act_sid, ACT_TYPE act_type)
  1938. {
  1939. StringBuffer filter;
  1940. const char* basedn;
  1941. if(act_type == USER_ACT)
  1942. {
  1943. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1944. filter.append("sAMAccountName=").append(act_name);
  1945. else
  1946. filter.append("uid=").append(act_name);
  1947. basedn = m_ldapconfig->getUserBasedn();
  1948. lookupSid(basedn, filter.str(), act_sid);
  1949. if(act_sid.length() == 0)
  1950. {
  1951. StringBuffer basebuf;
  1952. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1953. basebuf.append("cn=Users,").append(m_ldapconfig->getBasedn());
  1954. else if(stricmp(act_name, m_ldapconfig->getSysUser()) == 0)
  1955. basebuf.append(m_ldapconfig->getSysUserBasedn());
  1956. else
  1957. basebuf.append("ou=People,").append(m_ldapconfig->getBasedn());
  1958. lookupSid(basebuf.str(), filter.str(), act_sid);
  1959. }
  1960. }
  1961. else
  1962. {
  1963. filter.append("cn=").append(act_name);
  1964. basedn = m_ldapconfig->getGroupBasedn();
  1965. lookupSid(basedn, filter.str(), act_sid);
  1966. if(act_sid.length() == 0)
  1967. {
  1968. StringBuffer basebuf;
  1969. basebuf.append("cn=Users,").append(m_ldapconfig->getBasedn());
  1970. lookupSid(basebuf.str(), filter.str(), act_sid);
  1971. if(act_sid.length() == 0)
  1972. {
  1973. basebuf.clear();
  1974. basebuf.append("cn=Builtin,").append(m_ldapconfig->getBasedn());
  1975. lookupSid(basebuf.str(), filter.str(), act_sid);
  1976. }
  1977. }
  1978. }
  1979. }
  1980. virtual void setPermissionProcessor(IPermissionProcessor* pp)
  1981. {
  1982. m_pp = pp;
  1983. }
  1984. virtual bool retrieveUsers(IUserArray& users)
  1985. {
  1986. return retrieveUsers("", users);
  1987. }
  1988. virtual bool retrieveUsers(const char* searchstr, IUserArray& users)
  1989. {
  1990. char *attribute;
  1991. LDAPMessage *message;
  1992. StringBuffer filter;
  1993. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  1994. filter.append("objectClass=User");
  1995. else
  1996. filter.append("objectClass=inetorgperson");
  1997. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  1998. Owned<ILdapConnection> lconn = m_connections->getConnection();
  1999. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2000. char* act_fieldname;
  2001. char* sid_fieldname;
  2002. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2003. {
  2004. act_fieldname = "sAMAccountName";
  2005. sid_fieldname = "objectSid";
  2006. }
  2007. else
  2008. {
  2009. act_fieldname = "uid";
  2010. sid_fieldname = "entryid";
  2011. }
  2012. if(searchstr && *searchstr && strcmp(searchstr, "*") != 0)
  2013. {
  2014. filter.insert(0, "(&(");
  2015. filter.appendf(")(|(%s=*%s*)(%s=*%s*)(%s=*%s*)))", act_fieldname, searchstr, "givenName", searchstr, "sn", searchstr);
  2016. }
  2017. char *attrs[] = {act_fieldname, sid_fieldname, "cn", "userAccountControl", "pwdLastSet", NULL};
  2018. CPagedLDAPSearch pagedSrch(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs);
  2019. for (message = pagedSrch.getFirstEntry(); message; message = pagedSrch.getNextEntry())
  2020. {
  2021. bool accountPwdNeverExpires = false;
  2022. Owned<ISecUser> user = new CLdapSecUser("", "");
  2023. // Go through the search results by checking message types
  2024. CLDAPGetAttributesWrapper atts(ld, message);
  2025. for ( attribute = atts.getFirst();
  2026. attribute != NULL;
  2027. attribute = atts.getNext())
  2028. {
  2029. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2030. if (!vals.hasValues())
  2031. continue;
  2032. if(stricmp(attribute, "cn") == 0)
  2033. {
  2034. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2035. if (vals.hasValues())
  2036. user->setFullName(vals.queryCharValue(0));
  2037. }
  2038. else if (stricmp(attribute, "userAccountControl") == 0)
  2039. {
  2040. //UF_DONT_EXPIRE_PASSWD 0x10000
  2041. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2042. if (vals.hasValues())
  2043. if (atoi((char*)vals.queryCharValue(0)) & 0x10000)//this can be true at the account level, even if domain policy requires password
  2044. accountPwdNeverExpires = true;
  2045. }
  2046. else if(stricmp(attribute, "pwdLastSet") == 0)
  2047. {
  2048. CDateTime expiry;
  2049. if (!m_domainPwdsNeverExpire && !accountPwdNeverExpires)
  2050. {
  2051. CLDAPGetValuesLenWrapper valsLen(ld, message, attribute);
  2052. if (valsLen.hasValues())
  2053. {
  2054. struct berval* val = valsLen.queryBValues()[0];
  2055. calcPWExpiry(expiry, (unsigned)val->bv_len, val->bv_val);
  2056. }
  2057. }
  2058. else
  2059. expiry.clear();
  2060. user->setPasswordExpiration(expiry);
  2061. }
  2062. else if(stricmp(attribute, act_fieldname) == 0)
  2063. {
  2064. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2065. if (vals.hasValues())
  2066. user->setName(vals.queryCharValue(0));
  2067. }
  2068. else if(stricmp(attribute, sid_fieldname) == 0)
  2069. {
  2070. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2071. {
  2072. CLDAPGetValuesLenWrapper valsLen(ld, message, attribute);
  2073. if (valsLen.hasValues())
  2074. {
  2075. struct berval* val = valsLen.queryBValues()[0];
  2076. if(val != NULL)
  2077. {
  2078. unsigned uid = val->bv_val[val->bv_len - 4];
  2079. int i;
  2080. for(i = 3; i > 0; i--)
  2081. {
  2082. uid = (uid << 8) + val->bv_val[val->bv_len - i];
  2083. }
  2084. ((CLdapSecUser*)user.get())->setUserID(uid);
  2085. }
  2086. }
  2087. }
  2088. else
  2089. {
  2090. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2091. if (vals.hasValues())
  2092. ((CLdapSecUser*)user.get())->setUserID(atoi(vals.queryCharValue(0)));
  2093. }
  2094. }
  2095. }
  2096. if (user->getName() && *user->getName())
  2097. users.append(*LINK(user.get()));
  2098. }
  2099. return true;
  2100. }
  2101. virtual IPropertyTreeIterator* getUserIterator(const char* userName)
  2102. {
  2103. IUserArray users;
  2104. retrieveUsers(userName, users);
  2105. Owned<IPropertyTree> usersTree = createPTree("Users");
  2106. ForEachItemIn(i, users)
  2107. addUserTree(users.item(i), usersTree);
  2108. return usersTree->getElements("*");
  2109. }
  2110. void addUserTree(ISecUser& usr, IPropertyTree* users)
  2111. {
  2112. const char* usrName = usr.getName();
  2113. if(!usrName || !*usrName)
  2114. return;
  2115. const char* fullName = usr.getFullName();
  2116. StringBuffer sb;
  2117. switch (usr.getPasswordDaysRemaining())//-1 if expired, -2 if never expires
  2118. {
  2119. case scPasswordExpired:
  2120. sb.set("Expired");
  2121. break;
  2122. case scPasswordNeverExpires:
  2123. sb.set("Never");
  2124. break;
  2125. default:
  2126. CDateTime dt;
  2127. usr.getPasswordExpiration(dt);
  2128. dt.getDateString(sb);
  2129. break;
  2130. }
  2131. Owned<IPTree> userTree = createPTree("User");
  2132. userTree->addProp(getUserFieldNames(UFName), usrName);
  2133. if (fullName && *fullName)
  2134. userTree->addProp(getUserFieldNames(UFFullName), fullName);
  2135. userTree->addPropInt(getUserFieldNames(UFUserID), usr.getUserID());
  2136. userTree->addProp(getUserFieldNames(UFPasswordExpiration), sb.str());
  2137. users->addPropTree("User", userTree.getClear());
  2138. }
  2139. ISecItemIterator* getUsersSorted(const char* userName, UserField* sortOrder, const unsigned pageStartFrom, const unsigned pageSize, unsigned* total, __int64* cacheHint)
  2140. {
  2141. class CElementsPager : public CSimpleInterface, implements IElementsPager
  2142. {
  2143. ILdapClient* ldapClient;
  2144. StringAttr userName;
  2145. StringAttr sortOrder;
  2146. public:
  2147. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2148. CElementsPager(ILdapClient* _ldapClient, const char* _userName, const char*_sortOrder)
  2149. : ldapClient(_ldapClient), userName(_userName), sortOrder(_sortOrder) { };
  2150. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree>& elements)
  2151. {
  2152. StringArray unknownAttributes;
  2153. Owned<IPropertyTreeIterator> iter = ldapClient->getUserIterator(userName.get());
  2154. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  2155. return NULL;
  2156. }
  2157. virtual bool allMatchingElementsReceived() { return true; }//For now, ldap always returns all of matched users.
  2158. };
  2159. StringBuffer so;
  2160. if (sortOrder)
  2161. {
  2162. for (unsigned i=0;sortOrder[i]!=UFterm;i++)
  2163. {
  2164. if (so.length())
  2165. so.append(',');
  2166. int fmt = sortOrder[i];
  2167. if (fmt&UFreverse)
  2168. so.append('-');
  2169. if (fmt&UFnocase)
  2170. so.append('?');
  2171. if (fmt&UFnumeric)
  2172. so.append('#');
  2173. so.append(getUserFieldNames((UserField) (fmt&0xff)));
  2174. }
  2175. }
  2176. IArrayOf<IPropertyTree> results;
  2177. Owned<IElementsPager> elementsPager = new CElementsPager(this, userName, so.length()?so.str():NULL);
  2178. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager, pageStartFrom, pageSize, NULL, "", cacheHint, results, total, NULL, false);
  2179. return new CSecItemIterator(results);
  2180. }
  2181. virtual bool userInGroup(const char* userdn, const char* groupdn)
  2182. {
  2183. const char* fldname;
  2184. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2185. fldname = "member";
  2186. else
  2187. fldname = "uniquemember";
  2188. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2189. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2190. int rc = LDAP_COMPARE_EXT_S(ld, (char*)groupdn, (char*)fldname, (char*)userdn,0,0,0);
  2191. if(rc == LDAP_COMPARE_TRUE)
  2192. return true;
  2193. else
  2194. return false;
  2195. }
  2196. // Update user's firstname, lastname (plus displayname for active directory).
  2197. virtual bool updateUser(const char* type, ISecUser& user)
  2198. {
  2199. const char* username = user.getName();
  2200. if(!username || !*username)
  2201. return false;
  2202. StringBuffer userdn;
  2203. getUserDN(username, userdn);
  2204. int rc = LDAP_SUCCESS;
  2205. if(!type || !*type || stricmp(type, "names") == 0)
  2206. {
  2207. StringBuffer cnbuf;
  2208. const char* fname = user.getFirstName();
  2209. const char* lname = user.getLastName();
  2210. if(fname && *fname && lname && *lname)
  2211. {
  2212. cnbuf.append(fname).append(" ").append(lname);
  2213. }
  2214. else
  2215. throw MakeStringException(-1, "Please specify both firstname and lastname");
  2216. char *gn_values[] = { (char*)fname, NULL };
  2217. LDAPMod gn_attr = {
  2218. LDAP_MOD_REPLACE,
  2219. "givenName",
  2220. gn_values
  2221. };
  2222. char *sn_values[] = { (char*)lname, NULL };
  2223. LDAPMod sn_attr = {
  2224. LDAP_MOD_REPLACE,
  2225. "sn",
  2226. sn_values
  2227. };
  2228. char *cn_values[] = {(char*)cnbuf.str(), NULL };
  2229. LDAPMod cn_attr =
  2230. {
  2231. LDAP_MOD_REPLACE,
  2232. "cn",
  2233. cn_values
  2234. };
  2235. char *dispname_values[] = {(char*)cnbuf.str(), NULL };
  2236. LDAPMod dispname_attr =
  2237. {
  2238. LDAP_MOD_REPLACE,
  2239. "displayName",
  2240. dispname_values
  2241. };
  2242. LDAPMod *attrs[4];
  2243. int ind = 0;
  2244. attrs[ind++] = &gn_attr;
  2245. attrs[ind++] = &sn_attr;
  2246. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2247. {
  2248. attrs[ind++] = &dispname_attr;
  2249. }
  2250. else
  2251. {
  2252. attrs[ind++] = &cn_attr;
  2253. }
  2254. attrs[ind] = NULL;
  2255. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2256. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2257. rc = ldap_modify_ext_s(ld, (char*)userdn.str(), attrs, NULL, NULL);
  2258. if (rc == LDAP_SUCCESS && m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2259. {
  2260. StringBuffer newrdn("cn=");
  2261. newrdn.append(cnbuf.str());
  2262. rc = LdapRename(ld, (char*)userdn.str(), (char*)newrdn.str(), NULL, true, NULL, NULL);
  2263. }
  2264. }
  2265. else if(stricmp(type, "posixenable") == 0)
  2266. {
  2267. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2268. throw MakeStringException(-1, "posixAccount isn't applicable to Active Directory");
  2269. CLdapSecUser* ldapuser = dynamic_cast<CLdapSecUser*>(&user);
  2270. char* oc_values[] = {"posixAccount", NULL};
  2271. LDAPMod oc_attr = {
  2272. LDAP_MOD_ADD,
  2273. "objectclass",
  2274. oc_values
  2275. };
  2276. char* oc1_values[] = {"shadowAccount", NULL};
  2277. LDAPMod oc1_attr = {
  2278. LDAP_MOD_ADD,
  2279. "objectclass",
  2280. oc1_values
  2281. };
  2282. char *gidnum_values[] = { (char*)ldapuser->getGidnumber(), NULL };
  2283. LDAPMod gidnum_attr = {
  2284. LDAP_MOD_REPLACE,
  2285. "gidnumber",
  2286. gidnum_values
  2287. };
  2288. char *uidnum_values[] = { (char*)ldapuser->getUidnumber(), NULL };
  2289. LDAPMod uidnum_attr = {
  2290. LDAP_MOD_REPLACE,
  2291. "uidnumber",
  2292. uidnum_values
  2293. };
  2294. char *homedir_values[] = {(char*)ldapuser->getHomedirectory(), NULL };
  2295. LDAPMod homedir_attr =
  2296. {
  2297. LDAP_MOD_REPLACE,
  2298. "homedirectory",
  2299. homedir_values
  2300. };
  2301. char *loginshell_values[] = {(char*)ldapuser->getLoginshell(), NULL };
  2302. LDAPMod loginshell_attr =
  2303. {
  2304. LDAP_MOD_REPLACE,
  2305. "loginshell",
  2306. loginshell_values
  2307. };
  2308. LDAPMod *attrs[7];
  2309. int ind = 0;
  2310. attrs[ind++] = &gidnum_attr;
  2311. attrs[ind++] = &uidnum_attr;
  2312. attrs[ind++] = &homedir_attr;
  2313. attrs[ind++] = &loginshell_attr;
  2314. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2315. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2316. int compresult = LDAP_COMPARE_EXT_S(ld, (char*)userdn.str(), (char*)"objectclass", (char*)"posixAccount",0,0,0);
  2317. if(compresult != LDAP_COMPARE_TRUE)
  2318. attrs[ind++] = &oc_attr;
  2319. compresult = LDAP_COMPARE_EXT_S(ld, (char*)userdn.str(), (char*)"objectclass", (char*)"shadowAccount",0,0,0);
  2320. if(compresult != LDAP_COMPARE_TRUE)
  2321. attrs[ind++] = &oc1_attr;
  2322. attrs[ind] = NULL;
  2323. rc = ldap_modify_ext_s(ld, (char*)userdn.str(), attrs, NULL, NULL);
  2324. }
  2325. else if(stricmp(type, "posixdisable") == 0)
  2326. {
  2327. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  2328. throw MakeStringException(-1, "posixAccount isn't applicable to Active Directory");
  2329. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2330. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2331. int compresult = LDAP_COMPARE_EXT_S(ld, (char*)userdn.str(), (char*)"objectclass", (char*)"posixAccount",0,0,0);
  2332. if(compresult != LDAP_COMPARE_TRUE)
  2333. {
  2334. rc = LDAP_SUCCESS;
  2335. }
  2336. else
  2337. {
  2338. CLdapSecUser* ldapuser = dynamic_cast<CLdapSecUser*>(&user);
  2339. char* oc_values[] = {"posixAccount", NULL};
  2340. LDAPMod oc_attr = {
  2341. LDAP_MOD_DELETE,
  2342. "objectclass",
  2343. oc_values
  2344. };
  2345. char* oc1_values[] = {"shadowAccount", NULL};
  2346. LDAPMod oc1_attr = {
  2347. LDAP_MOD_DELETE,
  2348. "objectclass",
  2349. oc1_values
  2350. };
  2351. char *gidnum_values[] = { NULL };
  2352. LDAPMod gidnum_attr = {
  2353. LDAP_MOD_DELETE,
  2354. "gidnumber",
  2355. gidnum_values
  2356. };
  2357. char *uidnum_values[] = {NULL };
  2358. LDAPMod uidnum_attr = {
  2359. LDAP_MOD_DELETE,
  2360. "uidnumber",
  2361. uidnum_values
  2362. };
  2363. char *homedir_values[] = { NULL };
  2364. LDAPMod homedir_attr =
  2365. {
  2366. LDAP_MOD_DELETE,
  2367. "homedirectory",
  2368. homedir_values
  2369. };
  2370. char *loginshell_values[] = { NULL };
  2371. LDAPMod loginshell_attr =
  2372. {
  2373. LDAP_MOD_DELETE,
  2374. "loginshell",
  2375. loginshell_values
  2376. };
  2377. LDAPMod *attrs[7];
  2378. int ind = 0;
  2379. attrs[ind++] = &gidnum_attr;
  2380. attrs[ind++] = &uidnum_attr;
  2381. attrs[ind++] = &homedir_attr;
  2382. attrs[ind++] = &loginshell_attr;
  2383. attrs[ind++] = &oc_attr;
  2384. attrs[ind++] = &oc1_attr;
  2385. attrs[ind] = NULL;
  2386. rc = ldap_modify_ext_s(ld, (char*)userdn.str(), attrs, NULL, NULL);
  2387. }
  2388. }
  2389. else if(stricmp(type, "sudoersadd") == 0)
  2390. {
  2391. CLdapSecUser* ldapuser = dynamic_cast<CLdapSecUser*>(&user);
  2392. char *cn_values[] = {(char*)username, NULL };
  2393. LDAPMod cn_attr =
  2394. {
  2395. LDAP_MOD_ADD,
  2396. "cn",
  2397. cn_values
  2398. };
  2399. char *oc_values[] = {"sudoRole", NULL };
  2400. LDAPMod oc_attr =
  2401. {
  2402. LDAP_MOD_ADD,
  2403. "objectClass",
  2404. oc_values
  2405. };
  2406. char *user_values[] = {(char*)username, NULL };
  2407. LDAPMod user_attr =
  2408. {
  2409. LDAP_MOD_ADD,
  2410. "sudoUser",
  2411. user_values
  2412. };
  2413. char* sudoHost = (char*)ldapuser->getSudoHost();
  2414. char* sudoCommand = (char*)ldapuser->getSudoCommand();
  2415. char* sudoOption = (char*)ldapuser->getSudoOption();
  2416. char *host_values[] = {sudoHost, NULL };
  2417. LDAPMod host_attr =
  2418. {
  2419. LDAP_MOD_ADD,
  2420. "sudoHost",
  2421. host_values
  2422. };
  2423. char *cmd_values[] = {sudoCommand, NULL };
  2424. LDAPMod cmd_attr =
  2425. {
  2426. LDAP_MOD_ADD,
  2427. "sudoCommand",
  2428. cmd_values
  2429. };
  2430. char *option_values[] = {sudoOption, NULL };
  2431. LDAPMod option_attr =
  2432. {
  2433. LDAP_MOD_ADD,
  2434. "sudoOption",
  2435. option_values
  2436. };
  2437. LDAPMod *attrs[8];
  2438. int ind = 0;
  2439. attrs[ind++] = &cn_attr;
  2440. attrs[ind++] = &oc_attr;
  2441. attrs[ind++] = &user_attr;
  2442. if(sudoHost && *sudoHost)
  2443. attrs[ind++] = &host_attr;
  2444. if(sudoCommand && *sudoCommand)
  2445. attrs[ind++] = &cmd_attr;
  2446. if(sudoOption && *sudoOption)
  2447. attrs[ind++] = &option_attr;
  2448. attrs[ind] = NULL;
  2449. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2450. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2451. StringBuffer dn;
  2452. dn.append("cn=").append(username).append(",").append(m_ldapconfig->getResourceBasedn(RT_SUDOERS));
  2453. int rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  2454. if ( rc != LDAP_SUCCESS )
  2455. {
  2456. if(rc == LDAP_ALREADY_EXISTS)
  2457. {
  2458. throw MakeStringException(-1, "can't add %s to sudoers, an LDAP object with this name already exists", username);
  2459. }
  2460. else
  2461. {
  2462. DBGLOG("error adding %s to sudoers: %s", username, ldap_err2string( rc ));
  2463. throw MakeStringException(-1, "error adding %s to sudoers: %s", username, ldap_err2string( rc ));
  2464. }
  2465. }
  2466. }
  2467. else if(stricmp(type, "sudoersdelete") == 0)
  2468. {
  2469. StringBuffer dn;
  2470. dn.append("cn=").append(username).append(",").append(m_ldapconfig->getResourceBasedn(RT_SUDOERS));
  2471. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2472. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2473. int rc = ldap_delete_ext_s(ld, (char*)dn.str(), NULL, NULL);
  2474. if ( rc != LDAP_SUCCESS )
  2475. {
  2476. throw MakeStringException(-1, "Error deleting user %s from sudoers: %s", username, ldap_err2string(rc));
  2477. }
  2478. }
  2479. else if(stricmp(type, "sudoersupdate") == 0)
  2480. {
  2481. CLdapSecUser* ldapuser = dynamic_cast<CLdapSecUser*>(&user);
  2482. char* sudoHost = (char*)ldapuser->getSudoHost();
  2483. char* sudoCommand = (char*)ldapuser->getSudoCommand();
  2484. char* sudoOption = (char*)ldapuser->getSudoOption();
  2485. char *host_values[] = {(sudoHost&&*sudoHost)?sudoHost:NULL, NULL };
  2486. LDAPMod host_attr =
  2487. {
  2488. LDAP_MOD_REPLACE,
  2489. "sudoHost",
  2490. host_values
  2491. };
  2492. char *cmd_values[] = {(sudoCommand&&*sudoCommand)?sudoCommand:NULL, NULL };
  2493. LDAPMod cmd_attr =
  2494. {
  2495. LDAP_MOD_REPLACE,
  2496. "sudoCommand",
  2497. cmd_values
  2498. };
  2499. char *option_values[] = {(sudoOption&&*sudoOption)?sudoOption:NULL, NULL };
  2500. LDAPMod option_attr =
  2501. {
  2502. LDAP_MOD_REPLACE,
  2503. "sudoOption",
  2504. option_values
  2505. };
  2506. LDAPMod *attrs[4];
  2507. int ind = 0;
  2508. attrs[ind++] = &host_attr;
  2509. attrs[ind++] = &cmd_attr;
  2510. attrs[ind++] = &option_attr;
  2511. attrs[ind] = NULL;
  2512. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2513. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2514. StringBuffer dn;
  2515. dn.append("cn=").append(username).append(",").append(m_ldapconfig->getResourceBasedn(RT_SUDOERS));
  2516. int rc = ldap_modify_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  2517. if ( rc != LDAP_SUCCESS )
  2518. {
  2519. DBGLOG("error modifying sudoers for user %s: %s", username, ldap_err2string( rc ));
  2520. throw MakeStringException(-1, "error modifying sudoers for user %s: %s", username, ldap_err2string( rc ));
  2521. }
  2522. }
  2523. if (rc == LDAP_SUCCESS )
  2524. DBGLOG("User %s successfully updated", username);
  2525. else
  2526. throw MakeStringException(-1, "Error updating user %s - %s", username, ldap_err2string( rc ));
  2527. return true;
  2528. }
  2529. virtual bool changePasswordSSL(const char* username, const char* newPassword)
  2530. {
  2531. Owned<ILdapConnection> lconn;
  2532. try
  2533. {
  2534. lconn.setown(m_connections->getSSLConnection());
  2535. }
  2536. catch(IException*)
  2537. {
  2538. throw MakeStringException(-1, "Failed to set user %s's password because of not being able to create an SSL connection to the ldap server. To set an Active Directory user's password from Linux, you need to enable SSL on the Active Directory ldap server", username);
  2539. }
  2540. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2541. char *attribute, **values = NULL;
  2542. LDAPMessage *message;
  2543. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  2544. StringBuffer filter;
  2545. filter.append("sAMAccountName=").append(username);
  2546. char *attrs[] = {"distinguishedName", NULL};
  2547. CLDAPMessage searchResult;
  2548. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  2549. if ( rc != LDAP_SUCCESS )
  2550. {
  2551. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  2552. return false;
  2553. }
  2554. StringBuffer userdn;
  2555. message = LdapFirstEntry( ld, searchResult);
  2556. if(message != NULL)
  2557. {
  2558. CLDAPGetAttributesWrapper atts(ld, searchResult);
  2559. for ( attribute = atts.getFirst();
  2560. attribute != NULL;
  2561. attribute = atts.getNext())
  2562. {
  2563. if(0 == stricmp(attribute, "distinguishedName"))
  2564. {
  2565. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2566. if (vals.hasValues())
  2567. userdn.set(vals.queryCharValue(0));
  2568. break;
  2569. }
  2570. }
  2571. }
  2572. if(userdn.length() == 0)
  2573. {
  2574. throw MakeStringException(-1, "can't find dn for user %s", username);
  2575. }
  2576. LDAPMod modPassword;
  2577. LDAPMod *modEntry[2];
  2578. struct berval pwdBerVal;
  2579. struct berval *pwd_attr[2];
  2580. unsigned short pszPasswordWithQuotes[1024];
  2581. modEntry[0] = &modPassword;
  2582. modEntry[1] = NULL;
  2583. modPassword.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  2584. modPassword.mod_type = "unicodePwd";
  2585. modPassword.mod_vals.modv_bvals = pwd_attr;
  2586. pwd_attr[0] = &pwdBerVal;
  2587. pwd_attr[1]= NULL;
  2588. StringBuffer quotedPasswd("\"");
  2589. quotedPasswd.append(newPassword).append("\"");
  2590. ConvertCToW(pszPasswordWithQuotes, quotedPasswd);
  2591. pwdBerVal.bv_len = quotedPasswd.length() * sizeof(unsigned short);
  2592. pwdBerVal.bv_val = (char*)pszPasswordWithQuotes;
  2593. rc = ldap_modify_ext_s(ld, (char*)userdn.str(), modEntry, NULL, NULL);
  2594. if (rc == LDAP_SUCCESS )
  2595. DBGLOG("User %s's password has been changed successfully", username);
  2596. else
  2597. {
  2598. StringBuffer errmsg;
  2599. errmsg.appendf("Error setting password for %s - (%d) %s.", username, rc, ldap_err2string( rc ));
  2600. if(rc == LDAP_UNWILLING_TO_PERFORM)
  2601. errmsg.append(" The ldap server refused to change the password. Usually this is because your new password doesn't satisfy the domain policy.");
  2602. throw MakeStringExceptionDirect(-1, errmsg.str());
  2603. }
  2604. return true;
  2605. }
  2606. virtual bool queryPasswordStatus(ISecUser& user, const char* password)
  2607. {
  2608. char *ldap_errstring = NULL;
  2609. const char * username = user.getName();
  2610. StringBuffer userdn;
  2611. getUserDN(user.getName(), userdn);
  2612. StringBuffer hostbuf;
  2613. m_ldapconfig->getLdapHost(hostbuf);
  2614. LDAP* user_ld = LdapUtils::LdapInit(m_ldapconfig->getProtocol(), hostbuf.str(), m_ldapconfig->getLdapPort(), m_ldapconfig->getLdapSecurePort());
  2615. int rc = LdapUtils::LdapBind(user_ld, m_ldapconfig->getDomain(), username, password, userdn, m_ldapconfig->getServerType(), m_ldapconfig->getAuthMethod());
  2616. if(rc != LDAP_SUCCESS)
  2617. ldap_get_option(user_ld, LDAP_OPT_ERROR_STRING, &ldap_errstring);
  2618. LDAP_UNBIND(user_ld);
  2619. //Error string ""80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 532, v1db0."
  2620. //is returned if pw valid but expired
  2621. if(rc == LDAP_SUCCESS || strstr(ldap_errstring, "data 532") || strstr(ldap_errstring, "data 773"))//
  2622. return true;
  2623. else
  2624. return false;
  2625. }
  2626. virtual bool updateUserPassword(ISecUser& user, const char* newPassword, const char* currPassword)
  2627. {
  2628. const char* username = user.getName();
  2629. if(!username || !*username)
  2630. return false;
  2631. if (currPassword)
  2632. {
  2633. //User will not be authenticated if their password was expired,
  2634. //so check here that they provided a valid one in the "change
  2635. //password" form (use the one they type, not the one in the secuser)
  2636. bool validated = queryPasswordStatus(user, currPassword);
  2637. if (!validated)
  2638. throw MakeStringException(-1, "Password not changed, invalid credentials");
  2639. }
  2640. return updateUserPassword(username, newPassword);
  2641. }
  2642. virtual bool updateUserPassword(const char* username, const char* newPassword)
  2643. {
  2644. if(!username || !*username)
  2645. return false;
  2646. const char* sysuser = m_ldapconfig->getSysUser();
  2647. if(sysuser && *sysuser && strcmp(username, sysuser) == 0)
  2648. throw MakeStringException(-1, "You can't change password of the system user.");
  2649. LdapServerType servertype = m_ldapconfig->getServerType();
  2650. bool ret = true;
  2651. if(servertype == ACTIVE_DIRECTORY)
  2652. {
  2653. #ifdef _WIN32
  2654. DWORD nStatus = 0;
  2655. // The application has to run on the same domain as ldap host, and under an administrative user.
  2656. USER_INFO_1003 usriSetPassword;
  2657. StringBuffer fullserver("\\\\");
  2658. StringBuffer server;
  2659. m_ldapconfig->getLdapHost(server);
  2660. fullserver.append(server.str());
  2661. LPWSTR whost = (LPWSTR)alloca((fullserver.length() +1) * sizeof(WCHAR));
  2662. ConvertCToW((unsigned short *)whost, fullserver.str());
  2663. LPWSTR wusername = (LPWSTR)alloca((strlen(username) + 1) * sizeof(WCHAR));
  2664. ConvertCToW((unsigned short *)wusername, username);
  2665. LPWSTR wnewpasswd = (LPWSTR)alloca((strlen(newPassword) + 1) * sizeof(WCHAR));
  2666. ConvertCToW((unsigned short *)wnewpasswd, newPassword);
  2667. usriSetPassword.usri1003_password = wnewpasswd;
  2668. nStatus = NetUserSetInfo(whost, wusername, 1003, (LPBYTE)&usriSetPassword, NULL);
  2669. if (nStatus == NERR_Success)
  2670. {
  2671. DBGLOG("User %s's password has been changed successfully", username);
  2672. return true;
  2673. }
  2674. else
  2675. {
  2676. StringBuffer errcode, errmsg;
  2677. if(nStatus == ERROR_ACCESS_DENIED)
  2678. {
  2679. errcode.append("ERROR_ACCESS_DENIED");
  2680. errmsg.append("The user does not have access to the requested information.");
  2681. }
  2682. else if(nStatus == ERROR_INVALID_PASSWORD)
  2683. {
  2684. errcode.append("ERROR_INVALID_PASSWORD");
  2685. errmsg.append("The user has entered an invalid password.");
  2686. }
  2687. else if(nStatus == NERR_InvalidComputer)
  2688. {
  2689. errcode.append("NERR_InvalidComputer");
  2690. errmsg.append("The computer name is invalid.");
  2691. }
  2692. else if(nStatus == NERR_NotPrimary)
  2693. {
  2694. errcode.append("NERR_NotPrimary");
  2695. errmsg.append("The operation is allowed only on the primary domain controller of the domain.");
  2696. }
  2697. else if(nStatus == NERR_UserNotFound)
  2698. {
  2699. errcode.append("NERR_UserNotFound");
  2700. errmsg.append("The user name could not be found.");
  2701. }
  2702. else if(nStatus == NERR_PasswordTooShort)
  2703. {
  2704. errcode.append("NERR_PasswordTooShort");
  2705. errmsg.append("The password is shorter than required. ");
  2706. }
  2707. else if(nStatus == ERROR_LOGON_FAILURE)
  2708. {
  2709. errcode.append("ERROR_LOGON_FAILURE");
  2710. errmsg.append("To be able to reset password this way, esp has to run under an administrative user on the same domain as the active directory. ");
  2711. }
  2712. else
  2713. {
  2714. errcode.appendf("%d", nStatus);
  2715. errmsg.append("");
  2716. }
  2717. // For certain errors just return, other errors try changePasswordSSL.
  2718. if(nStatus == ERROR_INVALID_PASSWORD || nStatus == NERR_UserNotFound || nStatus == NERR_PasswordTooShort)
  2719. throw MakeStringException(-1, "An error has occurred while setting password with NetUserSetInfo for %s: %s - %s\n", username, errcode.str(), errmsg.str());
  2720. else
  2721. DBGLOG("An error has occurred while setting password with NetUserSetInfo for %s: %s - %s\n", username, errcode.str(), errmsg.str());
  2722. }
  2723. DBGLOG("Trying changePasswordSSL to change password over regular SSL connection.");
  2724. #endif
  2725. changePasswordSSL(username, newPassword);
  2726. }
  2727. else
  2728. {
  2729. StringBuffer filter;
  2730. filter.append("uid=").append(username);
  2731. char **values = NULL;
  2732. LDAPMessage *message;
  2733. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  2734. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2735. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2736. char *attrs[] = {LDAP_NO_ATTRS, NULL};
  2737. CLDAPMessage searchResult;
  2738. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  2739. if ( rc != LDAP_SUCCESS )
  2740. {
  2741. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  2742. return false;
  2743. }
  2744. StringBuffer userdn;
  2745. message = LdapFirstEntry( ld, searchResult);
  2746. if(message != NULL)
  2747. {
  2748. char *p = ldap_get_dn(ld, message);
  2749. userdn.append(p);
  2750. ldap_memfree(p);
  2751. }
  2752. char* passwdvalue[] = { (char*)newPassword, NULL };
  2753. LDAPMod pmod =
  2754. {
  2755. LDAP_MOD_REPLACE,
  2756. "userpassword",
  2757. passwdvalue
  2758. };
  2759. LDAPMod* pmods[] = {&pmod, NULL};
  2760. rc = ldap_modify_ext_s(ld, (char*)userdn.str(), pmods, NULL, NULL);
  2761. if (rc == LDAP_SUCCESS )
  2762. DBGLOG("User %s's password has been changed successfully", username);
  2763. else
  2764. {
  2765. StringBuffer errmsg;
  2766. errmsg.appendf("Error changing password for %s - (%d) %s.", username, rc, ldap_err2string( rc ));
  2767. if(rc == LDAP_UNWILLING_TO_PERFORM)
  2768. errmsg.append(" The ldap server refused to execute the password change action, one of the reasons might be that the new password you entered doesn't satisfy the policy requirement.");
  2769. throw MakeStringExceptionDirect(-1, errmsg.str());
  2770. }
  2771. }
  2772. return true;
  2773. }
  2774. virtual bool getResources(SecResourceType rtype, const char * basedn, const char* prefix, IArrayOf<ISecResource>& resources)
  2775. {
  2776. char *attribute;
  2777. LDAPMessage *message;
  2778. StringBuffer basednbuf;
  2779. LdapUtils::normalizeDn(basedn, m_ldapconfig->getBasedn(), basednbuf);
  2780. StringBuffer filter("objectClass=*");
  2781. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  2782. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2783. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2784. const char* fldname;
  2785. LdapServerType servertype = m_ldapconfig->getServerType();
  2786. if(servertype == ACTIVE_DIRECTORY && (rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE))
  2787. fldname = "name";
  2788. else
  2789. fldname = "ou";
  2790. char *attrs[] = {(char*)fldname, "description", NULL};
  2791. CPagedLDAPSearch pagedSrch(ld, (char*)basednbuf.str(), LDAP_SCOPE_ONELEVEL, (char*)filter.str(), attrs);
  2792. for (message = pagedSrch.getFirstEntry(); message; message = pagedSrch.getNextEntry())
  2793. {
  2794. // Go through the search results by checking message types
  2795. CLDAPGetAttributesWrapper atts(ld, message);
  2796. for ( attribute = atts.getFirst();
  2797. attribute != NULL;
  2798. attribute = atts.getNext())
  2799. {
  2800. StringBuffer descbuf;
  2801. StringBuffer curname;
  2802. CLDAPGetAttributesWrapper atts(ld, message);
  2803. for ( attribute = atts.getFirst();
  2804. attribute != NULL;
  2805. attribute = atts.getNext())
  2806. {
  2807. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2808. if (vals.hasValues())
  2809. {
  2810. const char* val = vals.queryCharValue(0);
  2811. if(val != NULL)
  2812. {
  2813. if(stricmp(attribute, fldname) == 0)
  2814. {
  2815. curname.append(val);
  2816. }
  2817. else if(stricmp(attribute, "description") == 0)
  2818. {
  2819. descbuf.append(val);
  2820. }
  2821. }
  2822. }
  2823. }
  2824. if(curname.length() == 0)
  2825. continue;
  2826. StringBuffer resourcename;
  2827. if(prefix != NULL && *prefix != '\0')
  2828. resourcename.append(prefix);
  2829. resourcename.append(curname.str());
  2830. CLdapSecResource* resource = new CLdapSecResource(resourcename.str());
  2831. resource->setDescription(descbuf.str());
  2832. resources.append(*resource);
  2833. if(rtype == RT_FILE_SCOPE || rtype == RT_WORKUNIT_SCOPE)
  2834. {
  2835. StringBuffer nextbasedn;
  2836. nextbasedn.append("ou=").append(curname.str()).append(",").append(basedn);
  2837. StringBuffer nextprefix;
  2838. if(prefix != NULL && *prefix != '\0')
  2839. nextprefix.append(prefix);
  2840. nextprefix.append(curname.str()).append("::");
  2841. getResources(rtype, nextbasedn.str(), nextprefix.str(), resources);
  2842. }
  2843. }
  2844. }
  2845. return true;
  2846. }
  2847. virtual bool getResourcesEx(SecResourceType rtype, const char * basedn, const char* prefix, const char* searchstr, IArrayOf<ISecResource>& resources)
  2848. {
  2849. char *attribute;
  2850. LDAPMessage *message;
  2851. StringBuffer basednbuf;
  2852. LdapUtils::normalizeDn(basedn, m_ldapconfig->getBasedn(), basednbuf);
  2853. StringBuffer filter("objectClass=*");
  2854. if(searchstr && *searchstr && strcmp(searchstr, "*") != 0)
  2855. {
  2856. filter.insert(0, "(&(");
  2857. filter.appendf(")(|(%s=*%s*)))", "uNCName", searchstr);
  2858. }
  2859. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  2860. Owned<ILdapConnection> lconn = m_connections->getConnection();
  2861. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  2862. const char* fldname;
  2863. LdapServerType servertype = m_ldapconfig->getServerType();
  2864. if(servertype == ACTIVE_DIRECTORY && (rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE))
  2865. fldname = "name";
  2866. else
  2867. fldname = "ou";
  2868. char *attrs[] = {(char*)fldname, "description", NULL};
  2869. CPagedLDAPSearch pagedSrch(ld, (char*)basednbuf.str(), LDAP_SCOPE_ONELEVEL, (char*)filter.str(), attrs);
  2870. for (message = pagedSrch.getFirstEntry(); message; message = pagedSrch.getNextEntry())
  2871. {
  2872. // Go through the search results by checking message types
  2873. StringBuffer descbuf;
  2874. StringBuffer curname;
  2875. CLDAPGetAttributesWrapper atts(ld, message);
  2876. for ( attribute = atts.getFirst();
  2877. attribute != NULL;
  2878. attribute = atts.getNext())
  2879. {
  2880. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  2881. if (vals.hasValues())
  2882. {
  2883. const char * val = vals.queryCharValue(0);
  2884. if(val != NULL)
  2885. {
  2886. if(stricmp(attribute, fldname) == 0)
  2887. {
  2888. curname.append(val);
  2889. }
  2890. else if(stricmp(attribute, "description") == 0)
  2891. {
  2892. descbuf.append(val);
  2893. }
  2894. }
  2895. }
  2896. }
  2897. if(curname.length() == 0)
  2898. continue;
  2899. StringBuffer resourcename;
  2900. if(prefix != NULL && *prefix != '\0')
  2901. resourcename.append(prefix);
  2902. resourcename.append(curname.str());
  2903. CLdapSecResource* resource = new CLdapSecResource(resourcename.str());
  2904. resource->setDescription(descbuf.str());
  2905. resources.append(*resource);
  2906. if(rtype == RT_FILE_SCOPE || rtype == RT_WORKUNIT_SCOPE)
  2907. {
  2908. StringBuffer nextbasedn;
  2909. nextbasedn.append("ou=").append(curname.str()).append(",").append(basedn);
  2910. StringBuffer nextprefix;
  2911. if(prefix != NULL && *prefix != '\0')
  2912. nextprefix.append(prefix);
  2913. nextprefix.append(curname.str()).append("::");
  2914. getResources(rtype, nextbasedn.str(), nextprefix.str(), resources);
  2915. }
  2916. }
  2917. return true;
  2918. }
  2919. virtual IPropertyTreeIterator* getResourceIterator(SecResourceType rtype, const char * basedn,
  2920. const char* prefix, const char* resourceName, unsigned extraNameFilter)
  2921. {
  2922. IArrayOf<ISecResource> resources;
  2923. getResourcesEx(rtype, basedn, prefix, resourceName, resources);
  2924. Owned<IPTree> resourceTree = createPTree("Resources");
  2925. ForEachItemIn(i, resources)
  2926. {
  2927. ISecResource& resource = resources.item(i);
  2928. const char* resourceName = resource.getName();
  2929. if (!resourceName || !*resourceName)
  2930. continue;
  2931. if (checkResourceNameExtraFilter(rtype, resourceName, extraNameFilter))
  2932. addResourceTree(resourceName, resource.getDescription(), resourceTree);
  2933. }
  2934. return resourceTree->getElements("*");
  2935. }
  2936. bool checkResourceNameExtraFilter(SecResourceType rtype, const char* name, unsigned extraNameFilter)
  2937. {
  2938. if((rtype == RT_FILE_SCOPE) && (extraNameFilter & RF_RT_FILE_SCOPE_FILE) && strieq(name, "file"))
  2939. return false;
  2940. if((rtype == RT_MODULE) && (extraNameFilter & RF_RT_MODULE_NO_REPOSITORY) && strnicmp(name, "repository.", 11))
  2941. return false;
  2942. return true;
  2943. }
  2944. void addResourceTree(const char* name, const char* desc, IPropertyTree* elements)
  2945. {
  2946. if (!name || !*name)
  2947. return;
  2948. Owned<IPTree> element = createPTree();
  2949. element->addProp(getResourceFieldNames(RFName), name);
  2950. if (desc && *desc)
  2951. element->addProp(getResourceFieldNames(RFDesc), desc);
  2952. elements->addPropTree("Resource", element.getClear());
  2953. }
  2954. ISecItemIterator* getResourcesSorted(SecResourceType rtype, const char * basedn, const char* resourceName, unsigned extraNameFilter,
  2955. ResourceField* sortOrder, const unsigned pageStartFrom, const unsigned pageSize, unsigned* total, __int64* cacheHint)
  2956. {
  2957. class CElementsPager : public CSimpleInterface, implements IElementsPager
  2958. {
  2959. ILdapClient* ldapClient;
  2960. StringAttr sortOrder, basedn, resourceName;
  2961. SecResourceType rtype;
  2962. unsigned extraNameFilter;
  2963. public:
  2964. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2965. CElementsPager(ILdapClient* _ldapClient, SecResourceType _rtype, const char * _basedn, const char* _resourceName,
  2966. unsigned _extraNameFilter, const char*_sortOrder) : ldapClient(_ldapClient), rtype(_rtype), basedn(_basedn),
  2967. resourceName(_resourceName), extraNameFilter(_extraNameFilter), sortOrder(_sortOrder) { };
  2968. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree>& elements)
  2969. {
  2970. StringArray unknownAttributes;
  2971. Owned<IPropertyTreeIterator> iter = ldapClient->getResourceIterator(rtype, basedn.get(), "", resourceName.get(), extraNameFilter);
  2972. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  2973. return NULL;
  2974. }
  2975. virtual bool allMatchingElementsReceived() { return true; }//For now, ldap always returns all of matched users.
  2976. };
  2977. StringBuffer so;
  2978. if (sortOrder)
  2979. {
  2980. for (unsigned i=0;sortOrder[i]!=RFterm;i++)
  2981. {
  2982. if (so.length())
  2983. so.append(',');
  2984. int fmt = sortOrder[i];
  2985. if (fmt&UFreverse)
  2986. so.append('-');
  2987. if (fmt&UFnocase)
  2988. so.append('?');
  2989. if (fmt&UFnumeric)
  2990. so.append('#');
  2991. so.append(getUserFieldNames((UserField) (fmt&0xff)));
  2992. }
  2993. }
  2994. IArrayOf<IPropertyTree> results;
  2995. Owned<IElementsPager> elementsPager = new CElementsPager(this, rtype, basedn, resourceName, extraNameFilter, so.length()?so.str():NULL);
  2996. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager, pageStartFrom, pageSize, NULL, "", cacheHint, results, total, NULL, false);
  2997. return new CSecItemIterator(results);
  2998. }
  2999. virtual bool getPermissionsArray(const char* basedn, SecResourceType rtype, const char* name, IArrayOf<CPermission>& permissions)
  3000. {
  3001. StringBuffer basednbuf;
  3002. LdapUtils::normalizeDn(basedn, m_ldapconfig->getBasedn(), basednbuf);
  3003. Owned<CSecurityDescriptor> sd = new CSecurityDescriptor(name);
  3004. IArrayOf<CSecurityDescriptor> sdlist;
  3005. sdlist.append(*LINK(sd));
  3006. if(rtype == RT_FILE_SCOPE || rtype == RT_WORKUNIT_SCOPE)
  3007. getSecurityDescriptorsScope(sdlist, basednbuf.str());
  3008. else
  3009. getSecurityDescriptors(sdlist, basednbuf.str());
  3010. m_pp->getPermissionsArray(sd.get(), permissions);
  3011. return true;
  3012. }
  3013. virtual void getAllGroups(StringArray & groups, StringArray & managedBy, StringArray & descriptions)
  3014. {
  3015. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3016. {
  3017. groups.append("Authenticated Users");
  3018. managedBy.append("");
  3019. descriptions.append("");
  3020. groups.append("Administrators");
  3021. managedBy.append("");
  3022. descriptions.append("");
  3023. }
  3024. else
  3025. {
  3026. groups.append("Directory Administrators");
  3027. managedBy.append("");
  3028. descriptions.append("");
  3029. }
  3030. char *attribute;
  3031. LDAPMessage *message;
  3032. StringBuffer filter;
  3033. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3034. filter.append("objectClass=group");
  3035. else
  3036. filter.append("objectClass=groupofuniquenames");
  3037. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3038. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3039. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3040. char *attrs[] = {"cn", "managedBy", "description", NULL};
  3041. CPagedLDAPSearch pagedSrch(ld, (char*)m_ldapconfig->getGroupBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs);
  3042. for (message = pagedSrch.getFirstEntry(); message; message = pagedSrch.getNextEntry())
  3043. {
  3044. // Go through the search results by checking message types
  3045. CLDAPGetAttributesWrapper atts(ld, message);
  3046. for ( attribute = atts.getFirst();
  3047. attribute != NULL;
  3048. attribute = atts.getNext())
  3049. {
  3050. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  3051. if (!vals.hasValues())
  3052. continue;
  3053. if(stricmp(attribute, "cn") == 0)
  3054. {
  3055. groups.append(vals.queryCharValue(0));
  3056. managedBy.append("");
  3057. descriptions.append("");
  3058. }
  3059. else if(stricmp(attribute, "managedBy") == 0)
  3060. managedBy.replace(vals.queryCharValue(0), groups.length() - 1);
  3061. else if(stricmp(attribute, "description") == 0)
  3062. descriptions.replace(vals.queryCharValue(0), groups.length() - 1);
  3063. }
  3064. }
  3065. }
  3066. virtual IPropertyTreeIterator* getGroupIterator()
  3067. {
  3068. StringArray groupNames, managedBy, descriptions;
  3069. getAllGroups(groupNames, managedBy, descriptions);
  3070. Owned<IPTree> groups = createPTree("Groups");
  3071. ForEachItemIn(i, groupNames)
  3072. addGroupTree(groupNames.item(i), managedBy.item(i), descriptions.item(i), groups);
  3073. return groups->getElements("*");
  3074. }
  3075. void addGroupTree(const char* name, const char* manageBy, const char* desc, IPropertyTree* groups)
  3076. {
  3077. if (!name || !*name)
  3078. return;
  3079. Owned<IPTree> group = createPTree();
  3080. group->addProp(getGroupFieldNames(GFName), name);
  3081. if (manageBy && *manageBy)
  3082. group->addProp(getGroupFieldNames(GFManagedBy), manageBy);
  3083. if (desc && *desc)
  3084. group->addProp(getGroupFieldNames(GFDesc), desc);
  3085. groups->addPropTree("Group", group.getClear());
  3086. }
  3087. ISecItemIterator* getGroupsSorted(GroupField* sortOrder, const unsigned pageStartFrom, const unsigned pageSize, unsigned* total, __int64* cacheHint)
  3088. {
  3089. class CElementsPager : public CSimpleInterface, implements IElementsPager
  3090. {
  3091. ILdapClient* ldapClient;
  3092. StringAttr sortOrder;
  3093. public:
  3094. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  3095. CElementsPager(ILdapClient* _ldapClient, const char*_sortOrder)
  3096. : ldapClient(_ldapClient), sortOrder(_sortOrder) { };
  3097. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree>& elements)
  3098. {
  3099. StringArray unknownAttributes;
  3100. Owned<IPropertyTreeIterator> iter = ldapClient->getGroupIterator();
  3101. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  3102. return NULL;
  3103. }
  3104. virtual bool allMatchingElementsReceived() { return true; }//For now, ldap always returns all of matched users.
  3105. };
  3106. StringBuffer so;
  3107. if (sortOrder)
  3108. {
  3109. for (unsigned i=0;sortOrder[i]!=GFterm;i++)
  3110. {
  3111. if (so.length())
  3112. so.append(',');
  3113. int fmt = sortOrder[i];
  3114. if (fmt&UFreverse)
  3115. so.append('-');
  3116. if (fmt&UFnocase)
  3117. so.append('?');
  3118. if (fmt&UFnumeric)
  3119. so.append('#');
  3120. so.append(getUserFieldNames((UserField) (fmt&0xff)));
  3121. }
  3122. }
  3123. IArrayOf<IPropertyTree> results;
  3124. Owned<IElementsPager> elementsPager = new CElementsPager(this, so.length()?so.str():NULL);
  3125. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager, pageStartFrom, pageSize, NULL, "", cacheHint, results, total, NULL, false);
  3126. return new CSecItemIterator(results);
  3127. }
  3128. virtual bool changePermission(CPermissionAction& action)
  3129. {
  3130. StringBuffer basednbuf;
  3131. LdapUtils::normalizeDn(action.m_basedn.str(), m_ldapconfig->getBasedn(), basednbuf);
  3132. Owned<CSecurityDescriptor> sd = new CSecurityDescriptor(action.m_rname.str());
  3133. IArrayOf<CSecurityDescriptor> sdlist;
  3134. sdlist.append(*LINK(sd));
  3135. if(action.m_rtype == RT_FILE_SCOPE || action.m_rtype == RT_WORKUNIT_SCOPE)
  3136. getSecurityDescriptorsScope(sdlist, basednbuf.str());
  3137. else
  3138. getSecurityDescriptors(sdlist, basednbuf.str());
  3139. if(m_ldapconfig->getServerType() != ACTIVE_DIRECTORY)
  3140. {
  3141. StringBuffer act_dn;
  3142. if(action.m_account_type == GROUP_ACT)
  3143. getGroupDN(action.m_account_name.str(), act_dn);
  3144. else
  3145. getUserDN(action.m_account_name.str(), act_dn);
  3146. action.m_account_name.clear().append(act_dn.str());
  3147. }
  3148. Owned<CSecurityDescriptor> newsd = m_pp->changePermission(sd.get(), action);
  3149. StringBuffer normdnbuf;
  3150. LdapServerType servertype = m_ldapconfig->getServerType();
  3151. name2dn(action.m_rtype, action.m_rname.str(), action.m_basedn.str(), normdnbuf);
  3152. char *empty_values[] = { NULL };
  3153. int numberOfSegs = m_pp->sdSegments(newsd.get());
  3154. LDAPMod *attrs[2];
  3155. LDAPMod sd_attr;
  3156. if(newsd->getDescriptor().length() > 0)
  3157. {
  3158. struct berval** sd_values = (struct berval**)alloca(sizeof(struct berval*)*(numberOfSegs+1));
  3159. MemoryBuffer& sdbuf = newsd->getDescriptor();
  3160. // Active Directory acutally has only one segment.
  3161. if(servertype == ACTIVE_DIRECTORY)
  3162. {
  3163. struct berval* sd_val = (struct berval*)alloca(sizeof(struct berval));
  3164. sd_val->bv_len = sdbuf.length();
  3165. sd_val->bv_val = (char*)sdbuf.toByteArray();
  3166. sd_values[0] = sd_val;
  3167. sd_values[1] = NULL;
  3168. sd_attr.mod_type = "nTSecurityDescriptor";
  3169. }
  3170. else
  3171. {
  3172. const char* bbptr = sdbuf.toByteArray();
  3173. const char* bptr = sdbuf.toByteArray();
  3174. int sdbuflen = sdbuf.length();
  3175. int segind;
  3176. for(segind = 0; segind < numberOfSegs; segind++)
  3177. {
  3178. if(bptr - bbptr >= sdbuflen)
  3179. break;
  3180. while(*bptr == '\0' && (bptr - bbptr) < sdbuflen)
  3181. bptr++;
  3182. const char* eptr = bptr;
  3183. while(*eptr != '\0' && (eptr - bbptr) < sdbuflen)
  3184. eptr++;
  3185. struct berval* sd_val = (struct berval*)alloca(sizeof(struct berval));
  3186. sd_val->bv_len = eptr - bptr;
  3187. sd_val->bv_val = (char*)bptr;
  3188. sd_values[segind] = sd_val;
  3189. bptr = eptr + 1;
  3190. }
  3191. sd_values[segind] = NULL;
  3192. sd_attr.mod_type = (char*)m_ldapconfig->getSdFieldName();
  3193. }
  3194. sd_attr.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  3195. sd_attr.mod_vals.modv_bvals = sd_values;
  3196. attrs[0] = &sd_attr;
  3197. }
  3198. else
  3199. {
  3200. if(m_ldapconfig->getServerType() == OPEN_LDAP)
  3201. throw MakeStringException(-1, "removing all permissions for openldap is currently not supported");
  3202. sd_attr.mod_op = LDAP_MOD_DELETE;
  3203. sd_attr.mod_type = (char*)m_ldapconfig->getSdFieldName();
  3204. sd_attr.mod_vals.modv_strvals = empty_values;
  3205. attrs[0] = &sd_attr;
  3206. }
  3207. attrs[1] = NULL;
  3208. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3209. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3210. int rc = ldap_modify_ext_s(ld, (char*)normdnbuf.str(), attrs, NULL, NULL);
  3211. if ( rc != LDAP_SUCCESS )
  3212. {
  3213. throw MakeStringException(-1, "ldap_modify_ext_s error: %d %s", rc, ldap_err2string( rc ));
  3214. }
  3215. return true;
  3216. }
  3217. virtual void getGroups(const char *user, StringArray& groups)
  3218. {
  3219. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3220. {
  3221. char *attribute;
  3222. LDAPMessage *message;
  3223. if(user == NULL || strlen(user) == 0)
  3224. return;
  3225. StringBuffer filter("sAMAccountName=");
  3226. filter.append(user);
  3227. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3228. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3229. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3230. char *attrs[] = {"memberOf", NULL};
  3231. CLDAPMessage searchResult;
  3232. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  3233. if ( rc != LDAP_SUCCESS )
  3234. {
  3235. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  3236. return;
  3237. }
  3238. unsigned entries = ldap_count_entries(ld, searchResult);
  3239. if(entries == 0)
  3240. {
  3241. searchResult.ldapMsgFree();
  3242. rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getSysUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  3243. if ( rc != LDAP_SUCCESS )
  3244. {
  3245. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getSysUserBasedn());
  3246. return;
  3247. }
  3248. }
  3249. // Go through the search results by checking message types
  3250. for(message = LdapFirstEntry( ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  3251. {
  3252. CLDAPGetAttributesWrapper atts(ld, searchResult);
  3253. for ( attribute = atts.getFirst();
  3254. attribute != NULL;
  3255. attribute = atts.getNext())
  3256. {
  3257. if(0 == stricmp(attribute, "memberOf"))
  3258. {
  3259. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  3260. if (vals.hasValues())
  3261. {
  3262. for (int i = 0; vals.queryBValues()[ i ] != NULL; i++ )
  3263. {
  3264. const char* val = vals.queryCharValue(i);
  3265. char* comma = strchr((char*)val, ',');
  3266. StringBuffer groupname;
  3267. groupname.append(comma - val -3, val+3);
  3268. groups.append(groupname.str());
  3269. }
  3270. }
  3271. }
  3272. }
  3273. }
  3274. }
  3275. else
  3276. {
  3277. StringArray allgroups;
  3278. StringArray allgroupManagedBy;
  3279. StringArray allgroupDescription;
  3280. getAllGroups(allgroups, allgroupManagedBy, allgroupDescription);
  3281. for(unsigned i = 0; i < allgroups.length(); i++)
  3282. {
  3283. const char* grp = allgroups.item(i);
  3284. StringBuffer grpdn, usrdn;
  3285. getUserDN(user, usrdn);
  3286. getGroupDN(grp, grpdn);
  3287. if(userInGroup(usrdn.str(), grpdn.str()))
  3288. {
  3289. groups.append(grp);
  3290. }
  3291. }
  3292. }
  3293. }
  3294. virtual void changeUserGroup(const char* action, const char* username, const char* groupname)
  3295. {
  3296. StringBuffer userdn, groupdn;
  3297. getUserDN(username, userdn);
  3298. getGroupDN(groupname, groupdn);
  3299. // Not needed for Active Directory
  3300. // changeUserMemberOf(action, userdn.str(), groupdn.str());
  3301. changeGroupMember(action, groupdn.str(), userdn.str());
  3302. }
  3303. virtual bool deleteUser(ISecUser* user)
  3304. {
  3305. if(user == NULL)
  3306. return false;
  3307. const char* username = user->getName();
  3308. if(username == NULL || *username == '\0')
  3309. return false;
  3310. StringBuffer userdn;
  3311. getUserDN(username, userdn);
  3312. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3313. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3314. int rc = ldap_delete_ext_s(ld, (char*)userdn.str(), NULL, NULL);
  3315. if ( rc != LDAP_SUCCESS )
  3316. {
  3317. throw MakeStringException(-1, "error deleting user %s: %s", username, ldap_err2string(rc));
  3318. }
  3319. StringArray grps;
  3320. getGroups(username, grps);
  3321. ForEachItemIn(x, grps)
  3322. {
  3323. const char* grp = grps.item(x);
  3324. if(!grp || !*grp)
  3325. continue;
  3326. changeUserGroup("delete", username, grp);
  3327. }
  3328. //Remove tempfile scope for this user
  3329. StringBuffer resName(queryDfsXmlBranchName(DXB_Internal));
  3330. resName.append("::").append(username);
  3331. deleteResource(RT_FILE_SCOPE, resName.str(), m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE));
  3332. return true;
  3333. }
  3334. virtual void addGroup(const char* groupname, const char * groupOwner, const char * groupDesc)
  3335. {
  3336. if(groupname == NULL || *groupname == '\0')
  3337. throw MakeStringException(-1, "Can't add group, groupname is empty");
  3338. addGroup(groupname, groupOwner, groupDesc, m_ldapconfig->getGroupBasedn());
  3339. }
  3340. virtual void addGroup(const char* groupname, const char * groupOwner, const char * groupDesc, const char* basedn)
  3341. {
  3342. if(groupname == NULL || *groupname == '\0')
  3343. return;
  3344. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3345. {
  3346. if(stricmp(groupname, "Administrators") == 0)
  3347. throw MakeStringException(-1, "Can't add group %s, it's reserved by the system.", groupname);
  3348. }
  3349. else
  3350. {
  3351. if(stricmp(groupname, "Directory Administrators") == 0)
  3352. throw MakeStringException(-1, "Can't add group %s, it's reserved by the system.", groupname);
  3353. }
  3354. StringBuffer dn;
  3355. dn.append("cn=").append(groupname).append(",").append(basedn);
  3356. char* oc_name;
  3357. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3358. {
  3359. oc_name = "group";
  3360. }
  3361. else
  3362. {
  3363. oc_name = "groupofuniquenames";
  3364. }
  3365. char *cn_values[] = {(char*)groupname, NULL };
  3366. LDAPMod cn_attr =
  3367. {
  3368. LDAP_MOD_ADD,
  3369. "cn",
  3370. cn_values
  3371. };
  3372. char *oc_values[] = {oc_name, NULL };
  3373. LDAPMod oc_attr =
  3374. {
  3375. LDAP_MOD_ADD,
  3376. "objectClass",
  3377. oc_values
  3378. };
  3379. char *member_values[] = {"", NULL};
  3380. LDAPMod member_attr =
  3381. {
  3382. LDAP_MOD_ADD,
  3383. "uniqueMember",
  3384. member_values
  3385. };
  3386. char *owner_values[] = {(char*)groupOwner, NULL};
  3387. LDAPMod owner_attr =
  3388. {
  3389. LDAP_MOD_ADD,
  3390. "managedBy",
  3391. owner_values
  3392. };
  3393. char *desc_values[] = {(char*)groupDesc, NULL};
  3394. LDAPMod desc_attr =
  3395. {
  3396. LDAP_MOD_ADD,
  3397. "description",
  3398. desc_values
  3399. };
  3400. LDAPMod *attrs[6];
  3401. int ind = 0;
  3402. attrs[ind++] = &cn_attr;
  3403. attrs[ind++] = &oc_attr;
  3404. if (groupOwner && *groupOwner)
  3405. attrs[ind++] = &owner_attr;
  3406. if (groupDesc && *groupDesc)
  3407. attrs[ind++] = &desc_attr;
  3408. attrs[ind] = NULL;
  3409. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3410. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3411. int rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  3412. if ( rc == LDAP_INVALID_SYNTAX && m_ldapconfig->getServerType() == OPEN_LDAP)//Fedora389 does not 'seem' to need this, openLDAP does
  3413. {
  3414. attrs[ind++] = &member_attr;
  3415. attrs[ind] = NULL;
  3416. rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  3417. }
  3418. if ( rc != LDAP_SUCCESS)
  3419. {
  3420. if(rc == LDAP_ALREADY_EXISTS)
  3421. {
  3422. throw MakeStringException(-1, "can't add group %s, an LDAP object with this name already exists", groupname);
  3423. }
  3424. else
  3425. {
  3426. DBGLOG("error addGroup %s, ldap_add_ext_s error: %s", groupname, ldap_err2string( rc ));
  3427. throw MakeStringException(-1, "error addGroup %s, ldap_add_ext_s error: %s", groupname, ldap_err2string( rc ));
  3428. }
  3429. }
  3430. }
  3431. virtual void deleteGroup(const char* groupname)
  3432. {
  3433. if(groupname == NULL || *groupname == '\0')
  3434. throw MakeStringException(-1, "group name can't be empty");
  3435. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3436. {
  3437. if(stricmp(groupname, "Administrators") == 0 || stricmp(groupname, "Authenticated Users") == 0)
  3438. throw MakeStringException(-1, "you can't delete Authenticated Users or Administrators group");
  3439. }
  3440. else
  3441. {
  3442. if(stricmp(groupname, "Directory Administrators") == 0)
  3443. throw MakeStringException(-1, "you can't delete Directory Administrators group");
  3444. }
  3445. StringBuffer dn;
  3446. getGroupDN(groupname, dn);
  3447. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3448. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3449. int rc = ldap_delete_ext_s(ld, (char*)dn.str(), NULL, NULL);
  3450. if ( rc != LDAP_SUCCESS )
  3451. {
  3452. throw MakeStringException(-1, "error deleting group %s: %s", groupname, ldap_err2string(rc));
  3453. }
  3454. }
  3455. virtual void getGroupMembers(const char* groupname, StringArray & users)
  3456. {
  3457. char *attribute;
  3458. LDAPMessage *message;
  3459. if(groupname == NULL || strlen(groupname) == 0)
  3460. throw MakeStringException(-1, "group name can't be empty");
  3461. StringBuffer grpdn;
  3462. getGroupDN(groupname, grpdn);
  3463. StringBuffer filter;
  3464. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3465. {
  3466. filter.append("distinguishedName=").append(grpdn.str());
  3467. }
  3468. else if(m_ldapconfig->getServerType() == IPLANET)
  3469. {
  3470. filter.append("entrydn=").append(grpdn.str());
  3471. }
  3472. else if(m_ldapconfig->getServerType() == OPEN_LDAP)
  3473. {
  3474. filter.append("cn=").append(groupname);
  3475. }
  3476. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3477. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3478. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3479. const char* memfieldname;
  3480. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3481. {
  3482. memfieldname = "member";
  3483. }
  3484. else
  3485. {
  3486. memfieldname = "uniquemember";
  3487. }
  3488. char *attrs[] = {(char*)memfieldname, NULL};
  3489. StringBuffer groupbasedn;
  3490. getGroupBaseDN(groupname, groupbasedn);
  3491. CPagedLDAPSearch pagedSrch(ld, (char*)groupbasedn.str(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs);
  3492. for (message = pagedSrch.getFirstEntry(); message; message = pagedSrch.getNextEntry())
  3493. {
  3494. // Go through the search results by checking message types
  3495. CLDAPGetAttributesWrapper atts(ld, message);
  3496. for ( attribute = atts.getFirst();
  3497. attribute != NULL;
  3498. attribute = atts.getNext())
  3499. {
  3500. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  3501. if (vals.hasValues())
  3502. {
  3503. for (int i = 0; vals.queryBValues()[ i ] != NULL; i++ )
  3504. {
  3505. const char* val = vals.queryCharValue(i);
  3506. StringBuffer uid;
  3507. getUidFromDN(val, uid);
  3508. if(uid.length() > 0)
  3509. users.append(uid.str());
  3510. }
  3511. }
  3512. }
  3513. }
  3514. }
  3515. virtual IPropertyTreeIterator* getGroupMemberIterator(const char* groupName)
  3516. {
  3517. StringArray users;
  3518. getGroupMembers(groupName, users);
  3519. Owned<IPropertyTree> usersTree = createPTree("Users");
  3520. ForEachItemIn(i, users)
  3521. {
  3522. const char* usrName = users.item(i);
  3523. if (!usrName || !*usrName)
  3524. continue;
  3525. IUserArray usersInBaseDN;
  3526. retrieveUsers(usrName, usersInBaseDN);
  3527. ForEachItemIn(x, usersInBaseDN)
  3528. {
  3529. ISecUser& usr = usersInBaseDN.item(x);
  3530. const char* usrName0 = usr.getName();
  3531. if(usrName0 && strieq(usrName, usrName0))
  3532. {
  3533. //BUG#41536: The users in the Administrators group are all the users on the whole
  3534. //active directory, while the users in the users list are only the users who are
  3535. //under the "usersBasedn" of this environment. So, we should only return the users
  3536. //who are in the usersBasedn.
  3537. addUserTree(usr, usersTree);
  3538. break;
  3539. }
  3540. }
  3541. }
  3542. return usersTree->getElements("*");
  3543. }
  3544. ISecItemIterator* getGroupMembersSorted(const char* groupName, UserField* sortOrder, const unsigned pageStartFrom, const unsigned pageSize,
  3545. unsigned* total, __int64* cacheHint)
  3546. {
  3547. class CElementsPager : public CSimpleInterface, implements IElementsPager
  3548. {
  3549. ILdapClient* ldapClient;
  3550. StringAttr sortOrder, groupName;
  3551. public:
  3552. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  3553. CElementsPager(ILdapClient* _ldapClient, const char*_groupName, const char*_sortOrder)
  3554. : ldapClient(_ldapClient), groupName(_groupName), sortOrder(_sortOrder) { };
  3555. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree>& elements)
  3556. {
  3557. StringArray unknownAttributes;
  3558. Owned<IPropertyTreeIterator> iter = ldapClient->getGroupMemberIterator(groupName.str());
  3559. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  3560. return NULL;
  3561. }
  3562. virtual bool allMatchingElementsReceived() { return true; }//For now, ldap always returns all of matched users.
  3563. };
  3564. StringBuffer so;
  3565. if (sortOrder)
  3566. {
  3567. for (unsigned i=0;sortOrder[i]!=UFterm;i++)
  3568. {
  3569. if (so.length())
  3570. so.append(',');
  3571. int fmt = sortOrder[i];
  3572. if (fmt&UFreverse)
  3573. so.append('-');
  3574. if (fmt&UFnocase)
  3575. so.append('?');
  3576. if (fmt&UFnumeric)
  3577. so.append('#');
  3578. so.append(getUserFieldNames((UserField) (fmt&0xff)));
  3579. }
  3580. }
  3581. IArrayOf<IPropertyTree> results;
  3582. Owned<IElementsPager> elementsPager = new CElementsPager(this, groupName, so.length()?so.str():NULL);
  3583. Owned<IRemoteConnection> conn=getElementsPaged(elementsPager, pageStartFrom, pageSize, NULL, "", cacheHint, results, total, NULL, false);
  3584. return new CSecItemIterator(results);
  3585. }
  3586. virtual void deleteResource(SecResourceType rtype, const char* name, const char* basedn)
  3587. {
  3588. if(basedn == NULL || *basedn == '\0')
  3589. basedn = m_ldapconfig->getResourceBasedn(rtype);
  3590. StringBuffer dn;
  3591. name2dn(rtype, name, basedn, dn);
  3592. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3593. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3594. int rc = ldap_delete_ext_s(ld, (char*)dn.str(), NULL, NULL);
  3595. if ( rc != LDAP_SUCCESS )
  3596. {
  3597. DBGLOG("error deleting %s: %s", dn.str(), ldap_err2string(rc));
  3598. //throw MakeStringException(-1, "error deleting %s: %s", dn.str(), ldap_err2string(rc));
  3599. }
  3600. }
  3601. virtual void renameResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn)
  3602. {
  3603. if(oldname == NULL || *oldname == '\0' || newname == NULL || *newname == '\0')
  3604. throw MakeStringException(-1, "please specfiy old and new names");
  3605. if(basedn == NULL || *basedn == '\0')
  3606. basedn = m_ldapconfig->getResourceBasedn(rtype);
  3607. StringBuffer olddn, newrdn;
  3608. name2dn(rtype, oldname, basedn, olddn);
  3609. name2rdn(rtype, newname, newrdn);
  3610. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3611. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3612. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY && (rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE))
  3613. {
  3614. char* uncname_values[] = {(char*)newname, NULL};
  3615. LDAPMod uncname_attr =
  3616. {
  3617. LDAP_MOD_REPLACE,
  3618. "uNCName",
  3619. uncname_values
  3620. };
  3621. LDAPMod *attrs[2];
  3622. attrs[0] = &uncname_attr;
  3623. attrs[1] = NULL;
  3624. int rc = ldap_modify_ext_s(ld, (char*)olddn.str(), attrs, NULL, NULL);
  3625. if (rc != LDAP_SUCCESS )
  3626. {
  3627. DBGLOG("Error changing unc %s to %s - %s", oldname, newname, ldap_err2string( rc ));
  3628. //throw MakeStringException(-1, "Error changing unc %s to %s - %s", oldname, newname, ldap_err2string( rc ));
  3629. }
  3630. }
  3631. #ifdef _WIN32
  3632. int rc = ldap_rename_ext_s(ld, (char*)olddn.str(), (char*)newrdn.str(), NULL, true, NULL, NULL);
  3633. #else
  3634. int rc = ldap_rename_s(ld, (char*)olddn.str(), (char*)newrdn.str(), NULL, true, NULL, NULL);
  3635. #endif
  3636. if (rc != LDAP_SUCCESS )
  3637. {
  3638. DBGLOG("Error renaming %s to %s - %s", oldname, newname, ldap_err2string( rc ));
  3639. //throw MakeStringException(-1, "Error renaming %s to %s - %s", oldname, newname, ldap_err2string( rc ));
  3640. }
  3641. }
  3642. virtual void copyResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn)
  3643. {
  3644. if(oldname == NULL || *oldname == '\0' || newname == NULL || *newname == '\0')
  3645. throw MakeStringException(-1, "please specfiy old and new names");
  3646. if(basedn == NULL || *basedn == '\0')
  3647. basedn = m_ldapconfig->getResourceBasedn(rtype);
  3648. Owned<CSecurityDescriptor> sd = new CSecurityDescriptor(oldname);
  3649. IArrayOf<CSecurityDescriptor> sdlist;
  3650. sdlist.append(*LINK(sd));
  3651. if(rtype == RT_FILE_SCOPE || rtype == RT_WORKUNIT_SCOPE)
  3652. getSecurityDescriptorsScope(sdlist, basedn);
  3653. else
  3654. getSecurityDescriptors(sdlist, basedn);
  3655. if(sd->getDescriptor().length() == 0)
  3656. throw MakeStringException(-1, "error copying %s to %s, %s doesn't exist", oldname, newname, oldname);
  3657. ISecUser* user = NULL;
  3658. CLdapSecResource resource(newname);
  3659. addResource(rtype, *user, &resource, PT_DEFAULT, basedn, sd.get(), false);
  3660. }
  3661. void normalizeDn(const char* dn, StringBuffer& ndn)
  3662. {
  3663. LdapUtils::normalizeDn(dn, m_ldapconfig->getBasedn(), ndn);
  3664. }
  3665. virtual bool isSuperUser(ISecUser* user)
  3666. {
  3667. if(user == NULL || user->getName() == NULL)
  3668. return false;
  3669. const char* username = user->getName();
  3670. const char* sysuser = m_ldapconfig->getSysUser();
  3671. if(sysuser != NULL && stricmp(sysuser, username) == 0)
  3672. return true;
  3673. StringBuffer userdn, admingrpdn;
  3674. getUserDN(username, userdn);
  3675. getAdminGroupDN(admingrpdn);
  3676. return userInGroup(userdn.str(), admingrpdn.str());
  3677. }
  3678. virtual ILdapConfig* queryConfig()
  3679. {
  3680. return m_ldapconfig.get();
  3681. }
  3682. virtual int countUsers(const char* searchstr, int limit)
  3683. {
  3684. StringBuffer filter;
  3685. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3686. filter.append("objectClass=User");
  3687. else
  3688. filter.append("objectClass=inetorgperson");
  3689. if(searchstr && *searchstr && strcmp(searchstr, "*") != 0)
  3690. {
  3691. filter.insert(0, "(&(");
  3692. filter.appendf(")(|(%s=*%s*)(%s=*%s*)(%s=*%s*)))", (m_ldapconfig->getServerType()==ACTIVE_DIRECTORY)?"sAMAcccountName":"uid", searchstr, "givenName", searchstr, "sn", searchstr);
  3693. }
  3694. return countEntries(m_ldapconfig->getUserBasedn(), filter.str(), limit);
  3695. }
  3696. virtual int countResources(const char* basedn, const char* searchstr, int limit)
  3697. {
  3698. StringBuffer filter;
  3699. filter.append("objectClass=*");
  3700. if(searchstr && *searchstr && strcmp(searchstr, "*") != 0)
  3701. {
  3702. filter.insert(0, "(&(");
  3703. filter.appendf(")(|(%s=*%s*)))", "uNCName", searchstr);
  3704. }
  3705. return countEntries(basedn, filter.str(), limit);
  3706. }
  3707. virtual int countEntries(const char* basedn, const char* filter, int limit)
  3708. {
  3709. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3710. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3711. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3712. char *attrs[] = { LDAP_NO_ATTRS, NULL };
  3713. CPagedLDAPSearch pagedSrch(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter, attrs);
  3714. int entries = pagedSrch.countEntries();
  3715. return entries;
  3716. }
  3717. virtual const char* getPasswordStorageScheme()
  3718. {
  3719. if(m_pwscheme.length() == 0)
  3720. {
  3721. if(m_ldapconfig->getServerType() == IPLANET)
  3722. {
  3723. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3724. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3725. char* pw_attrs[] = {"nsslapd-rootpwstoragescheme", NULL};
  3726. CLDAPMessage msg;
  3727. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3728. int err = ldap_search_ext_s(ld, "cn=config", LDAP_SCOPE_BASE, "objectClass=*", pw_attrs, false, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &msg.msg);
  3729. if(err != LDAP_SUCCESS)
  3730. {
  3731. DBGLOG("ldap_search_ext_s error: %s", ldap_err2string( err ));
  3732. return NULL;
  3733. }
  3734. LDAPMessage* entry = LdapFirstEntry(ld, msg);
  3735. if(entry != NULL)
  3736. {
  3737. CLDAPGetValuesLenWrapper vals(ld, entry, "nsslapd-rootpwstoragescheme");
  3738. if (vals.hasValues())
  3739. m_pwscheme.append(vals.queryCharValue(0));
  3740. }
  3741. ldap_msgfree(msg);
  3742. }
  3743. }
  3744. if(m_pwscheme.length() == 0)
  3745. return NULL;
  3746. else
  3747. return m_pwscheme.str();
  3748. }
  3749. private:
  3750. virtual void addDC(const char* dc)
  3751. {
  3752. if(dc == NULL || *dc == '\0')
  3753. return;
  3754. StringBuffer dcname;
  3755. LdapUtils::getName(dc, dcname);
  3756. char *dc_values[] = {(char*)dcname.str(), NULL };
  3757. LDAPMod dc_attr =
  3758. {
  3759. LDAP_MOD_ADD,
  3760. "dc",
  3761. dc_values
  3762. };
  3763. char *o_values[] = {(char*)dcname.str(), NULL };
  3764. LDAPMod o_attr =
  3765. {
  3766. LDAP_MOD_ADD,
  3767. "o",
  3768. o_values
  3769. };
  3770. char *oc_values[] = {"organization", "dcObject", NULL };
  3771. LDAPMod oc_attr =
  3772. {
  3773. LDAP_MOD_ADD,
  3774. "objectClass",
  3775. oc_values
  3776. };
  3777. LDAPMod *attrs[4];
  3778. attrs[0] = &oc_attr;
  3779. attrs[1] = &o_attr;
  3780. attrs[2] = &dc_attr;
  3781. attrs[3] = NULL;
  3782. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3783. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3784. int rc = ldap_add_ext_s(ld, (char*)dc, attrs, NULL, NULL);
  3785. if ( rc != LDAP_SUCCESS )
  3786. {
  3787. if(rc == LDAP_ALREADY_EXISTS)
  3788. {
  3789. throw MakeStringException(-1, "can't add dc %s, an LDAP object with this name already exists", dc);
  3790. }
  3791. else
  3792. {
  3793. DBGLOG("error addDC %s, ldap_add_ext_s error: 0x%0x %s", dc, rc, ldap_err2string( rc ));
  3794. throw MakeStringException(-1, "error addDC %s, ldap_add_ext_s error: %s", dc, ldap_err2string( rc ));
  3795. }
  3796. }
  3797. }
  3798. virtual void getUserDN(const char* username, StringBuffer& userdn)
  3799. {
  3800. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3801. {
  3802. StringBuffer filter;
  3803. filter.append("sAMAccountName=");
  3804. filter.append(username);
  3805. char *attribute;
  3806. LDAPMessage *message;
  3807. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3808. char *dn_fieldname;
  3809. dn_fieldname = "distinguishedName";
  3810. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3811. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3812. char *attrs[] = {dn_fieldname, NULL};
  3813. CLDAPMessage searchResult;
  3814. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  3815. if ( rc != LDAP_SUCCESS )
  3816. {
  3817. throw MakeStringException(-1, "ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  3818. }
  3819. unsigned entries = ldap_count_entries(ld, searchResult);
  3820. if(entries == 0)
  3821. {
  3822. searchResult.ldapMsgFree();
  3823. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getSysUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  3824. if ( rc != LDAP_SUCCESS )
  3825. {
  3826. throw MakeStringException(-1, "ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getSysUserBasedn());
  3827. }
  3828. }
  3829. message = LdapFirstEntry( ld, searchResult);
  3830. if(message != NULL)
  3831. {
  3832. CLDAPGetAttributesWrapper atts(ld, searchResult);
  3833. attribute = atts.getFirst();
  3834. if(attribute != NULL)
  3835. {
  3836. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  3837. if (vals.hasValues())
  3838. userdn.append(vals.queryCharValue(0));
  3839. }
  3840. }
  3841. if(userdn.length() == 0)
  3842. throw MakeStringException(-1, "user %s can't be found", username);
  3843. }
  3844. else
  3845. {
  3846. if(stricmp(username, "anyone") == 0)
  3847. userdn.append(username);
  3848. else
  3849. userdn.append("uid=").append(username).append(",").append(m_ldapconfig->getUserBasedn());
  3850. }
  3851. }
  3852. virtual void getUidFromDN(const char* dn, StringBuffer& uid)
  3853. {
  3854. if(dn == NULL || *dn == '\0')
  3855. return;
  3856. if(m_ldapconfig->getServerType() != ACTIVE_DIRECTORY)
  3857. {
  3858. if (strncmp(dn,"uid=",4))//Fedora389 returns "cn=Directory Administrators"
  3859. return;
  3860. const char* comma = strchr(dn, ',');
  3861. // DN is in the format of "uid=uuu,ou=ooo,dc=dd"
  3862. uid.append(comma - dn - 4, dn + 4);
  3863. return;
  3864. }
  3865. StringBuffer filter;
  3866. filter.append("distinguishedName=").append(dn);
  3867. char *attribute;
  3868. LDAPMessage *message;
  3869. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  3870. char *uid_fieldname = "sAMAccountName";
  3871. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3872. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3873. char *attrs[] = {uid_fieldname, NULL};
  3874. CLDAPMessage searchResult;
  3875. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  3876. if ( rc != LDAP_SUCCESS )
  3877. {
  3878. throw MakeStringException(-1, "ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  3879. }
  3880. message = LdapFirstEntry( ld, searchResult);
  3881. if(message != NULL)
  3882. {
  3883. CLDAPGetAttributesWrapper atts(ld, searchResult);
  3884. attribute = atts.getFirst();
  3885. if(attribute != NULL)
  3886. {
  3887. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  3888. if (vals.hasValues())
  3889. uid.append(vals.queryCharValue(0));
  3890. }
  3891. }
  3892. }
  3893. virtual void getGroupDN(const char* groupname, StringBuffer& groupdn)
  3894. {
  3895. if(groupname == NULL)
  3896. return;
  3897. LdapServerType stype = m_ldapconfig->getServerType();
  3898. groupdn.append("cn=").append(groupname).append(",");
  3899. if(stype == ACTIVE_DIRECTORY && stricmp(groupname, "Administrators") == 0)
  3900. {
  3901. groupdn.append("cn=Builtin,").append(m_ldapconfig->getBasedn());
  3902. }
  3903. else if((stype == IPLANET || stype == OPEN_LDAP) && stricmp(groupname, "Directory Administrators") == 0)
  3904. {
  3905. groupdn.append(m_ldapconfig->getBasedn());
  3906. }
  3907. else
  3908. {
  3909. groupdn.append(m_ldapconfig->getGroupBasedn());
  3910. }
  3911. }
  3912. virtual void getGroupBaseDN(const char* groupname, StringBuffer& groupbasedn)
  3913. {
  3914. if(groupname == NULL)
  3915. return;
  3916. LdapServerType stype = m_ldapconfig->getServerType();
  3917. if(stype == ACTIVE_DIRECTORY && stricmp(groupname, "Administrators") == 0)
  3918. {
  3919. groupbasedn.append("cn=Builtin,").append(m_ldapconfig->getBasedn());
  3920. }
  3921. else if((stype == IPLANET || stype == OPEN_LDAP) && stricmp(groupname, "Directory Administrators") == 0)
  3922. {
  3923. groupbasedn.append(m_ldapconfig->getBasedn());
  3924. }
  3925. else
  3926. {
  3927. groupbasedn.append(m_ldapconfig->getGroupBasedn());
  3928. }
  3929. }
  3930. virtual void getAdminGroupDN(StringBuffer& groupdn)
  3931. {
  3932. LdapServerType stype = m_ldapconfig->getServerType();
  3933. if(stype == ACTIVE_DIRECTORY)
  3934. {
  3935. groupdn.append("cn=Administrators,cn=Builtin,").append(m_ldapconfig->getBasedn());
  3936. }
  3937. else if(stype == IPLANET)
  3938. {
  3939. groupdn.append("cn=Directory Administrators,").append(m_ldapconfig->getBasedn());
  3940. }
  3941. else if(stype == OPEN_LDAP)
  3942. {
  3943. groupdn.append("cn=Directory Administrators,").append(m_ldapconfig->getBasedn());
  3944. }
  3945. }
  3946. virtual void changeUserMemberOf(const char* action, const char* userdn, const char* groupdn)
  3947. {
  3948. char *grp_values[] = {(char*)groupdn, NULL};
  3949. LDAPMod grp_attr = {
  3950. (action != NULL && stricmp(action, "delete") == 0)?LDAP_MOD_DELETE:LDAP_MOD_ADD,
  3951. "memberOf",
  3952. grp_values
  3953. };
  3954. LDAPMod *grp_attrs[2];
  3955. grp_attrs[0] = &grp_attr;
  3956. grp_attrs[1] = NULL;
  3957. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3958. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3959. int rc = ldap_modify_ext_s(ld, (char*)userdn, grp_attrs, NULL, NULL);
  3960. if ( rc != LDAP_SUCCESS )
  3961. {
  3962. throw MakeStringException(-1, "error changing group for user %s, ldap_modify_ext_s error: %s", userdn, ldap_err2string( rc ));
  3963. }
  3964. }
  3965. virtual void changeGroupMember(const char* action, const char* groupdn, const char* userdn)
  3966. {
  3967. Owned<ILdapConnection> lconn = m_connections->getConnection();
  3968. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  3969. const char* memberfieldname;
  3970. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  3971. {
  3972. memberfieldname = "member";
  3973. }
  3974. else
  3975. {
  3976. memberfieldname = "uniquemember";
  3977. }
  3978. char *member_values[] = {(char*)userdn, NULL};
  3979. LDAPMod member_attr = {
  3980. (action != NULL && stricmp(action, "delete") == 0)?LDAP_MOD_DELETE:LDAP_MOD_ADD,
  3981. (char*)memberfieldname,
  3982. member_values
  3983. };
  3984. LDAPMod *member_attrs[2];
  3985. member_attrs[0] = &member_attr;
  3986. member_attrs[1] = NULL;
  3987. int rc = ldap_modify_ext_s(ld, (char*)groupdn, member_attrs, NULL, NULL);
  3988. if ( rc != LDAP_SUCCESS )
  3989. {
  3990. if (action != NULL && stricmp(action, "delete") == 0)
  3991. throw MakeStringException(-1, "Failed in deleting member from group: ldap_modify_ext_s error: %s; userdn: %s; groupdn: %s", ldap_err2string( rc ), userdn, groupdn);
  3992. else
  3993. throw MakeStringException(-1, "Failed in adding member to group, ldap_modify_ext_s error: %s; userdn: %s; groupdn: %s", ldap_err2string( rc ), userdn, groupdn);
  3994. }
  3995. }
  3996. void ConvertCToW(unsigned short* pszDest, const char * pszSrc)
  3997. {
  3998. unsigned i = 0;
  3999. for(i = 0; i < strlen(pszSrc); i++)
  4000. pszDest[i] = (unsigned short) pszSrc[i];
  4001. pszDest[i] = (unsigned short)'\0';
  4002. }
  4003. virtual bool authorizeScope(ISecUser& user, IArrayOf<ISecResource>& resources, const char* basedn)
  4004. {
  4005. IArrayOf<CSecurityDescriptor> sdlist;
  4006. std::set<const char*, ltstr> scopeset;
  4007. ForEachItemIn(x, resources)
  4008. {
  4009. ISecResource& res = resources.item(x);
  4010. const char* resourcename = res.getName();
  4011. if(resourcename == NULL || *resourcename == '\0')
  4012. continue;
  4013. // Add one extra Volume type SecurityDescriptor for each resource for ActiveDirectory.
  4014. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4015. {
  4016. CSecurityDescriptor* sd = new CSecurityDescriptor(resourcename);
  4017. sd->setObjectClass("Volume");
  4018. sdlist.append(*sd);
  4019. }
  4020. scopeset.insert(resourcename);
  4021. int len = strlen(resourcename);
  4022. const char* curptr = resourcename + len - 1;
  4023. while(curptr > resourcename)
  4024. {
  4025. while(curptr > resourcename && *curptr != ':')
  4026. curptr--;
  4027. bool foundcolon=false;
  4028. while(curptr >resourcename && *curptr == ':')
  4029. {
  4030. curptr--;
  4031. foundcolon = true;
  4032. }
  4033. if(curptr > resourcename || foundcolon)
  4034. {
  4035. int curlen = curptr - resourcename + 1;
  4036. char* curscope = (char*)alloca(curlen + 1);
  4037. strncpy(curscope, resourcename, curlen);
  4038. curscope[curlen] = 0;
  4039. scopeset.insert(curscope);
  4040. }
  4041. }
  4042. }
  4043. if(scopeset.size() == 0)
  4044. return true;
  4045. std::set<const char*, ltstr>::iterator iter;
  4046. for(iter = scopeset.begin(); iter != scopeset.end(); iter++)
  4047. {
  4048. const char* curscope = *iter;
  4049. CSecurityDescriptor* sd = new CSecurityDescriptor(*iter);
  4050. sd->setObjectClass("organizationalUnit");
  4051. sdlist.append(*sd);
  4052. }
  4053. getSecurityDescriptorsScope(sdlist, basedn);
  4054. IArrayOf<CSecurityDescriptor> matched_sdlist;
  4055. ForEachItemIn(y, resources)
  4056. {
  4057. ISecResource& res = resources.item(y);
  4058. const char* rname = res.getName();
  4059. if(rname == NULL || *rname == '\0')
  4060. throw MakeStringException(-1, "resource name can't be empty inside authorizeScope");
  4061. CSecurityDescriptor* matchedsd = NULL;
  4062. ForEachItemIn(z, sdlist)
  4063. {
  4064. CSecurityDescriptor& sd = sdlist.item(z);
  4065. const char* sdname = sd.getName();
  4066. if(sdname == NULL || *sdname == '\0')
  4067. continue;
  4068. if(strncmp(sdname, rname, strlen(sdname)) == 0
  4069. && (matchedsd == NULL
  4070. || ((matchedsd->getDescriptor().length() == 0 && sd.getDescriptor().length() > 0)
  4071. || (sd.getDescriptor().length() > 0 && strlen(sdname) > strlen(matchedsd->getName())))))
  4072. matchedsd = &sd;
  4073. }
  4074. if(matchedsd != NULL)
  4075. matched_sdlist.append(*LINK(matchedsd));
  4076. else
  4077. matched_sdlist.append(*(new CSecurityDescriptor(rname)));
  4078. }
  4079. bool ok = false;
  4080. if(m_pp != NULL)
  4081. ok = m_pp->getPermissions(user, matched_sdlist, resources);
  4082. return ok;
  4083. }
  4084. virtual void getSecurityDescriptors(SecResourceType rtype, IArrayOf<CSecurityDescriptor>& sdlist)
  4085. {
  4086. int len = sdlist.length();
  4087. if(len == 0)
  4088. return;
  4089. const char* rbasedn = m_ldapconfig->getResourceBasedn(rtype);
  4090. if(rbasedn == NULL || *rbasedn == '\0')
  4091. {
  4092. DBGLOG("corresponding resource basedn is not defined");
  4093. return;
  4094. }
  4095. std::map<std::string, IArrayOf<CSecurityDescriptor>*> sdmap;
  4096. for(int i = 0; i < len; i++)
  4097. {
  4098. CSecurityDescriptor& sd = sdlist.item(i);
  4099. const char* relativeBasedn = sd.getRelativeBasedn();
  4100. StringBuffer basedn;
  4101. if(relativeBasedn != NULL)
  4102. basedn.append(relativeBasedn).append(",");
  4103. basedn.append(rbasedn);
  4104. std::map<std::string, IArrayOf<CSecurityDescriptor>*>::iterator sdit = sdmap.find(basedn.str());
  4105. if(sdit == sdmap.end())
  4106. {
  4107. IArrayOf<CSecurityDescriptor>* newlist = new IArrayOf<CSecurityDescriptor>;
  4108. newlist->append(*LINK(&sd));
  4109. sdmap[basedn.str()] = newlist;
  4110. }
  4111. else
  4112. {
  4113. (*sdit).second->append(*LINK(&sd));
  4114. }
  4115. }
  4116. for(std::map<std::string, IArrayOf<CSecurityDescriptor>*>::iterator cur = sdmap.begin(); cur != sdmap.end(); cur++)
  4117. {
  4118. getSecurityDescriptors(*((*cur).second), (*cur).first.c_str());
  4119. delete (*cur).second;
  4120. }
  4121. }
  4122. virtual void getSecurityDescriptors(IArrayOf<CSecurityDescriptor>& sdlist, const char* basedn)
  4123. {
  4124. char *attribute;
  4125. CLDAPGetValuesLenWrapper valsLen;
  4126. LDAPMessage *message;
  4127. int i;
  4128. const char *id_fieldname;
  4129. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4130. {
  4131. id_fieldname = "name";
  4132. }
  4133. else
  4134. {
  4135. id_fieldname = "ou";
  4136. }
  4137. const char *des_fieldname = m_ldapconfig->getSdFieldName();
  4138. int len = sdlist.length();
  4139. if(len == 0)
  4140. return;
  4141. StringBuffer filter;
  4142. filter.append("(|");
  4143. for(i = 0; i < len; i++)
  4144. {
  4145. CSecurityDescriptor& sd = sdlist.item(i);
  4146. StringBuffer namebuf;
  4147. namebuf.append(sd.getName());
  4148. namebuf.trim();
  4149. if(namebuf.length() > 0)
  4150. {
  4151. filter.append("(").append(id_fieldname).append("=").append(namebuf.str()).append(")");;
  4152. }
  4153. }
  4154. filter.append(")");
  4155. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  4156. char* attrs[] = {(char*)id_fieldname, (char*)des_fieldname, NULL};
  4157. Owned<ILdapConnection> lconn = m_connections->getConnection();
  4158. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  4159. CLDAPMessage searchResult;
  4160. int rc = ldap_search_ext_s(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg ); /* returned results */
  4161. if ( rc != LDAP_SUCCESS )
  4162. {
  4163. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), basedn);
  4164. return;
  4165. }
  4166. // Go through the search results by checking message types
  4167. for(message = LdapFirstEntry(ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  4168. {
  4169. StringBuffer resourcename;
  4170. CLDAPGetAttributesWrapper atts(ld, searchResult);
  4171. for ( attribute = atts.getFirst();
  4172. attribute != NULL;
  4173. attribute = atts.getNext())
  4174. {
  4175. if(stricmp(attribute, id_fieldname) == 0)
  4176. {
  4177. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  4178. if (vals.hasValues())
  4179. resourcename.append(vals.queryCharValue(0));
  4180. }
  4181. else if(stricmp(attribute, des_fieldname) == 0)
  4182. {
  4183. valsLen.retrieveBValues(ld, message, attribute);
  4184. }
  4185. }
  4186. for(i = 0; i < len; i++)
  4187. {
  4188. CSecurityDescriptor& sd = sdlist.item(i);
  4189. if(resourcename.length() > 0 && stricmp(resourcename.str(), sd.getName()) == 0)
  4190. {
  4191. if (valsLen.hasValues())
  4192. {
  4193. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4194. {
  4195. struct berval* val = valsLen.queryBValues()[0];
  4196. if(val != NULL)
  4197. {
  4198. CSecurityDescriptor& sd = sdlist.item(i);
  4199. sd.setDescriptor(val->bv_len, val->bv_val);
  4200. }
  4201. }
  4202. else
  4203. {
  4204. MemoryBuffer allvals;
  4205. int valseq = 0;
  4206. struct berval* val = valsLen.queryBValues()[valseq++];
  4207. while(val != NULL)
  4208. {
  4209. if(val->bv_len > 0)
  4210. {
  4211. allvals.append(val->bv_len, val->bv_val);
  4212. allvals.append('\0'); // my separator between ACIs
  4213. }
  4214. val = valsLen.queryBValues()[valseq++];
  4215. }
  4216. if(allvals.length() > 0)
  4217. {
  4218. CSecurityDescriptor& sd = sdlist.item(i);
  4219. sd.setDescriptor(allvals.length(), (void*)allvals.toByteArray());
  4220. }
  4221. }
  4222. }
  4223. break;
  4224. }
  4225. }
  4226. }
  4227. }
  4228. virtual void getSecurityDescriptorsScope(IArrayOf<CSecurityDescriptor>& sdlist, const char* basedn)
  4229. {
  4230. char *attribute;
  4231. CLDAPGetValuesLenWrapper valsLen;
  4232. LDAPMessage *message;
  4233. int i;
  4234. int len = sdlist.length();
  4235. if(len == 0)
  4236. return;
  4237. LdapServerType servertype = m_ldapconfig->getServerType();
  4238. char *sd_fieldname = (char*)m_ldapconfig->getSdFieldName();
  4239. StringBuffer filter;
  4240. filter.append("(|");
  4241. for(i = 0; i < len; i++)
  4242. {
  4243. CSecurityDescriptor& sd = sdlist.item(i);
  4244. StringBuffer namebuf;
  4245. namebuf.append(sd.getName());
  4246. namebuf.trim();
  4247. if(namebuf.length() > 0)
  4248. {
  4249. const char* resourcename = namebuf.str();
  4250. int len = namebuf.length();
  4251. const char* curptr = resourcename + len - 1;
  4252. StringBuffer dn, cn;
  4253. bool isleaf = true;
  4254. while(curptr > resourcename)
  4255. {
  4256. const char* lastptr = curptr;
  4257. while(curptr > resourcename && *curptr != ':')
  4258. curptr--;
  4259. int curlen;
  4260. const char* curscope;
  4261. if(*curptr == ':')
  4262. {
  4263. curlen = lastptr - curptr;
  4264. curscope = curptr + 1;
  4265. }
  4266. else
  4267. {
  4268. curlen = lastptr - curptr + 1;
  4269. curscope = curptr;
  4270. }
  4271. if(isleaf && (sd.getObjectClass() != NULL) && (stricmp(sd.getObjectClass(), "Volume") == 0))
  4272. {
  4273. cn.append(curlen, curscope);
  4274. dn.append("cn=").append(curlen, curscope).append(",");
  4275. }
  4276. else
  4277. {
  4278. cn.append(curlen, curscope);
  4279. dn.append("ou=").append(curlen, curscope).append(",");
  4280. }
  4281. isleaf = false;
  4282. if (curptr == resourcename) //handle a single char as the top scope, such as x::abc
  4283. break;
  4284. while(curptr >resourcename && *curptr == ':')
  4285. curptr--;
  4286. if (curptr == resourcename && *curptr != ':') //handle a single char as the top scope, such as x::abc
  4287. {
  4288. dn.append("ou=").append(1, curptr).append(",");
  4289. }
  4290. }
  4291. dn.append(basedn);
  4292. if(servertype == ACTIVE_DIRECTORY)
  4293. {
  4294. filter.append("(distinguishedName=").append(dn.str()).append(")");
  4295. }
  4296. else if(servertype == IPLANET)
  4297. {
  4298. filter.append("(entrydn=").append(dn.str()).append(")");
  4299. }
  4300. else if(servertype == OPEN_LDAP)
  4301. {
  4302. filter.append("(ou=").append(cn.str()).append(")");
  4303. }
  4304. sd.setDn(dn.str());
  4305. }
  4306. }
  4307. filter.append(")");
  4308. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  4309. char* attrs[] = {sd_fieldname, NULL};
  4310. Owned<ILdapConnection> lconn = m_connections->getConnection();
  4311. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  4312. CLDAPMessage searchResult;
  4313. int rc = ldap_search_ext_s(ld, (char*)basedn, LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg ); /* returned results */
  4314. if ( rc != LDAP_SUCCESS )
  4315. {
  4316. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), basedn);
  4317. return;
  4318. }
  4319. // Go through the search results by checking message types
  4320. for(message = LdapFirstEntry(ld, searchResult); message != NULL; message = ldap_next_entry(ld, message))
  4321. {
  4322. StringBuffer dn;
  4323. char *p = ldap_get_dn(ld, message);
  4324. dn.append(p);
  4325. ldap_memfree(p);
  4326. CLDAPGetAttributesWrapper atts(ld, searchResult);
  4327. for ( attribute = atts.getFirst();
  4328. attribute != NULL;
  4329. attribute = atts.getNext())
  4330. {
  4331. if(stricmp(attribute, sd_fieldname) == 0)
  4332. {
  4333. valsLen.retrieveBValues(ld, message, attribute);
  4334. }
  4335. }
  4336. for(i = 0; i < len; i++)
  4337. {
  4338. CSecurityDescriptor& sd = sdlist.item(i);
  4339. if(dn.length() > 0 && stricmp(dn.str(), sd.getDn()) == 0)
  4340. {
  4341. if (valsLen.hasValues())
  4342. {
  4343. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4344. {
  4345. struct berval* val = valsLen.queryBValues()[0];
  4346. if(val != NULL)
  4347. {
  4348. CSecurityDescriptor& sd = sdlist.item(i);
  4349. sd.setDescriptor(val->bv_len, val->bv_val);
  4350. }
  4351. }
  4352. else
  4353. {
  4354. MemoryBuffer allvals;
  4355. int valseq = 0;
  4356. struct berval* val = valsLen.queryBValues()[valseq++];
  4357. while(val != NULL)
  4358. {
  4359. if(val->bv_len > 0)
  4360. {
  4361. allvals.append(val->bv_len, val->bv_val);
  4362. allvals.append('\0'); // my separator between ACIs
  4363. }
  4364. val = valsLen.queryBValues()[valseq++];
  4365. }
  4366. if(allvals.length() > 0)
  4367. {
  4368. CSecurityDescriptor& sd = sdlist.item(i);
  4369. sd.setDescriptor(allvals.length(), (void*)allvals.toByteArray());
  4370. }
  4371. }
  4372. }
  4373. break;
  4374. }
  4375. }
  4376. }
  4377. }
  4378. virtual void createLdapBasedn(ISecUser* user, const char* basedn, SecPermissionType ptype)
  4379. {
  4380. if(basedn == NULL || basedn[0] == '\0')
  4381. return;
  4382. const char* ptr = strstr(basedn, "ou=");
  4383. if(ptr == NULL)
  4384. return;
  4385. ptr += 3;
  4386. StringBuffer oubuf;
  4387. const char* comma = strchr(ptr, ',');
  4388. if(comma == NULL)
  4389. {
  4390. oubuf.append(ptr);
  4391. ptr = NULL;
  4392. }
  4393. else
  4394. {
  4395. oubuf.append(comma - ptr, ptr);
  4396. ptr = comma + 1;
  4397. }
  4398. if(ptr != NULL)
  4399. createLdapBasedn(user, ptr, ptype);
  4400. addOrganizationalUnit(user, oubuf.str(), ptr, ptype);
  4401. }
  4402. virtual bool addOrganizationalUnit(ISecUser* user, const char* name, const char* basedn, SecPermissionType ptype)
  4403. {
  4404. if(name == NULL || basedn == NULL)
  4405. return false;
  4406. if(strchr(name, '/') != NULL || strchr(name, '=') != NULL)
  4407. return false;
  4408. StringBuffer dn;
  4409. dn.append("ou=").append(name).append(",").append(basedn);
  4410. char *ou_values[] = {(char*)name, NULL };
  4411. LDAPMod ou_attr =
  4412. {
  4413. LDAP_MOD_ADD,
  4414. "ou",
  4415. ou_values
  4416. };
  4417. char *name_values[] = {(char*)name, NULL };
  4418. LDAPMod name_attr =
  4419. {
  4420. LDAP_MOD_ADD,
  4421. "name",
  4422. name_values
  4423. };
  4424. char *oc_values[] = {"OrganizationalUnit", NULL };
  4425. LDAPMod oc_attr =
  4426. {
  4427. LDAP_MOD_ADD,
  4428. "objectClass",
  4429. oc_values
  4430. };
  4431. MemoryBuffer sdbuf;
  4432. Owned<CSecurityDescriptor> default_sd = NULL;
  4433. if(m_pp != NULL)
  4434. default_sd.setown(m_pp->createDefaultSD(user, name, ptype));
  4435. if(default_sd != NULL)
  4436. sdbuf.append(default_sd->getDescriptor());
  4437. LDAPMod *attrs[6];
  4438. int ind = 0;
  4439. attrs[ind++] = &ou_attr;
  4440. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4441. {
  4442. attrs[ind++] = &name_attr;
  4443. }
  4444. attrs[ind++] = &oc_attr;
  4445. LDAPMod sd_attr;
  4446. struct berval sd_val;
  4447. sd_val.bv_len = sdbuf.length();
  4448. sd_val.bv_val = (char*)sdbuf.toByteArray();
  4449. struct berval* sd_values[] = {&sd_val, NULL};
  4450. sd_attr.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  4451. sd_attr.mod_type = (char*)m_ldapconfig->getSdFieldName();
  4452. sd_attr.mod_vals.modv_bvals = sd_values;
  4453. if(sdbuf.length() > 0)
  4454. attrs[ind++] = &sd_attr;
  4455. attrs[ind] = NULL;
  4456. Owned<ILdapConnection> lconn = m_connections->getConnection();
  4457. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  4458. int rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  4459. if ( rc != LDAP_SUCCESS )
  4460. {
  4461. if(rc == LDAP_ALREADY_EXISTS)
  4462. {
  4463. //WARNLOG("Can't insert ou=%s,%s to Ldap Server, an LDAP object with this name already exists", name, basedn);
  4464. return false;
  4465. }
  4466. else
  4467. {
  4468. throw MakeStringException(-1, "ldap_add_ext_s error for ou=%s,%s: %d %s", name, basedn, rc, ldap_err2string( rc ));
  4469. }
  4470. }
  4471. return true;
  4472. }
  4473. virtual void name2dn(SecResourceType rtype, const char* resourcename, const char* basedn, StringBuffer& ldapname)
  4474. {
  4475. StringBuffer namebuf;
  4476. const char* bptr = resourcename;
  4477. const char* sep = strstr(resourcename, "::");
  4478. while(sep != NULL)
  4479. {
  4480. if(sep > bptr)
  4481. {
  4482. StringBuffer onebuf;
  4483. onebuf.append("ou=").append(sep-bptr, bptr).append(",");
  4484. namebuf.insert(0, onebuf.str());
  4485. }
  4486. bptr = sep + 2;
  4487. sep = strstr(bptr, "::");
  4488. }
  4489. if(*bptr != '\0')
  4490. {
  4491. StringBuffer onebuf;
  4492. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY && (rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE))
  4493. onebuf.append("cn");
  4494. else
  4495. onebuf.append("ou");
  4496. onebuf.append("=").append(bptr).append(",");
  4497. namebuf.insert(0, onebuf.str());
  4498. }
  4499. namebuf.append(basedn);
  4500. LdapUtils::normalizeDn(namebuf.str(), m_ldapconfig->getBasedn(), ldapname);
  4501. }
  4502. virtual void name2rdn(SecResourceType rtype, const char* resourcename, StringBuffer& ldapname)
  4503. {
  4504. if(resourcename == NULL || *resourcename == '\0')
  4505. return;
  4506. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY && (rtype == RT_DEFAULT || rtype == RT_MODULE || rtype == RT_SERVICE))
  4507. ldapname.append("cn=");
  4508. else
  4509. ldapname.append("ou=");
  4510. const char* prevptr = resourcename;
  4511. const char* nextptr = strstr(resourcename, "::");
  4512. while(nextptr != NULL)
  4513. {
  4514. prevptr = nextptr + 2;
  4515. nextptr = strstr(prevptr, "::");
  4516. }
  4517. if(prevptr != NULL && *prevptr != '\0')
  4518. ldapname.append(prevptr);
  4519. }
  4520. virtual bool addResource(SecResourceType rtype, ISecUser& user, ISecResource* resource, SecPermissionType ptype, const char* basedn)
  4521. {
  4522. Owned<CSecurityDescriptor> template_sd = NULL;
  4523. const char* templatename = m_ldapconfig->getTemplateName();
  4524. if(templatename != NULL && *templatename != '\0')
  4525. {
  4526. IArrayOf<CSecurityDescriptor> sdlist;
  4527. template_sd.setown(new CSecurityDescriptor(templatename));
  4528. sdlist.append(*LINK(template_sd));
  4529. if(basedn && *basedn)
  4530. getSecurityDescriptors(sdlist, basedn);
  4531. else
  4532. getSecurityDescriptors(rtype, sdlist);
  4533. }
  4534. Owned<CSecurityDescriptor> default_sd = NULL;
  4535. if(template_sd != NULL && template_sd->getDescriptor().length() > 0)
  4536. {
  4537. MemoryBuffer template_sd_buf;
  4538. template_sd_buf.append(template_sd->getDescriptor());
  4539. if(m_pp != NULL)
  4540. default_sd.setown(m_pp->createDefaultSD(&user, resource, template_sd_buf));
  4541. }
  4542. else
  4543. {
  4544. if(m_pp != NULL)
  4545. default_sd.setown(m_pp->createDefaultSD(&user, resource, ptype));
  4546. }
  4547. return addResource(rtype, user, resource, ptype, basedn, default_sd.get());
  4548. }
  4549. virtual bool addResource(SecResourceType rtype, ISecUser& user, ISecResource* resource, SecPermissionType ptype, const char* basedn, CSecurityDescriptor* default_sd, bool lessException=true)
  4550. {
  4551. if(resource == NULL)
  4552. return true;
  4553. char* resourcename = (char*)resource->getName();
  4554. if(resourcename == NULL)
  4555. {
  4556. DBGLOG("can't add resource, empty resource name");
  4557. return false;
  4558. }
  4559. const char* rbasedn;
  4560. StringBuffer rbasednbuf;
  4561. if(basedn == NULL)
  4562. rbasedn = m_ldapconfig->getResourceBasedn(rtype);
  4563. else
  4564. {
  4565. LdapUtils::normalizeDn(basedn, m_ldapconfig->getBasedn(), rbasednbuf);
  4566. rbasedn = rbasednbuf.str();
  4567. }
  4568. if(rbasedn == NULL || *rbasedn == '\0')
  4569. {
  4570. DBGLOG("Can't add resource, corresponding resource basedn is not defined");
  4571. return false;
  4572. }
  4573. if(strchr(resourcename, '/') != NULL || strchr(resourcename, '=') != NULL)
  4574. return false;
  4575. if(rtype == RT_FILE_SCOPE || rtype == RT_WORKUNIT_SCOPE)
  4576. {
  4577. StringBuffer extbuf;
  4578. name2dn(rtype, resourcename, rbasedn, extbuf);
  4579. createLdapBasedn(&user, extbuf.str(), ptype);
  4580. return true;
  4581. }
  4582. LdapServerType servertype = m_ldapconfig->getServerType();
  4583. char* description = (char*)((CLdapSecResource*)resource)->getDescription();
  4584. StringBuffer dn;
  4585. char *fieldname, *oc_name;
  4586. if(servertype == ACTIVE_DIRECTORY)
  4587. {
  4588. fieldname = "cn";
  4589. oc_name = "Volume";
  4590. }
  4591. else
  4592. {
  4593. fieldname = "ou";
  4594. oc_name = "OrganizationalUnit";
  4595. }
  4596. dn.append(fieldname).append("=").append(resourcename).append(",");
  4597. dn.append(rbasedn);
  4598. char *cn_values[] = {resourcename, NULL };
  4599. LDAPMod cn_attr =
  4600. {
  4601. LDAP_MOD_ADD,
  4602. fieldname,
  4603. cn_values
  4604. };
  4605. char *oc_values[] = {oc_name, NULL };
  4606. LDAPMod oc_attr =
  4607. {
  4608. LDAP_MOD_ADD,
  4609. "objectClass",
  4610. oc_values
  4611. };
  4612. char* uncname_values[] = {resourcename, NULL};
  4613. LDAPMod uncname_attr =
  4614. {
  4615. LDAP_MOD_ADD,
  4616. "uNCName",
  4617. uncname_values
  4618. };
  4619. StringBuffer descriptionbuf;
  4620. if(description && *description)
  4621. descriptionbuf.append(description);
  4622. else
  4623. descriptionbuf.appendf("Access to %s", resourcename);
  4624. char* description_values[] = {(char*)descriptionbuf.str(), NULL};
  4625. LDAPMod description_attr =
  4626. {
  4627. LDAP_MOD_ADD,
  4628. "description",
  4629. description_values
  4630. };
  4631. Owned<CSecurityDescriptor> template_sd = NULL;
  4632. const char* templatename = m_ldapconfig->getTemplateName();
  4633. if(templatename != NULL && *templatename != '\0')
  4634. {
  4635. IArrayOf<CSecurityDescriptor> sdlist;
  4636. template_sd.setown(new CSecurityDescriptor(templatename));
  4637. sdlist.append(*LINK(template_sd));
  4638. getSecurityDescriptors(rtype, sdlist);
  4639. }
  4640. int numberOfSegs = 0;
  4641. if(default_sd != NULL)
  4642. {
  4643. numberOfSegs = m_pp->sdSegments(default_sd);
  4644. }
  4645. LDAPMod **attrs = (LDAPMod**)(alloca((5+numberOfSegs)*sizeof(LDAPMod*)));
  4646. int ind = 0;
  4647. attrs[ind++] = &cn_attr;
  4648. attrs[ind++] = &oc_attr;
  4649. attrs[ind++] = &description_attr;
  4650. if(servertype == ACTIVE_DIRECTORY)
  4651. {
  4652. attrs[ind++] = &uncname_attr;
  4653. }
  4654. LDAPMod sd_attr;
  4655. if(default_sd != NULL)
  4656. {
  4657. struct berval** sd_values = (struct berval**)alloca(sizeof(struct berval*)*(numberOfSegs+1));
  4658. MemoryBuffer& sdbuf = default_sd->getDescriptor();
  4659. // Active Directory acutally has only one segment.
  4660. if(servertype == ACTIVE_DIRECTORY)
  4661. {
  4662. struct berval* sd_val = (struct berval*)alloca(sizeof(struct berval));
  4663. sd_val->bv_len = sdbuf.length();
  4664. sd_val->bv_val = (char*)sdbuf.toByteArray();
  4665. sd_values[0] = sd_val;
  4666. sd_values[1] = NULL;
  4667. sd_attr.mod_type = "ntSecurityDescriptor";
  4668. }
  4669. else
  4670. {
  4671. const char* bbptr = sdbuf.toByteArray();
  4672. const char* bptr = sdbuf.toByteArray();
  4673. int sdbuflen = sdbuf.length();
  4674. int segind;
  4675. for(segind = 0; segind < numberOfSegs; segind++)
  4676. {
  4677. if(bptr - bbptr >= sdbuflen)
  4678. break;
  4679. while(*bptr == '\0' && (bptr - bbptr) < sdbuflen)
  4680. bptr++;
  4681. const char* eptr = bptr;
  4682. while(*eptr != '\0' && (eptr - bbptr) < sdbuflen)
  4683. eptr++;
  4684. struct berval* sd_val = (struct berval*)alloca(sizeof(struct berval));
  4685. sd_val->bv_len = eptr - bptr;
  4686. sd_val->bv_val = (char*)bptr;
  4687. sd_values[segind] = sd_val;
  4688. bptr = eptr + 1;
  4689. }
  4690. sd_values[segind] = NULL;
  4691. sd_attr.mod_type = (char*)m_ldapconfig->getSdFieldName();
  4692. }
  4693. sd_attr.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  4694. sd_attr.mod_vals.modv_bvals = sd_values;
  4695. attrs[ind++] = &sd_attr;
  4696. }
  4697. attrs[ind] = NULL;
  4698. Owned<ILdapConnection> lconn = m_connections->getConnection();
  4699. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  4700. int rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  4701. if ( rc != LDAP_SUCCESS )
  4702. {
  4703. if(rc == LDAP_ALREADY_EXISTS)
  4704. {
  4705. //WARNLOG("Can't insert %s to Ldap Server, an LDAP object with this name already exists", resourcename);
  4706. if(lessException)
  4707. return false;
  4708. else
  4709. throw MakeStringException(-1, "Can't insert %s, an LDAP object with this name already exists", resourcename);
  4710. }
  4711. else
  4712. {
  4713. throw MakeStringException(-1, "ldap_add_ext_s error for %s: %d %s", resourcename, rc, ldap_err2string( rc ));
  4714. }
  4715. }
  4716. return true;
  4717. }
  4718. virtual void enableUser(ISecUser* user, const char* dn, LDAP* ld)
  4719. {
  4720. const char* username = user->getName();
  4721. StringBuffer filter;
  4722. filter.append("sAMAccountName=").append(username);
  4723. char *attribute;
  4724. LDAPMessage *message;
  4725. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  4726. char *attrs[] = {"userAccountControl", NULL};
  4727. CLDAPMessage searchResult;
  4728. int rc = ldap_search_ext_s(ld, (char*)m_ldapconfig->getUserBasedn(), LDAP_SCOPE_SUBTREE, (char*)filter.str(), attrs, 0, NULL, NULL, &timeOut, LDAP_NO_LIMIT, &searchResult.msg );
  4729. if ( rc != LDAP_SUCCESS )
  4730. {
  4731. DBGLOG("ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  4732. throw MakeStringException(-1, "ldap_search_ext_s error: %s, when searching %s under %s", ldap_err2string( rc ), filter.str(), m_ldapconfig->getUserBasedn());
  4733. }
  4734. StringBuffer act_ctrl;
  4735. message = LdapFirstEntry( ld, searchResult);
  4736. if(message != NULL)
  4737. {
  4738. CLDAPGetAttributesWrapper atts(ld, searchResult);
  4739. for ( attribute = atts.getFirst();
  4740. attribute != NULL;
  4741. attribute = atts.getNext())
  4742. {
  4743. if(0 == stricmp(attribute, "userAccountControl"))
  4744. {
  4745. CLDAPGetValuesLenWrapper vals(ld, message, attribute);
  4746. if (vals.hasValues())
  4747. {
  4748. act_ctrl.append(vals.queryCharValue(0));
  4749. break;
  4750. }
  4751. }
  4752. }
  4753. }
  4754. if(act_ctrl.length() == 0)
  4755. {
  4756. DBGLOG("enableUser: userAccountControl doesn't exist for user %s",username);
  4757. throw MakeStringException(-1, "enableUser: userAccountControl doesn't exist for user %s",username);
  4758. }
  4759. unsigned act_ctrl_val = atoi(act_ctrl.str());
  4760. // UF_ACCOUNTDISABLE 0x0002
  4761. act_ctrl_val &= 0xFFFFFFFD;
  4762. #ifdef _DONT_EXPIRE_PASSWORD
  4763. // UF_DONT_EXPIRE_PASSWD 0x10000
  4764. if (m_domainPwdsNeverExpire)
  4765. act_ctrl_val |= 0x10000;
  4766. #endif
  4767. StringBuffer new_act_ctrl;
  4768. new_act_ctrl.append(act_ctrl_val);
  4769. char *ctrl_values[] = {(char*)new_act_ctrl.str(), NULL};
  4770. LDAPMod ctrl_attr = {
  4771. LDAP_MOD_REPLACE,
  4772. "userAccountControl",
  4773. ctrl_values
  4774. };
  4775. LDAPMod *cattrs[2];
  4776. cattrs[0] = &ctrl_attr;
  4777. cattrs[1] = NULL;
  4778. rc = ldap_modify_ext_s(ld, (char*)dn, cattrs, NULL, NULL);
  4779. if ( rc != LDAP_SUCCESS )
  4780. {
  4781. throw MakeStringException(-1, "error enableUser %s, ldap_modify_ext_s error: %s", username, ldap_err2string( rc ));
  4782. }
  4783. // set the password.
  4784. Owned<ISecUser> tmpuser = new CLdapSecUser(user->getName(), "");
  4785. const char* passwd = user->credentials().getPassword();
  4786. if(passwd == NULL || *passwd == '\0')
  4787. passwd = "password";
  4788. if (!updateUserPassword(*tmpuser, passwd, NULL))
  4789. {
  4790. DBGLOG("Error updating password for %s",username);
  4791. throw MakeStringException(-1, "Error updating password for %s",username);
  4792. }
  4793. }
  4794. virtual bool addUser(ISecUser& user)
  4795. {
  4796. const char* username = user.getName();
  4797. if(username == NULL || *username == '\0')
  4798. {
  4799. DBGLOG("Can't add user, username not set");
  4800. throw MakeStringException(-1, "Can't add user, username not set");
  4801. }
  4802. const char* fname = user.getFirstName();
  4803. const char* lname = user.getLastName();
  4804. if((lname == NULL || *lname == '\0') && (fname == NULL || *fname == '\0' || m_ldapconfig->getServerType() == IPLANET))
  4805. lname = username;
  4806. const char* fullname = user.getFullName();
  4807. StringBuffer fullname_buf;
  4808. if(fullname == NULL || *fullname == '\0')
  4809. {
  4810. if(fname != NULL && *fname != '\0')
  4811. {
  4812. fullname_buf.append(fname);
  4813. if(lname != NULL && *lname != '\0')
  4814. fullname_buf.append(" ");
  4815. }
  4816. if(lname != NULL && *lname != '\0')
  4817. fullname_buf.append(lname);
  4818. if(fullname_buf.length() == 0)
  4819. {
  4820. fullname_buf.append(username);
  4821. }
  4822. fullname = fullname_buf.str();
  4823. }
  4824. StringBuffer dn;
  4825. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4826. {
  4827. dn.append("cn=").append(fullname).append(",");
  4828. }
  4829. else
  4830. {
  4831. dn.append("uid=").append(user.getName()).append(",");
  4832. }
  4833. dn.append(m_ldapconfig->getUserBasedn());
  4834. char* oc_name;
  4835. char* act_fieldname;
  4836. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4837. {
  4838. oc_name = "User";
  4839. act_fieldname = "sAMAccountName";
  4840. }
  4841. else
  4842. {
  4843. oc_name = "inetorgperson";
  4844. act_fieldname = "uid";
  4845. }
  4846. char *cn_values[] = {(char*)fullname, NULL };
  4847. LDAPMod cn_attr =
  4848. {
  4849. LDAP_MOD_ADD,
  4850. "cn",
  4851. cn_values
  4852. };
  4853. char *oc_values[] = {oc_name, NULL};
  4854. LDAPMod oc_attr =
  4855. {
  4856. LDAP_MOD_ADD,
  4857. "objectClass",
  4858. oc_values
  4859. };
  4860. char *gn_values[] = { (char*)fname, NULL };
  4861. LDAPMod gn_attr = {
  4862. LDAP_MOD_ADD,
  4863. "givenName",
  4864. gn_values
  4865. };
  4866. char *sn_values[] = { (char*)lname, NULL };
  4867. LDAPMod sn_attr = {
  4868. LDAP_MOD_ADD,
  4869. "sn",
  4870. sn_values
  4871. };
  4872. char* actname_values[] = {(char*)username, NULL};
  4873. LDAPMod actname_attr =
  4874. {
  4875. LDAP_MOD_ADD,
  4876. act_fieldname,
  4877. actname_values
  4878. };
  4879. const char* passwd = user.credentials().getPassword();
  4880. if(passwd == NULL || *passwd == '\0')
  4881. passwd = "password";
  4882. char* passwd_values[] = {(char*)passwd, NULL};
  4883. LDAPMod passwd_attr =
  4884. {
  4885. LDAP_MOD_ADD,
  4886. "userpassword",
  4887. passwd_values
  4888. };
  4889. char *dispname_values[] = {(char*)fullname, NULL };
  4890. LDAPMod dispname_attr =
  4891. {
  4892. LDAP_MOD_ADD,
  4893. "displayName",
  4894. dispname_values
  4895. };
  4896. char* username_values[] = {(char*)username, NULL};
  4897. LDAPMod username_attr =
  4898. {
  4899. LDAP_MOD_ADD,
  4900. "userPrincipalName",
  4901. username_values
  4902. };
  4903. LDAPMod *attrs[8];
  4904. int ind = 0;
  4905. attrs[ind++] = &cn_attr;
  4906. attrs[ind++] = &oc_attr;
  4907. if(fname != NULL && *fname != '\0')
  4908. attrs[ind++] = &gn_attr;
  4909. if(lname != NULL && *lname != '\0')
  4910. attrs[ind++] = &sn_attr;
  4911. attrs[ind++] = &actname_attr;
  4912. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4913. {
  4914. attrs[ind++] = &username_attr;
  4915. attrs[ind++] = &dispname_attr;
  4916. }
  4917. else
  4918. {
  4919. attrs[ind++] = &passwd_attr;
  4920. }
  4921. attrs[ind] = NULL;
  4922. Owned<ILdapConnection> lconn = m_connections->getConnection();
  4923. LDAP* ld = ((CLdapConnection*)lconn.get())->getLd();
  4924. int rc = ldap_add_ext_s(ld, (char*)dn.str(), attrs, NULL, NULL);
  4925. if ( rc != LDAP_SUCCESS )
  4926. {
  4927. if(rc == LDAP_ALREADY_EXISTS)
  4928. {
  4929. DBGLOG("Can't add user %s, an LDAP object with this name already exists", username);
  4930. throw MakeStringException(-1, "Can't add user %s, an LDAP object with this name already exists", username);
  4931. }
  4932. else
  4933. {
  4934. DBGLOG("Error addUser %s, ldap_add_ext_s error: %s", username, ldap_err2string( rc ));
  4935. throw MakeStringException(-1, "Error addUser %s, ldap_add_ext_s error: %s", username, ldap_err2string( rc ));
  4936. }
  4937. }
  4938. if(m_ldapconfig->getServerType() == ACTIVE_DIRECTORY)
  4939. {
  4940. try
  4941. {
  4942. enableUser(&user, dn.str(), ld);
  4943. }
  4944. catch(...)
  4945. {
  4946. deleteUser(&user);
  4947. throw;
  4948. }
  4949. }
  4950. //Add tempfile scope for this user (spill, paused and checkpoint
  4951. //will be created under this user specific scope)
  4952. StringBuffer resName(queryDfsXmlBranchName(DXB_Internal));
  4953. resName.append("::").append(username);
  4954. Owned<ISecResource> resource = new CLdapSecResource(resName.str());
  4955. if (!addResource(RT_FILE_SCOPE, user, resource, PT_ADMINISTRATORS_AND_USER, m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE)))
  4956. {
  4957. throw MakeStringException(-1, "Error adding temp file scope %s",resName.str());
  4958. }
  4959. return true;
  4960. }
  4961. bool createUserScope(ISecUser& user)
  4962. {
  4963. //Add tempfile scope for given user (spill, paused and checkpoint
  4964. //files will be created under this user specific scope)
  4965. StringBuffer resName(queryDfsXmlBranchName(DXB_Internal));
  4966. resName.append("::").append(user.getName());
  4967. Owned<ISecResource> resource = new CLdapSecResource(resName.str());
  4968. return addResource(RT_FILE_SCOPE, user, resource, PT_ADMINISTRATORS_AND_USER, m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE));
  4969. }
  4970. virtual aindex_t getManagedFileScopes(IArrayOf<ISecResource>& scopes)
  4971. {
  4972. getResourcesEx(RT_FILE_SCOPE, m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE), NULL, NULL, scopes);
  4973. return scopes.length();
  4974. }
  4975. virtual int queryDefaultPermission(ISecUser& user)
  4976. {
  4977. const char* basedn = m_ldapconfig->getResourceBasedn(RT_FILE_SCOPE);
  4978. if(basedn == NULL || *basedn == '\0')
  4979. {
  4980. DBGLOG("corresponding basedn is not defined");
  4981. return -2;
  4982. }
  4983. const char* basebasedn = strchr(basedn, ',') + 1;
  4984. StringBuffer baseresource;
  4985. baseresource.append(basebasedn-basedn-4, basedn+3);
  4986. IArrayOf<ISecResource> base_resources;
  4987. base_resources.append(*new CLdapSecResource(baseresource.str()));
  4988. bool baseok = authorizeScope(user, base_resources, basebasedn);
  4989. if(baseok)
  4990. return base_resources.item(0).getAccessFlags();
  4991. else
  4992. return -2;
  4993. }
  4994. };
  4995. #ifdef _WIN32
  4996. bool verifyServerCert(LDAP* ld, PCCERT_CONTEXT pServerCert)
  4997. {
  4998. return true;
  4999. }
  5000. #endif
  5001. ILdapClient* createLdapClient(IPropertyTree* cfg)
  5002. {
  5003. return new CLdapClient(cfg);
  5004. }