ldapconnection.cpp 236 KB

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