acllas.c 120 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include <ipfstruct.h>
  42. #include "acl.h"
  43. /*
  44. A word on this file:
  45. The various routines here implement each component of the subject of an aci
  46. eg. "groupdn", "userdn","roledn", "userattr" etc.
  47. They are responsible for evaluating each individual keyword not for doing
  48. the boolean combination of these keywords, nor for combining multiple
  49. allow()/deny() statements--that's libaccess's job.
  50. For example, for "groupdn", DS_LASGroupDnEval might have to evaluate
  51. something like this:
  52. "groupdn = "ldap:///cn=G1,o=sun.com || ldap:///cn=G2,o=sun.com"
  53. The "=" here may be "!=" as well and these routines take care of the
  54. comparator.
  55. These rotuines get called via acl__TestRights(), which calls
  56. ACL_EvalTestRights() a libaccess routine (the immediately calling routine is
  57. ACLEvalAce() in oneeval.cpp).
  58. They should return LAS_EVAL_TRUE, if that keyword component evaluates to
  59. TRUE, LAS_EVAL_FALSE if it evaluates to FALSE and LAS_EVAL_FAIL if an
  60. error occurrs during evaluation. Note that once any component of a subject
  61. returns LAS_EVAL_FAIL, the evaluation in libaccess stops and the whole
  62. subject does not match and that aci is not applied.
  63. */
  64. /*
  65. A word on three-valued logic:
  66. In general when you do boolean combination of terms some of which
  67. may evaluate to UNDEFINED then you need to define what the combination
  68. means.
  69. So, for example libaccess implements a scheme which once UNDEFINED
  70. is returned for a term, it bales out of the
  71. evaluation and the whole expression evaluates to UNDEFINED.
  72. In this case the aci will not apply.
  73. On the other hand LDAP filters (cf. rfc2251 4.5.1) say that for OR,
  74. an expression will
  75. evaluate to TRUE if any term is TRUE, even if some terms are UNDEFINED.
  76. Other off the cuff options might be to redefine UNDEFINED to be FALSE,
  77. or TRUE.
  78. Which is best ?
  79. Well it probably depends on exactly what is to decided based on the
  80. evaluation of the logical expression. However, the final suggestion is
  81. almost certainly
  82. bad--you are unlikely to want to take an action based on an undefined
  83. result and
  84. defining UNDEFINED to be either TRUE or FALSE may result in the overall
  85. expression
  86. returning TRUE--a security hole. The only case this might work is if you
  87. are dealing with restricted
  88. expressions eg. terms may only be AND'ed togther--in this case defining
  89. UNDEFINED to be FALSE would guarantee a result of FALSE.
  90. The libaccess approach of returning UNDEFINED once an UNDEFINED is
  91. encountered during
  92. evaluation is not too bad--at least it guarantees that no aci will apply
  93. based on an
  94. undefined value. However, with an aci like this "...allow(all) A or B"
  95. where A returned UNDEFINED, you might be disappointed not to receive the
  96. rights if it was B that
  97. was granting you the rights and evaluation of A, which has nothing to do
  98. with you, returns UNDEFINED. In the case of an aci like
  99. "...deny(all) A or B" then the same
  100. situation is arguably a security hole. Note that this scheme also makes
  101. the final result
  102. dependent on the evaluation order and so if the evaluation engine does
  103. anything fancy internally (eg. reordering the terms in an OR so that fast
  104. to evaluate ones came first) then
  105. this would need to be documented so that a user (or a tool) could look at
  106. the external syntax and figure out the result of the evaluation.
  107. Also it breaks commutivity and De Morgans law.
  108. The LDAP filter scheme is starting to look good--it solves the problems of
  109. the
  110. libaccess approach, makes the final result of an expression independent of
  111. the evaluation order and
  112. gives you back commutivity of OR and AND. De Morgans is still broken, but
  113. that's because of the asymmetry of behaviour of UNDEFINED with OR and AND.
  114. So...?
  115. For acis, in general it can look like this:
  116. "...allow(rights)(LogicalCombinationofBindRule);
  117. deny(LogicalCombinationOfBindRule)...."
  118. A BindRule is one of the "userdn", "groupdn" or "userattr" things and it
  119. can look like this:
  120. "groupdn = "ldap:///cn=G1,o=sun.com || ldap:///cn=G2,o=sun.com"
  121. The "=" here may be "!=" as well and these routines take care of the
  122. comparator.
  123. For "userattr" keywords a mutilvalued attribute amounts a logical OR of the
  124. individual values. There is also a logical OR over the different levels
  125. as specified by the "parent" keyword.
  126. In fact there are three levels of logical combination:
  127. 1. In the aclplugin:
  128. The "||" and "!=" combinator for BindRule keywords like userdn and
  129. groupdn.
  130. The fact that for the "userattr" keyword, a mutilvalued attribute is
  131. evaluated as "||". Same for the different levels.
  132. 2. In libaccess:
  133. The logical combination of BindRules.
  134. 3. In libaccess:
  135. The evaluation of multiple BindRules seperated by ";", which means OR.
  136. The LDAP filter three-valued logic SHOULD be applied to each level but
  137. here's the way it works right now:
  138. 1. At this level it depends....
  139. DS_LASIpGetter - get attr for IP -
  140. returns ip address or LAS_EVAL_FAIL for error.
  141. no logical combination.
  142. DS_LASDnsGetter - get attr for DNS-
  143. returns dns name or LAS_EVAL_FAIL for error
  144. no logical combination.
  145. DS_LASUserDnEval - LAS Evaluation for USERDN -
  146. three-valued logic
  147. logical combination: || and !=
  148. DS_LASGroupDnEval - LAS Evaluation for GROUPDN -
  149. three-valued logic
  150. logical combination: || and !=
  151. DS_LASRoleDnEval - LAS Evaluation for ROLEDN -
  152. three-valued logic
  153. logical combination: || and !=
  154. DS_LASUserDnAttrEval - LAS Evaluation for USERDNATTR -
  155. three-valued logic
  156. logical combination || (over specified attribute values and
  157. parent keyword levels), !=
  158. DS_LASAuthMethodEval - LAS Evaluation for AUTHMETHOD -
  159. three-valued logic ( logical combinations: !=)
  160. DS_LASGroupDnAttrEval - LAS Evaluation for GROUPDNATTR -
  161. three-valued logic
  162. logical combination || (over specified attribute values and
  163. parent keyword levels), !=
  164. DS_LASUserAttrEval - LAS Evaluation for USERATTR -
  165. USER, GROUPDN and ROLEDN as above.
  166. LDAPURL -- three-valued logic (logical combinations: || over
  167. specified attribute vales, !=)
  168. attrname#attrvalue -- three-valued logic, logical combination:!=
  169. 2. The libaccess scheme applies at this level.
  170. 3. The LDAP filter three-valued logic applies at this level.
  171. Example of realistic, non-bizarre things that cause evaluation of a
  172. BindRule to be undefined are exceeding some resource limits (nesting level,
  173. lookthrough limit) in group membership evaluation, or trying to get ADD
  174. permission from the "userattr" keyword at "parent" level 0.
  175. Note that not everything that might be construed as an error needs to be
  176. taken as UNDEFINED. For example, things like not finding a user or an
  177. attribute in an entry can be defined away as TRUE or FALSE. eg. in an
  178. LDAP filter (cn=rob) applied to an entry where cn is not present is FALSE,
  179. not UNDEFINED. Similarly, if the number of levels in a parent keyword
  180. exceeds the allowed limit, we just ignore the rest--though this
  181. is a syntax error which should be detected at parse time.
  182. */
  183. /* To get around warning: declared in ldapserver/lib/ldaputil/ldaputili.h */
  184. extern int ldapu_member_certificate_match (void* cert, const char* desc);
  185. /****************************************************************************/
  186. /* Defines, Constants, ande Declarations */
  187. /****************************************************************************/
  188. static char* const type_objectClass = "objectclass";
  189. static char* const filter_groups = "(|(objectclass=groupOfNames) (objectclass=groupOfUniqueNames)(objectclass=groupOfCertificates)(objectclass=groupOfURLs))";
  190. static char* const type_member = "member";
  191. static char* const type_uniquemember = "uniquemember";
  192. static char* const type_memberURL = "memberURL";
  193. static char* const type_memberCert = "memberCertificateDescription";
  194. /* cache strategy for groups */
  195. #define ACLLAS_CACHE_MEMBER_GROUPS 0x1
  196. #define ACLLAS_CACHE_NOT_MEMBER_GROUPS 0x2
  197. #define ACLLAS_CACHE_ALL_GROUPS 0x3
  198. /****************************************************************************/
  199. /* prototypes */
  200. /****************************************************************************/
  201. static int acllas__handle_group_entry(Slapi_Entry *, void *);
  202. static int acllas__user_ismember_of_group(struct acl_pblock *aclpb,
  203. char* groupDN,
  204. char* clientDN,
  205. int cache_status,
  206. CERTCertificate *clientCert);
  207. static int acllas__user_has_role( struct acl_pblock *aclpb,
  208. Slapi_DN *roleDN, Slapi_DN *clientDn);
  209. static int acllas__add_allgroups (Slapi_Entry* e, void *callback_data);
  210. static int acllas__eval_memberGroupDnAttr (char *attrName,
  211. Slapi_Entry *e,
  212. char *n_clientdn,
  213. struct acl_pblock *aclpb);
  214. static int acllas__verify_client (Slapi_Entry* e, void *callback_data);
  215. static int acllas__verify_ldapurl (Slapi_Entry* e, void *callback_data);
  216. static char* acllas__dn_parent( char *dn, int level);
  217. static int acllas__get_members (Slapi_Entry* e, void *callback_data);
  218. static int acllas__client_match_URL (struct acl_pblock *aclpb,
  219. char *n_dn, char *url );
  220. static int acllas__handle_client_search (Slapi_Entry *e, void *callback_data);
  221. static int __acllas_setup ( NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  222. char *attr_pattern, int *cachable, void **LAS_cookie,
  223. PList_t subject, PList_t resource, PList_t auth_info,
  224. PList_t global_auth, char *lasType, char *lasName, lasInfo *linfo);
  225. int
  226. aclutil_evaluate_macro( char * user, lasInfo *lasinfo,
  227. acl_eval_types evalType );
  228. static int
  229. acllas_eval_one_user( struct acl_pblock *aclpb,
  230. char * clientDN, char *userKeyword);
  231. static int
  232. acllas_eval_one_group(char *group, lasInfo *lasinfo);
  233. static int
  234. acllas_eval_one_role(char *role, lasInfo *lasinfo);
  235. static char **
  236. acllas_replace_dn_macro( char *rule, char *matched_val, lasInfo *lasinfo);
  237. static char **
  238. acllas_replace_attr_macro( char *rule, lasInfo *lasinfo);
  239. static int
  240. acllas_eval_one_target_filter( char * str, Slapi_Entry *e);
  241. /****************************************************************************/
  242. int
  243. DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
  244. auth_info, PList_t global_auth, void *arg)
  245. {
  246. struct acl_pblock *aclpb = NULL;
  247. IPAddr_t ip=0;
  248. PRNetAddr client_praddr;
  249. struct in_addr client_addr;
  250. int rv;
  251. rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb,
  252. subject, resource, auth_info, global_auth);
  253. if ( rv != LAS_EVAL_TRUE || ( NULL == aclpb )) {
  254. acl_print_acllib_err(errp, NULL);
  255. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  256. "DS_LASIpGetter:Unable to get the ACLPB(%d)\n", rv);
  257. return LAS_EVAL_FAIL;
  258. }
  259. if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR,
  260. &client_praddr ) != 0 ) {
  261. slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
  262. return( LAS_EVAL_FAIL );
  263. }
  264. if ( !PR_IsNetAddrType(&client_praddr, PR_IpAddrV4Mapped) ) {
  265. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  266. "Client address is IPv6. ACLs only support IPv4 addresses so far.\n");
  267. return( LAS_EVAL_FAIL );
  268. }
  269. client_addr.s_addr = client_praddr.ipv6.ip.pr_s6_addr32[3];
  270. ip = (IPAddr_t) ntohl( client_addr.s_addr );
  271. rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *)ip, NULL);
  272. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  273. "Returning client ip address '%s'\n",
  274. (slapi_is_loglevel_set(SLAPI_LOG_ACL) ? inet_ntoa(client_addr) : ""));
  275. return LAS_EVAL_TRUE;
  276. }
  277. /*
  278. * This is called from the libaccess code when it needs to find a dns name.
  279. * It's called from ACL_GetAttribute() when it finds that ACL_ATTR_DNS is
  280. * not already part of the proplist.
  281. *
  282. */
  283. int
  284. DS_LASDnsGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
  285. auth_info, PList_t global_auth, void *arg)
  286. {
  287. struct acl_pblock *aclpb = NULL;
  288. PRNetAddr client_praddr;
  289. PRHostEnt *hp;
  290. char *dnsName = NULL;
  291. int rv;
  292. struct berval **clientDns;
  293. rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb,
  294. subject, resource, auth_info, global_auth);
  295. if ( rv != LAS_EVAL_TRUE || ( NULL == aclpb )) {
  296. acl_print_acllib_err(errp, NULL);
  297. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  298. "DS_LASDnsGetter:Unable to get the ACLPB(%d)\n", rv);
  299. return LAS_EVAL_FAIL;
  300. }
  301. if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CLIENT_DNS, &clientDns ) != 0 ) {
  302. slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
  303. return( LAS_EVAL_FAIL );
  304. }
  305. /*
  306. * If the client hostname has already been put into the pblock then
  307. * use that. Otherwise we work it out and add it ourselves.
  308. * This info is connection-lifetime so with multiple operaitons on the same
  309. * connection we will only do the calculation once.
  310. *
  311. * rbyrneXXX surely this code would be better in connection.c so
  312. * the name would be just there waiting for us, and everyone else.
  313. *
  314. */
  315. if ( clientDns && clientDns[0] != NULL && clientDns[0]->bv_val ) {
  316. dnsName = clientDns[0]->bv_val;
  317. } else {
  318. struct berval **dnsList;
  319. char buf[PR_NETDB_BUF_SIZE];
  320. if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR, &client_praddr ) != 0 ) {
  321. slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
  322. return( LAS_EVAL_FAIL );
  323. }
  324. hp = (PRHostEnt *)slapi_ch_malloc( sizeof(PRHostEnt) );
  325. if ( PR_GetHostByAddr( &(client_praddr), (char *)buf, sizeof(buf), hp ) == PR_SUCCESS ) {
  326. if ( hp->h_name != NULL ) {
  327. dnsList = (struct berval**)
  328. slapi_ch_calloc (1, sizeof(struct berval*) * (1 + 1));
  329. *dnsList = (struct berval*)
  330. slapi_ch_calloc ( 1, sizeof(struct berval));
  331. dnsName = (*dnsList)->bv_val = slapi_ch_strdup( hp->h_name );
  332. (*dnsList)->bv_len = strlen ( (*dnsList)->bv_val );
  333. slapi_pblock_set( aclpb->aclpb_pblock, SLAPI_CLIENT_DNS, &dnsList );
  334. }
  335. }
  336. slapi_ch_free( (void **)&hp );
  337. }
  338. if ( NULL == dnsName ) return LAS_EVAL_FAIL;
  339. rv = PListInitProp(subject, 0, ACL_ATTR_DNS, dnsName, NULL);
  340. if (rv < 0) {
  341. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  342. "DS_LASDnsGetter:Couldn't set the DNS property(%d)\n", rv );
  343. return LAS_EVAL_FAIL;
  344. }
  345. slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "DNS name: %s\n", dnsName );
  346. return LAS_EVAL_TRUE;
  347. }
  348. /***************************************************************************/
  349. /* New LASes */
  350. /* */
  351. /* 1. user, groups. -- stubs to report errors. Not supported. */
  352. /* 2. userdn */
  353. /* 3. groupdn */
  354. /* 4. userdnattr */
  355. /* 5. authmethod */
  356. /* 6. groupdnattr */
  357. /* 7. roledn */
  358. /* */
  359. /* */
  360. /***************************************************************************/
  361. int
  362. DS_LASUserEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  363. char *attr_pattern, int *cachable, void **LAS_cookie,
  364. PList_t subject, PList_t resource, PList_t auth_info,
  365. PList_t global_auth)
  366. {
  367. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  368. "User LAS is not supported in the ACL\n");
  369. return LAS_EVAL_INVALID;
  370. }
  371. int
  372. DS_LASGroupEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  373. char *attr_pattern, int *cachable, void **LAS_cookie,
  374. PList_t subject, PList_t resource, PList_t auth_info,
  375. PList_t global_auth)
  376. {
  377. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  378. "Group LAS is not supported in the ACL\n");
  379. return LAS_EVAL_INVALID;
  380. }
  381. /***************************************************************************
  382. *
  383. * DS_LASUserDnEval
  384. * Evaluate the "userdn" LAS. See if the user has rights.
  385. *
  386. * Input:
  387. * attr_name The string "userdn" - in lower case.
  388. * comparator CMP_OP_EQ or CMP_OP_NE only
  389. * attr_pattern A comma-separated list of users
  390. * cachable Always set to FALSE.
  391. * subject Subject property list
  392. * resource Resource property list
  393. * auth_info Authentication info, if any
  394. *
  395. * Returns:
  396. * retcode The usual LAS return codes.
  397. *
  398. * Error Handling:
  399. * None.
  400. *
  401. **************************************************************************/
  402. int
  403. DS_LASUserDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  404. char *attr_pattern, int *cachable, void **LAS_cookie,
  405. PList_t subject, PList_t resource, PList_t auth_info,
  406. PList_t global_auth)
  407. {
  408. char *users = NULL;
  409. char *s_user, *user = NULL;
  410. char *ptr = NULL;
  411. char *end_dn = NULL;
  412. char *n_edn = NULL;
  413. char *parent_dn = NULL;
  414. int matched;
  415. int rc;
  416. short len;
  417. const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
  418. lasInfo lasinfo;
  419. int got_undefined = 0;
  420. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  421. attr_pattern,cachable,LAS_cookie,
  422. subject, resource, auth_info,global_auth,
  423. DS_LAS_USERDN, "DS_LASUserDnEval", &lasinfo )) ) {
  424. return LAS_EVAL_FAIL;
  425. }
  426. users = slapi_ch_strdup(attr_pattern);
  427. user = users;
  428. matched = ACL_FALSE;
  429. /* check if the clientdn is one of the users */
  430. while(user != 0 && *user != 0 && matched != ACL_TRUE ) {
  431. /* ignore leading whitespace */
  432. while(ldap_utf8isspace(user))
  433. LDAP_UTF8INC(user);
  434. /* Now we must see the userdn in the following
  435. ** formats:
  436. **
  437. ** The following formats are supported:
  438. **
  439. ** 1. The DN itself:
  440. ** allow (read) userdn = "ldap:///cn=prasanta, ..."
  441. **
  442. ** 2. keyword SELF:
  443. ** allow (write)
  444. ** userdn = "ldap:///self"
  445. **
  446. ** 3. Pattern:
  447. ** deny (read) userdn = "ldap:///cn=*, o=netscape, c = us";
  448. **
  449. ** 4. Anonymous user
  450. ** deny (read, write) userdn = "ldap:///anyone"
  451. **
  452. ** 5. All users (All authenticated users)
  453. ** allow (search) ** userdn = "ldap:///all"
  454. ** 6. parent "ldap:///parent"
  455. ** 7. Synamic users using the URL
  456. **
  457. **
  458. ** DNs must be separated by "||". Ex:
  459. ** allow (read)
  460. ** userdn = "ldap:///DN1 || ldap:///DN2"
  461. */
  462. /* The DN is now "ldap:///DN"
  463. ** remove the "ldap:///" part
  464. */
  465. if (strncasecmp (user, LDAP_URL_prefix,
  466. LDAP_URL_prefix_len) == 0) {
  467. s_user = user;
  468. user += LDAP_URL_prefix_len;
  469. } else {
  470. char ebuf[ BUFSIZ ];
  471. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  472. "DS_LASUserDnEval:Syntax error(%s)\n",
  473. escape_string_with_punctuation( user, ebuf ));
  474. return LAS_EVAL_FAIL;
  475. }
  476. /* Now we have the starting point of the "userdn" */
  477. if ((end_dn = strstr(user, "||")) != NULL) {
  478. auto char *t = end_dn;
  479. LDAP_UTF8INC(end_dn);
  480. LDAP_UTF8INC(end_dn);
  481. *t = 0;
  482. }
  483. /* Now user is a null terminated string */
  484. if (*user) {
  485. while(ldap_utf8isspace(user))
  486. LDAP_UTF8INC(user);
  487. /* ignore trailing whitespace */
  488. len = strlen(user);
  489. ptr = user+len-1;
  490. while(ptr >= user && ldap_utf8isspace(ptr)) {
  491. *ptr = '\0';
  492. LDAP_UTF8DEC(ptr);
  493. }
  494. }
  495. /*
  496. ** Check , if the user is a anonymous user. In that case
  497. ** We must find the rule "ldap:///anyone"
  498. */
  499. if (lasinfo.anomUser) {
  500. if (strcasecmp(user, "anyone") == 0 ) {
  501. /* matches -- anonymous user */
  502. matched = ACL_TRUE;
  503. break;
  504. }
  505. } else {
  506. /* URL format */
  507. if ((strstr (user, ACL_RULE_MACRO_DN_KEY) != NULL) ||
  508. (strstr (user, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) ||
  509. (strstr (user, ACL_RULE_MACRO_ATTR_KEY) != NULL)) {
  510. matched = aclutil_evaluate_macro( s_user, &lasinfo,
  511. ACL_EVAL_USER);
  512. if (matched == ACL_TRUE) {
  513. break;
  514. }
  515. } else if (strchr (user, '?') != NULL) {
  516. /* URL format */
  517. if (acllas__client_match_URL ( lasinfo.aclpb, lasinfo.clientDn,
  518. s_user) == ACL_TRUE) {
  519. matched = ACL_TRUE;
  520. break;
  521. }
  522. } else if (strcasecmp(user, "anyone") == 0 ) {
  523. /* Anyone means anyone in the world */
  524. matched = ACL_TRUE;
  525. break;
  526. } else if (strcasecmp(user, "self") == 0) {
  527. if (n_edn == NULL) {
  528. n_edn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
  529. }
  530. if (slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn, (ACLUCHP)n_edn) == 0)
  531. matched = ACL_TRUE;
  532. break;
  533. } else if (strcasecmp(user, "parent") == 0) {
  534. if (n_edn == NULL) {
  535. n_edn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
  536. }
  537. /* get the parent */
  538. parent_dn = slapi_dn_parent(n_edn);
  539. if (parent_dn &&
  540. slapi_utf8casecmp ((ACLUCHP)lasinfo.clientDn, (ACLUCHP)parent_dn) == 0)
  541. matched = ACL_TRUE;
  542. if (parent_dn) slapi_ch_free ( (void **) &parent_dn );
  543. break;
  544. } else if (strcasecmp(user, "all") == 0) {
  545. /* matches -- */
  546. matched = ACL_TRUE;
  547. break;
  548. } else if (strchr(user, '*')) {
  549. char line[200];
  550. char *lineptr = &line[0];
  551. char *newline = NULL;
  552. int lenu = 0;
  553. Slapi_Filter *f = NULL;
  554. char *tt;
  555. int filterChoice;
  556. /*
  557. ** what we are doing is faking the str2simple()
  558. ** function with a "userdn = "user")
  559. */
  560. for (tt = user; *tt; tt++)
  561. *tt = TOLOWER ( *tt );
  562. if ((lenu = strlen(user)) > 190) { /* 200 - 9 for "(userdn=%s)" */
  563. newline = slapi_ch_malloc(lenu + 10);
  564. lineptr = newline;
  565. }
  566. sprintf (lineptr, "(userdn=%s)", user);
  567. if ((f = slapi_str2filter (lineptr)) == NULL) {
  568. if (newline) slapi_ch_free((void **) &newline);
  569. /* try the next one */
  570. break;
  571. }
  572. if (newline) slapi_ch_free((void **) &newline);
  573. filterChoice = slapi_filter_get_choice ( f );
  574. if (( filterChoice != LDAP_FILTER_SUBSTRINGS) &&
  575. ( filterChoice != LDAP_FILTER_PRESENT)) {
  576. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  577. "DS_LASUserDnEval:Error in gen. filter(%s)\n", user);
  578. }
  579. if ((rc = acl_match_substring( f,
  580. lasinfo.clientDn,
  581. 1 /*exact match */)
  582. ) == ACL_TRUE) {
  583. matched = ACL_TRUE;
  584. slapi_filter_free(f,1);
  585. break;
  586. }
  587. if (rc == ACL_ERR) {
  588. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  589. "DS_LASUserDnEval:Error in matching patteren(%s)\n",
  590. user);
  591. }
  592. slapi_filter_free(f,1);
  593. } else {
  594. /* Must be a simple dn then */
  595. if (slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn,
  596. (ACLUCHP)slapi_dn_normalize(user)) == 0) {
  597. matched = ACL_TRUE;
  598. break;
  599. }
  600. }
  601. }
  602. if ( matched == ACL_DONT_KNOW ) {
  603. /* record this but keep going--maybe another user will evaluate to TRUE */
  604. got_undefined = 1;
  605. }
  606. /* Nothing matched -- try the next DN */
  607. user = end_dn;
  608. } /* end of while */
  609. slapi_ch_free ( (void **) &users);
  610. /*
  611. * If no terms were undefined, then evaluate as normal.
  612. * If there was an undefined term, but another one was TRUE, then we also evaluate
  613. * as normal. Otherwise, the whole expression is UNDEFINED.
  614. */
  615. if ( matched == ACL_TRUE || !got_undefined ) {
  616. if (comparator == CMP_OP_EQ) {
  617. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  618. } else {
  619. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  620. }
  621. } else {
  622. rc = LAS_EVAL_FAIL;
  623. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  624. "Returning UNDEFINED for userdn evaluation.\n");
  625. }
  626. return rc;
  627. }
  628. /***************************************************************************
  629. *
  630. * DS_LASGroupDnEval
  631. *
  632. *
  633. * Input:
  634. * attr_name The string "userdn" - in lower case.
  635. * comparator CMP_OP_EQ or CMP_OP_NE only
  636. * attr_pattern A comma-separated list of users
  637. * cachable Always set to FALSE.
  638. * subject Subject property list
  639. * resource Resource property list
  640. * auth_info Authentication info, if any
  641. *
  642. * Returns:
  643. * retcode The usual LAS return code
  644. * If the client is in any of the groups mentioned this groupdn keywrod
  645. * then returns LAS_EVAL_TRUE, if he's not in any LAS_EVAL_FALSE.
  646. * If any of the membership evaluations fail, then it goes on to evaluate the
  647. * others.
  648. *
  649. * Error Handling:
  650. * None.
  651. *
  652. **************************************************************************/
  653. int
  654. DS_LASGroupDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  655. char *attr_pattern, int *cachable, void **LAS_cookie,
  656. PList_t subject, PList_t resource, PList_t auth_info,
  657. PList_t global_auth)
  658. {
  659. char *groups;
  660. char *groupNameOrig;
  661. char *groupName;
  662. char *ptr;
  663. char *end_dn;
  664. int matched;
  665. int rc;
  666. int len;
  667. const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
  668. int any_group = 0;
  669. lasInfo lasinfo;
  670. int got_undefined = 0;
  671. /* the setup should not fail under normal operation */
  672. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  673. attr_pattern,cachable,LAS_cookie,
  674. subject, resource, auth_info,global_auth,
  675. DS_LAS_GROUPDN, "DS_LASGroupDnEval", &lasinfo )) ) {
  676. return LAS_EVAL_FAIL;
  677. }
  678. groups = slapi_ch_strdup(attr_pattern);
  679. groupNameOrig = groupName = groups;
  680. matched = ACL_FALSE;
  681. /* check if the groupdn is one of the users */
  682. while(groupName != 0 && *groupName != 0 && matched != ACL_TRUE) {
  683. /* ignore leading whitespace */
  684. while(ldap_utf8isspace(groupName))
  685. LDAP_UTF8INC(groupName);
  686. /*
  687. ** The syntax allowed for the groupdn is
  688. **
  689. ** Example:
  690. ** groupdn = "ldap:///dn1 || ldap:///dn2";
  691. **
  692. */
  693. if (strncasecmp (groupName, LDAP_URL_prefix,
  694. LDAP_URL_prefix_len) == 0) {
  695. groupName += LDAP_URL_prefix_len;
  696. } else {
  697. char ebuf[ BUFSIZ ];
  698. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  699. "DS_LASGroupDnEval:Syntax error(%s)\n",
  700. escape_string_with_punctuation( groupName, ebuf ));
  701. }
  702. /* Now we have the starting point of the "groupdn" */
  703. if ((end_dn = strstr(groupName, "||")) != NULL) {
  704. auto char *t = end_dn;
  705. LDAP_UTF8INC(end_dn);
  706. LDAP_UTF8INC(end_dn);
  707. /* removing trailing spaces */
  708. LDAP_UTF8DEC(t);
  709. while (' ' == *t || '\t' == *t) {
  710. LDAP_UTF8DEC(t);
  711. }
  712. LDAP_UTF8INC(t);
  713. *t = '\0';
  714. /* removing beginning spaces */
  715. while (' ' == *end_dn || '\t' == *end_dn) {
  716. LDAP_UTF8INC(end_dn);
  717. }
  718. }
  719. if (*groupName) {
  720. while(ldap_utf8isspace(groupName))
  721. LDAP_UTF8INC(groupName);
  722. /* ignore trailing whitespace */
  723. len = strlen(groupName);
  724. ptr = groupName+len-1;
  725. while(ptr >= groupName && ldap_utf8isspace(ptr)) {
  726. *ptr = '\0';
  727. LDAP_UTF8DEC(ptr);
  728. }
  729. }
  730. /*
  731. ** Now we have the DN of the group. Evaluate the "clientdn"
  732. ** and see if the user is a member of the group.
  733. */
  734. if (0 == (strcasecmp(groupName, "anyone"))) {
  735. any_group = 1;
  736. }
  737. if (any_group) {
  738. /* anyone in the world */
  739. matched = ACL_TRUE;
  740. break;
  741. } else if ( lasinfo.anomUser &&
  742. (lasinfo.aclpb->aclpb_clientcert == NULL) && (!any_group)) {
  743. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  744. "Group not evaluated(%s)\n", groupName);
  745. break;
  746. } else {
  747. if ((strstr (groupName, ACL_RULE_MACRO_DN_KEY) != NULL) ||
  748. (strstr (groupName, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) ||
  749. (strstr (groupName, ACL_RULE_MACRO_ATTR_KEY) != NULL)) {
  750. matched = aclutil_evaluate_macro( groupName, &lasinfo,
  751. ACL_EVAL_GROUP);
  752. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  753. "DS_LASGroupDnEval: Param group name:%s\n",
  754. groupName);
  755. } else {
  756. LDAPURLDesc *ludp = NULL;
  757. int rval;
  758. Slapi_PBlock *myPb = NULL;
  759. Slapi_Entry **grpentries = NULL;
  760. /* Groupdn is full ldapurl? */
  761. if (0 == ldap_url_parse(groupNameOrig, &ludp) &&
  762. NULL != ludp->lud_dn &&
  763. -1 != ludp->lud_scope &&
  764. NULL != ludp->lud_filter) {
  765. /* Yes, it is full ldapurl; Let's run the search */
  766. myPb = slapi_pblock_new ();
  767. slapi_search_internal_set_pb(
  768. myPb,
  769. ludp->lud_dn,
  770. ludp->lud_scope,
  771. ludp->lud_filter,
  772. NULL,
  773. 0,
  774. NULL /* controls */,
  775. NULL /* uniqueid */,
  776. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  777. 0 );
  778. slapi_search_internal_pb(myPb);
  779. slapi_pblock_get(myPb, SLAPI_PLUGIN_INTOP_RESULT, &rval);
  780. if (rval == LDAP_SUCCESS) {
  781. Slapi_Entry **ep;
  782. slapi_pblock_get(myPb,
  783. SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &grpentries);
  784. if ((grpentries != NULL) && (grpentries[0] != NULL)) {
  785. char *edn = NULL;
  786. for (ep = grpentries; *ep; ep++) {
  787. /* groups having ACI */
  788. edn = slapi_entry_get_ndn(*ep);
  789. matched = acllas_eval_one_group(edn, &lasinfo);
  790. if (ACL_TRUE == matched) {
  791. break; /* matched ! */
  792. }
  793. }
  794. }
  795. }
  796. slapi_free_search_results_internal(myPb);
  797. slapi_pblock_destroy (myPb);
  798. } else {
  799. /* normal evaluation */
  800. matched = acllas_eval_one_group( groupName, &lasinfo );
  801. }
  802. if ( ludp ) {
  803. ldap_free_urldesc( ludp );
  804. }
  805. }
  806. if ( matched == ACL_TRUE ) {
  807. break;
  808. } else if ( matched == ACL_DONT_KNOW ) {
  809. /* record this but keep going--maybe another group will evaluate to TRUE */
  810. got_undefined = 1;
  811. }
  812. }
  813. /* Nothing matched -- try the next DN */
  814. groupNameOrig = groupName = end_dn;
  815. } /* end of while */
  816. /*
  817. * If no terms were undefined, then evaluate as normal.
  818. * If there was an undefined term, but another one was TRUE, then we also evaluate
  819. * as normal. Otherwise, the whole expression is UNDEFINED.
  820. */
  821. if ( matched == ACL_TRUE || !got_undefined ) {
  822. if (comparator == CMP_OP_EQ) {
  823. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  824. } else {
  825. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  826. }
  827. } else {
  828. rc = LAS_EVAL_FAIL;
  829. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  830. "Returning UNDEFINED for groupdn evaluation.\n");
  831. }
  832. slapi_ch_free ((void**) &groups);
  833. return rc;
  834. }
  835. /***************************************************************************
  836. *
  837. * DS_LASRoleDnEval
  838. *
  839. *
  840. * Input:
  841. * attr_name The string "roledn" - in lower case.
  842. * comparator CMP_OP_EQ or CMP_OP_NE only
  843. * attr_pattern A "||" sperated list of roles
  844. * cachable Always set to FALSE.
  845. * subject Subject property list
  846. * resource Resource property list
  847. * auth_info Authentication info, if any
  848. *
  849. * Returns:
  850. * retcode The usual LAS return codes.
  851. *
  852. * Error Handling:
  853. * None.
  854. *
  855. **************************************************************************/
  856. int
  857. DS_LASRoleDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  858. char *attr_pattern, int *cachable, void **LAS_cookie,
  859. PList_t subject, PList_t resource, PList_t auth_info,
  860. PList_t global_auth)
  861. {
  862. char *roles;
  863. char *role;
  864. char *ptr;
  865. char *end_dn;
  866. int matched;
  867. int rc;
  868. int len;
  869. const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
  870. int any_role = 0;
  871. lasInfo lasinfo;
  872. int got_undefined = 0;
  873. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  874. attr_pattern,cachable,LAS_cookie,
  875. subject, resource, auth_info,global_auth,
  876. DS_LAS_ROLEDN, "DS_LASRoleDnEval",
  877. &lasinfo )) ) {
  878. return LAS_EVAL_FALSE;
  879. }
  880. roles = slapi_ch_strdup(attr_pattern);
  881. role = roles;
  882. matched = ACL_FALSE;
  883. /* check if the roledn is one of the users */
  884. while(role != 0 && *role != 0 && matched != ACL_TRUE) {
  885. /* ignore leading whitespace */
  886. while(ldap_utf8isspace(role))
  887. LDAP_UTF8INC(role);
  888. /*
  889. ** The syntax allowed for the roledn is
  890. **
  891. ** Example:
  892. ** roledn = "ldap:///roledn1 || ldap:///roledn2";
  893. **
  894. */
  895. if (strncasecmp (role, LDAP_URL_prefix,
  896. LDAP_URL_prefix_len) == 0) {
  897. role += LDAP_URL_prefix_len;
  898. } else {
  899. char ebuf[ BUFSIZ ];
  900. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  901. "DS_LASRoleDnEval:Syntax error(%s)\n",
  902. escape_string_with_punctuation( role, ebuf ));
  903. }
  904. /* Now we have the starting point of the "roledn" */
  905. if ((end_dn = strstr(role, "||")) != NULL) {
  906. auto char *t = end_dn;
  907. LDAP_UTF8INC(end_dn);
  908. LDAP_UTF8INC(end_dn);
  909. *t = 0;
  910. }
  911. if (*role) {
  912. while(ldap_utf8isspace(role))
  913. LDAP_UTF8INC(role);
  914. /* ignore trailing whitespace */
  915. len = strlen(role);
  916. ptr = role+len-1;
  917. while(ptr >= role && ldap_utf8isspace(ptr)) {
  918. *ptr = '\0';
  919. LDAP_UTF8DEC(ptr);
  920. }
  921. }
  922. /*
  923. ** Now we have the DN of the role. Evaluate the "clientdn"
  924. ** and see if the user has this role.
  925. */
  926. if (0 == (strcasecmp(role, "anyone"))) {
  927. any_role = 1;
  928. }
  929. if (any_role) {
  930. /* anyone in the world */
  931. matched = ACL_TRUE;
  932. break;
  933. } else if ( lasinfo.anomUser &&
  934. (lasinfo.aclpb->aclpb_clientcert == NULL) && (!any_role)) {
  935. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  936. "Role not evaluated(%s) for anon user\n", role);
  937. break;
  938. } else {
  939. /* Take care of param strings */
  940. if ((strstr (role, ACL_RULE_MACRO_DN_KEY) != NULL) ||
  941. (strstr (role, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) ||
  942. (strstr (role, ACL_RULE_MACRO_ATTR_KEY) != NULL)) {
  943. matched = aclutil_evaluate_macro( role, &lasinfo,
  944. ACL_EVAL_ROLE);
  945. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  946. "DS_LASRoleDnEval: Param role name:%s\n",
  947. role);
  948. } else {/* normal evaluation */
  949. matched = acllas_eval_one_role( role, &lasinfo);
  950. }
  951. if ( matched == ACL_TRUE ) {
  952. break;
  953. } else if ( matched == ACL_DONT_KNOW ) {
  954. /* record this but keep going--maybe another role will evaluate to TRUE */
  955. got_undefined = 1;
  956. }
  957. }
  958. /* Nothing matched -- try the next DN */
  959. role = end_dn;
  960. } /* end of while */
  961. /*
  962. * If no terms were undefined, then evaluate as normal.
  963. * If there was an undefined term, but another one was TRUE, then we also evaluate
  964. * as normal. Otherwise, the whole expression is UNDEFINED.
  965. */
  966. if ( matched == ACL_TRUE || !got_undefined ) {
  967. if (comparator == CMP_OP_EQ) {
  968. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  969. } else {
  970. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  971. }
  972. } else {
  973. rc = LAS_EVAL_FAIL;
  974. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  975. "Returning UNDEFINED for roledn evaluation.\n");
  976. }
  977. slapi_ch_free ((void**) &roles);
  978. return rc;
  979. }
  980. /***************************************************************************
  981. *
  982. * DS_LASUserDnAttrEval
  983. *
  984. *
  985. * Input:
  986. * attr_name The string "userdn" - in lower case.
  987. * comparator CMP_OP_EQ or CMP_OP_NE only
  988. * attr_pattern A comma-separated list of users
  989. * cachable Always set to FALSE.
  990. * subject Subject property list
  991. * resource Resource property list
  992. * auth_info Authentication info, if any
  993. *
  994. * Returns:
  995. * retcode The usual LAS return codes.
  996. *
  997. * Error Handling:
  998. * None.
  999. *
  1000. **************************************************************************/
  1001. struct userdnattr_info {
  1002. char *attr;
  1003. int result;
  1004. char *clientdn;
  1005. Acl_PBlock *aclpb;
  1006. };
  1007. #define ACLLAS_MAX_LEVELS 10
  1008. int
  1009. DS_LASUserDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  1010. char *attr_pattern, int *cachable, void **LAS_cookie,
  1011. PList_t subject, PList_t resource, PList_t auth_info,
  1012. PList_t global_auth)
  1013. {
  1014. char *n_currEntryDn = NULL;
  1015. char *s_attrName, *attrName;
  1016. char *ptr;
  1017. int matched;
  1018. int rc, len, i;
  1019. char *val;
  1020. Slapi_Attr *a;
  1021. int levels[ACLLAS_MAX_LEVELS];
  1022. int numOflevels =0;
  1023. struct userdnattr_info info;
  1024. char *attrs[2] = { LDAP_ALL_USER_ATTRS, NULL };
  1025. lasInfo lasinfo;
  1026. int got_undefined = 0;
  1027. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  1028. attr_pattern,cachable,LAS_cookie,
  1029. subject, resource, auth_info,global_auth,
  1030. DS_LAS_USERDNATTR, "DS_LASUserDnAttrEval",
  1031. &lasinfo )) ) {
  1032. return LAS_EVAL_FAIL;
  1033. }
  1034. /*
  1035. ** The userdnAttr syntax is
  1036. ** userdnattr = <attribute> or
  1037. ** userdnattr = parent[0,2,4].attribute"
  1038. ** Ex:
  1039. ** userdnattr = manager; or
  1040. ** userdnattr = "parent[0,2,4].manager";
  1041. **
  1042. ** Here 0 means current level, 2 means grandfather and
  1043. ** 4 (great great grandfather)
  1044. **
  1045. ** The function of this LAS is to compare the value of the
  1046. ** attribute in the Slapi_Entry with the "userdn".
  1047. **
  1048. ** Ex: userdn: "cn=prasanta, o= netscape, c= us"
  1049. ** and in the Slapi_Entry the manager attribute has
  1050. ** manager = <value>. Compare the userdn with manager.value to
  1051. ** determine the result.
  1052. **
  1053. */
  1054. s_attrName = attrName = slapi_ch_strdup (attr_pattern);
  1055. /* ignore leading/trailing whitespace */
  1056. while(ldap_utf8isspace(attrName)) LDAP_UTF8INC(attrName);
  1057. len = strlen(attrName);
  1058. ptr = attrName+len-1;
  1059. while(ptr >= attrName && ldap_utf8isspace(ptr)) {
  1060. *ptr = '\0';
  1061. LDAP_UTF8DEC(ptr);
  1062. }
  1063. /* See if we have a parent[2].attr" rule */
  1064. if ( (ptr = strstr(attrName, "parent[")) != NULL) {
  1065. char *word, *str, *next;
  1066. numOflevels = 0;
  1067. n_currEntryDn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
  1068. str = attrName;
  1069. word = ldap_utf8strtok_r(str, "[],. ",&next);
  1070. /* The first word is "parent[" and so it's not important */
  1071. while ((word= ldap_utf8strtok_r(NULL, "[],.", &next)) != NULL) {
  1072. if (ldap_utf8isdigit(word)) {
  1073. while (word && ldap_utf8isspace(word)) LDAP_UTF8INC(word);
  1074. if (numOflevels < ACLLAS_MAX_LEVELS)
  1075. levels[numOflevels++] = atoi (word);
  1076. else {
  1077. /*
  1078. * Here, ignore the extra levels..it's really
  1079. * a syntax error which should have been ruled out at parse time
  1080. */
  1081. slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
  1082. "DS_LASUserDnattr: Exceeded the ATTR LIMIT:%d: Ignoring extra levels\n",
  1083. ACLLAS_MAX_LEVELS);
  1084. }
  1085. } else {
  1086. /* Must be the attr name. We can goof of by
  1087. ** having parent[1,2,a] but then you have to be
  1088. ** stupid to do that.
  1089. */
  1090. char *p = word;
  1091. if (*--p == '.') {
  1092. attrName = word;
  1093. break;
  1094. }
  1095. }
  1096. }
  1097. info.attr = attrName;
  1098. info.clientdn = lasinfo.clientDn;
  1099. info.result = 0;
  1100. } else {
  1101. levels[0] = 0;
  1102. numOflevels = 1;
  1103. }
  1104. /* No attribute name specified--it's a syntax error and so undefined */
  1105. if (attrName == NULL ) {
  1106. slapi_ch_free ( (void**) &s_attrName);
  1107. return LAS_EVAL_FAIL;
  1108. }
  1109. slapi_log_error( SLAPI_LOG_ACL, plugin_name,"Attr:%s\n" , attrName);
  1110. matched = ACL_FALSE;
  1111. for (i=0; i < numOflevels; i++) {
  1112. if ( levels[i] == 0 ) {
  1113. Slapi_Value *sval=NULL;
  1114. const struct berval *attrVal;
  1115. int j;
  1116. /*
  1117. * For the add operation, the resource itself (level 0)
  1118. * must never be allowed to grant access--
  1119. * This is because access would be granted based on a value
  1120. * of an attribute in the new entry--security hole.
  1121. *
  1122. */
  1123. if ( lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
  1124. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1125. "ACL info: userdnAttr does not allow ADD permission at level 0.\n");
  1126. got_undefined = 1;
  1127. continue;
  1128. }
  1129. slapi_entry_attr_find( lasinfo.resourceEntry, attrName, &a);
  1130. if ( NULL == a ) continue;
  1131. j= slapi_attr_first_value ( a,&sval );
  1132. while ( j != -1 ) {
  1133. attrVal = slapi_value_get_berval ( sval );
  1134. /* Here if atleast 1 value matches then we are done.*/
  1135. val = slapi_dn_normalize (
  1136. slapi_ch_strdup( attrVal->bv_val));
  1137. if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)lasinfo.clientDn ) == 0) {
  1138. char ebuf [ BUFSIZ ];
  1139. /* Wow it matches */
  1140. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1141. "userdnAttr matches(%s, %s) level (%d)\n",
  1142. val,
  1143. ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo.clientDn, ebuf),
  1144. 0);
  1145. matched = ACL_TRUE;
  1146. slapi_ch_free ( (void **) &val);
  1147. break;
  1148. }
  1149. slapi_ch_free ( (void**) &val);
  1150. j = slapi_attr_next_value ( a, j, &sval );
  1151. }
  1152. } else {
  1153. char *p_dn; /* parent dn */
  1154. p_dn = acllas__dn_parent (n_currEntryDn, levels[i]);
  1155. if (p_dn == NULL) continue;
  1156. /* use new search internal API */
  1157. {
  1158. Slapi_PBlock *aPb = slapi_pblock_new ();
  1159. /*
  1160. * This search may be chained if chaining for ACL is
  1161. * is enabled in the backend and the entry is in
  1162. * a chained backend.
  1163. */
  1164. slapi_search_internal_set_pb ( aPb,
  1165. p_dn,
  1166. LDAP_SCOPE_BASE,
  1167. "objectclass=*",
  1168. &attrs[0],
  1169. 0,
  1170. NULL /* controls */,
  1171. NULL /* uniqueid */,
  1172. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  1173. 0 /* actions */);
  1174. slapi_search_internal_callback_pb(aPb,
  1175. &info /* callback_data */,
  1176. NULL/* result_callback */,
  1177. acllas__verify_client,
  1178. NULL /* referral_callback */);
  1179. slapi_pblock_destroy(aPb);
  1180. }
  1181. /*
  1182. * Currently info.result is boolean so
  1183. * we do not need to check for ACL_DONT_KNOW
  1184. */
  1185. if (info.result) {
  1186. matched = ACL_TRUE;
  1187. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1188. "userdnAttr matches at level (%d)\n", levels[i]);
  1189. }
  1190. }
  1191. if (matched == ACL_TRUE) {
  1192. break;
  1193. }
  1194. }
  1195. slapi_ch_free ( (void **) &s_attrName);
  1196. /*
  1197. * If no terms were undefined, then evaluate as normal.
  1198. * If there was an undefined term, but another one was TRUE, then we also evaluate
  1199. * as normal. Otherwise, the whole expression is UNDEFINED.
  1200. */
  1201. if ( matched == ACL_TRUE || !got_undefined ) {
  1202. if (comparator == CMP_OP_EQ) {
  1203. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  1204. } else {
  1205. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  1206. }
  1207. } else {
  1208. rc = LAS_EVAL_FAIL;
  1209. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1210. "Returning UNDEFINED for userdnattr evaluation.\n");
  1211. }
  1212. return rc;
  1213. }
  1214. /***************************************************************************
  1215. *
  1216. * DS_LASLdapUrlAttrEval
  1217. *
  1218. *
  1219. * Input:
  1220. * attr_name The string "ldapurl" - in lower case.
  1221. * comparator CMP_OP_EQ or CMP_OP_NE only
  1222. * attr_pattern A comma-separated list of users
  1223. * cachable Always set to FALSE.
  1224. * subject Subject property list
  1225. * resource Resource property list
  1226. * auth_info Authentication info, if any
  1227. * las_info LAS info to pass the resource entry
  1228. *
  1229. * Returns:
  1230. * retcode The usual LAS return codes.
  1231. *
  1232. * Error Handling:
  1233. * None.
  1234. *
  1235. **************************************************************************/
  1236. int
  1237. DS_LASLdapUrlAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  1238. char *attr_pattern, int *cachable, void **LAS_cookie,
  1239. PList_t subject, PList_t resource, PList_t auth_info,
  1240. PList_t global_auth, lasInfo lasinfo)
  1241. {
  1242. char *n_currEntryDn = NULL;
  1243. char *s_attrName = NULL, *attrName = NULL;
  1244. char *ptr;
  1245. int matched;
  1246. int rc, len, i;
  1247. int levels[ACLLAS_MAX_LEVELS];
  1248. int numOflevels =0;
  1249. struct userdnattr_info info;
  1250. char *attrs[2] = { LDAP_ALL_USER_ATTRS, NULL };
  1251. int got_undefined = 0;
  1252. /*
  1253. ** The ldapurlAttr syntax is
  1254. ** userdnattr = <attribute> or
  1255. ** userdnattr = parent[0,2,4].attribute"
  1256. ** Ex:
  1257. ** userdnattr = manager; or
  1258. ** userdnattr = "parent[0,2,4].manager";
  1259. **
  1260. ** Here 0 means current level, 2 means grandfather and
  1261. ** 4 (great great grandfather)
  1262. **
  1263. ** The function of this LAS is to compare the value of the
  1264. ** attribute in the Slapi_Entry with the "ldapurl".
  1265. **
  1266. ** Ex: ldapurl: ldap:///dc=example,dc=com??sub?(l=Mountain View)
  1267. ** and in the Slapi_Entry of the bind user has
  1268. ** l = Mountain View. Compare the bind user's 'l' and the value to
  1269. ** determine the result.
  1270. **
  1271. */
  1272. s_attrName = attrName = slapi_ch_strdup(attr_pattern);
  1273. /* ignore leading/trailing whitespace */
  1274. while (ldap_utf8isspace(attrName)) LDAP_UTF8INC(attrName);
  1275. len = strlen(attrName);
  1276. ptr = attrName+len-1;
  1277. while (ptr >= attrName && ldap_utf8isspace(ptr)) {
  1278. *ptr = '\0';
  1279. LDAP_UTF8DEC(ptr);
  1280. }
  1281. /* See if we have a parent[2].attr" rule */
  1282. if ( (ptr = strstr(attrName, "parent[")) != NULL) {
  1283. char *word, *str, *next;
  1284. numOflevels = 0;
  1285. n_currEntryDn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
  1286. str = attrName;
  1287. word = ldap_utf8strtok_r(str, "[],. ",&next);
  1288. /* The first word is "parent[" and so it's not important */
  1289. while ((word= ldap_utf8strtok_r(NULL, "[],.", &next)) != NULL) {
  1290. if (ldap_utf8isdigit(word)) {
  1291. while (word && ldap_utf8isspace(word)) LDAP_UTF8INC(word);
  1292. if (numOflevels < ACLLAS_MAX_LEVELS)
  1293. levels[numOflevels++] = atoi (word);
  1294. else {
  1295. /*
  1296. * Here, ignore the extra levels..it's really
  1297. * a syntax error which should have been ruled out at parse time
  1298. */
  1299. slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
  1300. "DS_LASLdapUrlattr: Exceeded the ATTR LIMIT:%d: Ignoring extra levels\n",
  1301. ACLLAS_MAX_LEVELS);
  1302. }
  1303. } else {
  1304. /* Must be the attr name. We can goof of by
  1305. ** having parent[1,2,a] but then you have to be
  1306. ** stupid to do that.
  1307. */
  1308. char *p = word;
  1309. if (*--p == '.') {
  1310. attrName = word;
  1311. break;
  1312. }
  1313. }
  1314. }
  1315. info.attr = attrName;
  1316. info.clientdn = lasinfo.clientDn;
  1317. info.aclpb = lasinfo.aclpb;
  1318. info.result = 0;
  1319. } else {
  1320. levels[0] = 0;
  1321. numOflevels = 1;
  1322. }
  1323. /* No attribute name specified--it's a syntax error and so undefined */
  1324. if (attrName == NULL ) {
  1325. slapi_ch_free ( (void**) &s_attrName);
  1326. return LAS_EVAL_FAIL;
  1327. }
  1328. slapi_log_error( SLAPI_LOG_ACL, plugin_name,"Attr:%s\n" , attrName);
  1329. matched = ACL_FALSE;
  1330. for (i = 0; i < numOflevels; i++) {
  1331. if ( levels[i] == 0 ) { /* parent[0] or the target itself */
  1332. Slapi_Value *sval = NULL;
  1333. const struct berval *attrVal;
  1334. Slapi_Attr *attrs;
  1335. int i;
  1336. /* Get the attr from the resouce entry */
  1337. if ( 0 == slapi_entry_attr_find (lasinfo.resourceEntry,
  1338. attrName, &attrs) ) {
  1339. i = slapi_attr_first_value ( attrs, &sval );
  1340. if ( i == -1 ) {
  1341. /* Attr val not there
  1342. * so it's value cannot equal other one */
  1343. matched = ACL_FALSE;
  1344. continue; /* try next level */
  1345. }
  1346. } else {
  1347. /* Not there so it cannot equal another one */
  1348. matched = ACL_FALSE;
  1349. continue; /* try next level */
  1350. }
  1351. while ( matched != ACL_TRUE && (sval != NULL)) {
  1352. attrVal = slapi_value_get_berval ( sval );
  1353. matched = acllas__client_match_URL ( lasinfo.aclpb,
  1354. lasinfo.clientDn,
  1355. attrVal->bv_val);
  1356. if ( matched != ACL_TRUE )
  1357. i = slapi_attr_next_value ( attrs, i, &sval );
  1358. if ( matched == ACL_DONT_KNOW ) {
  1359. got_undefined = 1;
  1360. }
  1361. }
  1362. } else {
  1363. char *p_dn; /* parent dn */
  1364. Slapi_PBlock *aPb = NULL;
  1365. p_dn = acllas__dn_parent (n_currEntryDn, levels[i]);
  1366. if (p_dn == NULL) continue;
  1367. /* use new search internal API */
  1368. aPb = slapi_pblock_new ();
  1369. /*
  1370. * This search may be chained if chaining for ACL is
  1371. * is enabled in the backend and the entry is in
  1372. * a chained backend.
  1373. */
  1374. slapi_search_internal_set_pb ( aPb,
  1375. p_dn,
  1376. LDAP_SCOPE_BASE,
  1377. "objectclass=*",
  1378. &attrs[0],
  1379. 0,
  1380. NULL /* controls */,
  1381. NULL /* uniqueid */,
  1382. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  1383. 0 /* actions */);
  1384. slapi_search_internal_callback_pb(aPb,
  1385. &info /* callback_data */,
  1386. NULL/* result_callback */,
  1387. acllas__verify_ldapurl,
  1388. NULL /* referral_callback */);
  1389. slapi_pblock_destroy(aPb);
  1390. /*
  1391. * Currently info.result is boolean so
  1392. * we do not need to check for ACL_DONT_KNOW
  1393. */
  1394. if (info.result) {
  1395. matched = ACL_TRUE;
  1396. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1397. "userdnAttr matches at level (%d)\n", levels[i]);
  1398. }
  1399. }
  1400. if (matched == ACL_TRUE) {
  1401. break;
  1402. }
  1403. }
  1404. slapi_ch_free ( (void **) &s_attrName);
  1405. /*
  1406. * If no terms were undefined, then evaluate as normal.
  1407. * If there was an undefined term, but another one was TRUE,
  1408. * then we also evaluate as normal.
  1409. * Otherwise, the whole expression is UNDEFINED.
  1410. */
  1411. if ( matched == ACL_TRUE || !got_undefined ) {
  1412. if (comparator == CMP_OP_EQ) {
  1413. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  1414. } else {
  1415. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  1416. }
  1417. } else {
  1418. rc = LAS_EVAL_FAIL;
  1419. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1420. "Returning UNDEFINED for userdnattr evaluation.\n");
  1421. }
  1422. return rc;
  1423. }
  1424. /***************************************************************************
  1425. *
  1426. * DS_LASAuthMethodEval
  1427. *
  1428. *
  1429. * Input:
  1430. * attr_name The string "authmethod" - in lower case.
  1431. * comparator CMP_OP_EQ or CMP_OP_NE only
  1432. * attr_pattern A comma-separated list of users
  1433. * cachable Always set to FALSE.
  1434. * subject Subject property list
  1435. * resource Resource property list
  1436. * auth_info Authentication info, if any
  1437. *
  1438. * Returns:
  1439. * retcode The usual LAS return codes.
  1440. *
  1441. * Error Handling:
  1442. * None.
  1443. *
  1444. **************************************************************************/
  1445. int
  1446. DS_LASAuthMethodEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  1447. char *attr_pattern, int *cachable, void **LAS_cookie,
  1448. PList_t subject, PList_t resource, PList_t auth_info,
  1449. PList_t global_auth)
  1450. {
  1451. char *attr;
  1452. char *ptr;
  1453. int len;
  1454. int matched;
  1455. int rc;
  1456. char *s = NULL;
  1457. lasInfo lasinfo;
  1458. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  1459. attr_pattern,cachable,LAS_cookie,
  1460. subject, resource, auth_info,global_auth,
  1461. DS_LAS_AUTHMETHOD, "DS_LASAuthMethodEval",
  1462. &lasinfo )) ) {
  1463. return LAS_EVAL_FAIL;
  1464. }
  1465. attr = attr_pattern;
  1466. matched = ACL_FALSE;
  1467. /* ignore leading whitespace */
  1468. s = strstr (attr, SLAPD_AUTH_SASL);
  1469. if ( s) {
  1470. s +=4;
  1471. attr = s;
  1472. }
  1473. while(ldap_utf8isspace(attr)) LDAP_UTF8INC(attr);
  1474. len = strlen(attr);
  1475. ptr = attr+len-1;
  1476. while(ptr >= attr && ldap_utf8isspace(ptr)) {
  1477. *ptr = '\0';
  1478. LDAP_UTF8DEC(ptr);
  1479. }
  1480. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1481. "DS_LASAuthMethodEval:authtype:%s authmethod:%s\n",
  1482. lasinfo.authType, attr);
  1483. /* None method means, we don't care -- otherwise we care */
  1484. if ((strcasecmp(attr, "none") == 0) ||
  1485. (strcasecmp(attr, lasinfo.authType) == 0)) {
  1486. matched = ACL_TRUE;
  1487. }
  1488. if ( matched == ACL_TRUE || matched == ACL_FALSE) {
  1489. if (comparator == CMP_OP_EQ) {
  1490. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  1491. } else {
  1492. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  1493. }
  1494. } else {
  1495. rc = LAS_EVAL_FAIL;
  1496. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1497. "Returning UNDEFINED for authmethod evaluation.\n");
  1498. }
  1499. return rc;
  1500. }
  1501. /****************************************************************************
  1502. * Struct to evaluate and keep the current members being evaluated
  1503. *
  1504. * 0 1 2 3 4 5
  1505. * member: [a,b,c,d,e,f]
  1506. * c_idx may point to 2 i.e to "c" if "c" is being evaluated to
  1507. * see if any of "c" members is the clientDN.
  1508. * lu_idx points to the last used spot i.e 5.
  1509. * lu_idx++ is the next free spot.
  1510. *
  1511. * We allocate ACLLAS_MAX_GRP_MEMBER ptr first and then we add if it
  1512. * is required.
  1513. *
  1514. ***************************************************************************/
  1515. #define ACLLAS_MAX_GRP_MEMBER 50
  1516. struct member_info
  1517. {
  1518. char *member; /* member DN */
  1519. struct member_info *parent; /* parent of this member */
  1520. } member_info;
  1521. struct eval_info
  1522. {
  1523. int result; /* result status */
  1524. char *userDN; /* client's normalized DN */
  1525. int c_idx; /* Index to the current member being processed */
  1526. int lu_idx; /* Index to the slot where the last member is stored */
  1527. char **member; /* mmebers list */
  1528. struct member_info **memberInfo;/* array of memberInfo */
  1529. CERTCertificate *clientCert; /* ptr to cert */
  1530. struct acl_pblock *aclpb; /*aclpblock */
  1531. } eval_info;
  1532. static void
  1533. dump_member_info ( struct member_info *minfo, char *buf )
  1534. {
  1535. if ( minfo )
  1536. {
  1537. if ( minfo->parent )
  1538. {
  1539. dump_member_info ( minfo->parent, buf );
  1540. }
  1541. else
  1542. {
  1543. strcat ( buf, "<nil>" );
  1544. }
  1545. strcat ( buf, "->" );
  1546. strcat ( buf, minfo->member );
  1547. }
  1548. }
  1549. #ifdef FOR_DEBUGGING
  1550. static void
  1551. dump_eval_info (char *caller, struct eval_info *info, int idx)
  1552. {
  1553. char buf[1024];
  1554. int len;
  1555. int i;
  1556. if ( idx < 0 )
  1557. {
  1558. sprintf ( buf, "\nuserDN=\"%s\"\nmember=", info->userDN);
  1559. if (info->member && *info->member)
  1560. {
  1561. len = strlen (buf);
  1562. /* member is a char ** */
  1563. sprintf ( &(buf[len]), "\"%s\"", *info->member );
  1564. }
  1565. len = strlen (buf);
  1566. sprintf ( &(buf[len]), "\nmemberinfo[%d]-[%d]:", info->c_idx, info->lu_idx );
  1567. if ( info->memberInfo )
  1568. for (i = 0; i <= info->lu_idx; i++)
  1569. {
  1570. len = strlen(buf);
  1571. sprintf ( &buf[len], "\n [%d]: ", i );
  1572. dump_member_info ( info->memberInfo[i], buf );
  1573. }
  1574. slapi_log_error ( SLAPI_LOG_FATAL, NULL, "\n======== candidate member info in eval_info ========%s\n\n", buf );
  1575. }
  1576. else
  1577. {
  1578. sprintf (buf, "evaluated candidate [%d]=", idx);
  1579. switch (info->result)
  1580. {
  1581. case ACL_TRUE:
  1582. strcat (buf, "ACL_TRUE\n");
  1583. break;
  1584. case ACL_FALSE:
  1585. strcat (buf, "ACL_FALSE\n");
  1586. break;
  1587. case ACL_DONT_KNOW:
  1588. strcat (buf, "ACL_DONT_KNOW\n");
  1589. break;
  1590. default:
  1591. len = strlen (buf);
  1592. sprintf ( &(buf[len]), "%d\n", info->result );
  1593. break;
  1594. }
  1595. dump_member_info ( info->memberInfo[idx], buf );
  1596. slapi_log_error ( SLAPI_LOG_FATAL, NULL, "%s\n", buf );
  1597. }
  1598. }
  1599. #endif
  1600. /***************************************************************************
  1601. *
  1602. * acllas__user_ismember_of_group
  1603. *
  1604. * Check if the user is a member of the group and nested groups..
  1605. *
  1606. * Input:
  1607. * char *groupdn - DN of the group
  1608. * char *clientDN - Dn of the client
  1609. *
  1610. * Returns:
  1611. * ACL_TRUE - the user is a member of the group.
  1612. * ACL_FALSE - Not a member
  1613. * ACL_DONT_KNOW - Any errors eg. resource limits exceeded and we could
  1614. * not compelte the evaluation.
  1615. *
  1616. * Error Handling:
  1617. * None.
  1618. *
  1619. **************************************************************************/
  1620. static int
  1621. acllas__user_ismember_of_group( struct acl_pblock *aclpb,
  1622. char* groupDN,
  1623. char* clientDN,
  1624. int cache_status,
  1625. CERTCertificate *clientCert)
  1626. {
  1627. char *attrs[5];
  1628. char *currDN;
  1629. int i,j;
  1630. int result = ACL_FALSE;
  1631. struct eval_info info;
  1632. int nesting_level;
  1633. int numOfMembersAtCurrentLevel;
  1634. int numOfMembersVisited;
  1635. int totalMembersVisited;
  1636. int numOfMembers;
  1637. int max_nestlevel;
  1638. int max_memberlimit;
  1639. aclUserGroup *u_group;
  1640. struct member_info *groupMember = NULL;
  1641. struct member_info *parentGroup = NULL;
  1642. /*
  1643. ** First, Let's look thru the cached list and determine if the client is
  1644. ** a member of the cached list of groups.
  1645. */
  1646. if ( (u_group = aclg_get_usersGroup ( aclpb , clientDN )) == NULL) {
  1647. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1648. "Failed to find/allocate a usergroup--aborting evaluation\n");
  1649. return(ACL_DONT_KNOW);
  1650. }
  1651. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluating user %s in group %s?\n",
  1652. clientDN, groupDN );
  1653. /* Before I start using, get a reader lock on the group cache */
  1654. aclg_lock_groupCache ( 1 /* reader */ );
  1655. for ( i= 0; i < u_group->aclug_numof_member_group; i++) {
  1656. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "-- In %s\n",
  1657. u_group->aclug_member_groups[i] );
  1658. if ( slapi_utf8casecmp((ACLUCHP)groupDN, (ACLUCHP)u_group->aclug_member_groups[i]) == 0){
  1659. aclg_unlock_groupCache ( 1 /* reader */ );
  1660. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_TRUE\n");
  1661. return ACL_TRUE;
  1662. }
  1663. }
  1664. /* see if we know the client is not a member of a group. */
  1665. for ( i= 0; i < u_group->aclug_numof_notmember_group; i++) {
  1666. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "-- Not in %s\n",
  1667. u_group->aclug_notmember_groups[i] );
  1668. if ( slapi_utf8casecmp((ACLUCHP)groupDN, (ACLUCHP)u_group->aclug_notmember_groups[i]) == 0){
  1669. aclg_unlock_groupCache ( 1 /* reader */ );
  1670. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_FALSE\n");
  1671. return ACL_FALSE;
  1672. }
  1673. }
  1674. /*
  1675. ** That means we didn't find the the group in the cache. -- we have to add it
  1676. ** so no need for READ lock - need to get a WRITE lock. We will get it just before
  1677. ** modifying it.
  1678. */
  1679. aclg_unlock_groupCache ( 1 /* reader */ );
  1680. /* Indicate the initialization handler -- this module will be
  1681. ** called by the backend to evaluate the entry.
  1682. */
  1683. info.result = ACL_FALSE;
  1684. if (clientDN && *clientDN != '\0')
  1685. info.userDN = clientDN;
  1686. else
  1687. info.userDN = NULL;
  1688. info.c_idx = 0;
  1689. info.memberInfo = (struct member_info **) slapi_ch_malloc (ACLLAS_MAX_GRP_MEMBER * sizeof(struct member_info *));
  1690. groupMember = (struct member_info *) slapi_ch_malloc ( sizeof (struct member_info) );
  1691. groupMember->member = slapi_ch_strdup(groupDN);
  1692. groupMember->parent = NULL;
  1693. info.memberInfo[0] = groupMember;
  1694. info.lu_idx = 0;
  1695. attrs[0] = type_member;
  1696. attrs[1] = type_uniquemember;
  1697. attrs[2] = type_memberURL;
  1698. attrs[3] = type_memberCert;
  1699. attrs[4] = NULL;
  1700. currDN = groupMember->member;
  1701. /* nesting level is 0 to begin with */
  1702. nesting_level = 0;
  1703. numOfMembersVisited = 0;
  1704. totalMembersVisited = 0;
  1705. numOfMembersAtCurrentLevel = 1;
  1706. if (clientCert)
  1707. info.clientCert = clientCert;
  1708. else
  1709. info.clientCert = NULL;
  1710. info.aclpb = aclpb;
  1711. max_memberlimit = aclpb->aclpb_max_member_sizelimit;
  1712. max_nestlevel = aclpb->aclpb_max_nesting_level;
  1713. #ifdef FOR_DEBUGGING
  1714. dump_eval_info ( "acllas__user_ismember_of_group", &info, -1 );
  1715. #endif
  1716. eval_another_member:
  1717. numOfMembers = info.lu_idx - info.c_idx;
  1718. /* Use new search internal API */
  1719. {
  1720. Slapi_PBlock * aPb = slapi_pblock_new ();
  1721. /*
  1722. * This search may NOT be chained--we demand that group
  1723. * definition be local.
  1724. */
  1725. slapi_search_internal_set_pb ( aPb,
  1726. currDN,
  1727. LDAP_SCOPE_BASE,
  1728. filter_groups,
  1729. &attrs[0],
  1730. 0,
  1731. NULL /* controls */,
  1732. NULL /* uniqueid */,
  1733. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  1734. SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
  1735. slapi_search_internal_callback_pb(aPb,
  1736. &info /* callback_data */,
  1737. NULL/* result_callback */,
  1738. acllas__handle_group_entry,
  1739. NULL /* referral_callback */);
  1740. if ( info.result == ACL_TRUE )
  1741. slapi_log_error( SLAPI_LOG_ACL, plugin_name,"-- In %s\n", info.memberInfo[info.c_idx]->member );
  1742. else if ( info.result == ACL_FALSE )
  1743. slapi_log_error( SLAPI_LOG_ACL, plugin_name,"-- Not in %s\n", info.memberInfo[info.c_idx]->member );
  1744. slapi_pblock_destroy (aPb);
  1745. }
  1746. if (info.result == ACL_TRUE) {
  1747. /*
  1748. ** that means the client is a member of the
  1749. ** group or one of the nested groups. We are done.
  1750. */
  1751. result = ACL_TRUE;
  1752. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_TRUE\n");
  1753. goto free_and_return;
  1754. }
  1755. numOfMembersVisited++;
  1756. if (numOfMembersVisited == numOfMembersAtCurrentLevel) {
  1757. /* This means we have looked at all the members for this level */
  1758. numOfMembersVisited = 0;
  1759. /* Now we are ready to look at the next level */
  1760. nesting_level++;
  1761. /* So, far we have visited ... */
  1762. totalMembersVisited += numOfMembersAtCurrentLevel;
  1763. /* How many members in the next level ? */
  1764. numOfMembersAtCurrentLevel =
  1765. info.lu_idx - totalMembersVisited +1;
  1766. }
  1767. if ((nesting_level > max_nestlevel)) {
  1768. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1769. "GroupEval:Member not found within the allowed nesting level (Allowed:%d Looked at:%d)\n",
  1770. max_nestlevel, nesting_level);
  1771. result = ACL_DONT_KNOW; /* don't try to cache info based on this result */
  1772. goto free_and_return;
  1773. }
  1774. /* limit of -1 means "no limit */
  1775. if (info.c_idx > max_memberlimit &&
  1776. max_memberlimit != -1 ) {
  1777. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  1778. "GroupEval:Looked at too many entries:(%d, %d)\n",
  1779. info.c_idx, info.lu_idx);
  1780. result = ACL_DONT_KNOW; /* don't try to cache info based on this result */
  1781. goto free_and_return;
  1782. }
  1783. if (info.lu_idx > info.c_idx) {
  1784. if (numOfMembers == (info.lu_idx - info.c_idx)) {
  1785. /* That means it's not a GROUP. It is just another
  1786. ** useless member which doesn't match. Remove the BAD dude.
  1787. */
  1788. groupMember = info.memberInfo[info.c_idx];
  1789. if (groupMember ) {
  1790. if ( groupMember->member ) slapi_ch_free ( (void **) &groupMember->member );
  1791. slapi_ch_free ( (void **) &groupMember );
  1792. info.memberInfo[info.c_idx] = NULL;
  1793. }
  1794. }
  1795. info.c_idx++;
  1796. /* Go thru the stack and see if we have already
  1797. ** evaluated this group. If we have, then skip it.
  1798. */
  1799. while (1) {
  1800. int evalNext=0;
  1801. int j;
  1802. if (info.c_idx > info.lu_idx) {
  1803. /* That means we have crossed the limit. We
  1804. ** may end of in this situation if we
  1805. ** have circular groups
  1806. */
  1807. info.c_idx = info.lu_idx;
  1808. goto free_and_return;
  1809. }
  1810. /* Break out of the loop if we have searched to the end */
  1811. groupMember = info.memberInfo[info.c_idx];
  1812. if ( (NULL == groupMember) || ((currDN = groupMember->member)!= NULL))
  1813. break;
  1814. for (j = 0; j < info.c_idx; j++) {
  1815. groupMember = info.memberInfo[j];
  1816. if (groupMember->member &&
  1817. (slapi_utf8casecmp((ACLUCHP)currDN, (ACLUCHP)groupMember->member) == 0)) {
  1818. /* Don't need the duplicate */
  1819. groupMember = info.memberInfo[info.c_idx];
  1820. slapi_ch_free ( (void **) &groupMember->member );
  1821. slapi_ch_free ( (void **) &groupMember );
  1822. info.memberInfo[info.c_idx] = NULL;
  1823. info.c_idx++;
  1824. evalNext=1;
  1825. break;
  1826. }
  1827. }
  1828. if (!evalNext) break;
  1829. }
  1830. /* Make sure that we have a valid DN to chug along */
  1831. groupMember = info.memberInfo[info.c_idx];
  1832. if ((info.c_idx <= info.lu_idx) && ((currDN = groupMember->member) != NULL))
  1833. goto eval_another_member;
  1834. }
  1835. free_and_return:
  1836. /* Remove the unnecessary members from the list which
  1837. ** we might have accumulated during the last execution
  1838. ** and we don't need to look at them.
  1839. */
  1840. i = info.c_idx;
  1841. i++;
  1842. while (i <= info.lu_idx) {
  1843. groupMember = info.memberInfo[i];
  1844. slapi_ch_free ( (void **) &groupMember->member );
  1845. slapi_ch_free ( (void **) &groupMember );
  1846. info.memberInfo[i] = NULL;
  1847. i++;
  1848. }
  1849. /*
  1850. ** Now we have a list which has all the groups
  1851. ** which we need to cache
  1852. */
  1853. info.lu_idx = info.c_idx;
  1854. /* since we are updating the groupcache, get a write lock */
  1855. aclg_lock_groupCache ( 2 /* writer */ );
  1856. /*
  1857. ** Keep the result of the evaluation in the cache.
  1858. ** We have 2 lists: member_of and not_member_of. We can use this
  1859. ** cached information next time we evaluate groups.
  1860. */
  1861. if (result == ACL_TRUE &&
  1862. (cache_status & ACLLAS_CACHE_MEMBER_GROUPS)) {
  1863. int ngr = 0;
  1864. /* get the last group which the user is a member of */
  1865. groupMember = info.memberInfo[info.c_idx];
  1866. while ( groupMember ) {
  1867. int already_cached = 0;
  1868. parentGroup = groupMember->parent;
  1869. for (j=0; j < u_group->aclug_numof_member_group;j++){
  1870. if (slapi_utf8casecmp( (ACLUCHP)groupMember->member,
  1871. (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
  1872. already_cached = 1;
  1873. break;
  1874. }
  1875. }
  1876. if (already_cached) {
  1877. groupMember = parentGroup;
  1878. parentGroup = NULL;
  1879. continue;
  1880. }
  1881. ngr = u_group->aclug_numof_member_group++;
  1882. if (u_group->aclug_numof_member_group >=
  1883. u_group->aclug_member_group_size){
  1884. u_group->aclug_member_groups =
  1885. (char **) slapi_ch_realloc (
  1886. (void *) u_group->aclug_member_groups,
  1887. (u_group->aclug_member_group_size +
  1888. ACLUG_INCR_GROUPS_LIST) *
  1889. sizeof (char *));
  1890. u_group->aclug_member_group_size +=
  1891. ACLUG_INCR_GROUPS_LIST;
  1892. }
  1893. u_group->aclug_member_groups[ngr] = slapi_ch_strdup ( groupMember->member );
  1894. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  1895. "Adding Group (%s) ParentGroup (%s) to the IN GROUP List\n",
  1896. groupMember->member , parentGroup ? parentGroup->member: "NULL");
  1897. groupMember = parentGroup;
  1898. parentGroup = NULL;
  1899. }
  1900. } else if (result == ACL_FALSE &&
  1901. (cache_status & ACLLAS_CACHE_NOT_MEMBER_GROUPS)) {
  1902. int ngr = 0;
  1903. /* NOT IN THE GROUP LIST */
  1904. /* get the last group which the user is a member of */
  1905. groupMember = info.memberInfo[info.c_idx];
  1906. while ( groupMember ) {
  1907. int already_cached = 0;
  1908. parentGroup = groupMember->parent;
  1909. for (j=0; j < u_group->aclug_numof_notmember_group;j++){
  1910. if (slapi_utf8casecmp( (ACLUCHP)groupMember->member,
  1911. (ACLUCHP)u_group->aclug_notmember_groups[j]) == 0) {
  1912. already_cached = 1;
  1913. break;
  1914. }
  1915. }
  1916. if (already_cached) {
  1917. groupMember = parentGroup;
  1918. parentGroup = NULL;
  1919. continue;
  1920. }
  1921. ngr = u_group->aclug_numof_notmember_group++;
  1922. if (u_group->aclug_numof_notmember_group >=
  1923. u_group->aclug_notmember_group_size){
  1924. u_group->aclug_notmember_groups =
  1925. (char **) slapi_ch_realloc (
  1926. (void *) u_group->aclug_notmember_groups,
  1927. (u_group->aclug_notmember_group_size +
  1928. ACLUG_INCR_GROUPS_LIST) *
  1929. sizeof (char *));
  1930. u_group->aclug_notmember_group_size +=
  1931. ACLUG_INCR_GROUPS_LIST;
  1932. }
  1933. u_group->aclug_notmember_groups[ngr] = slapi_ch_strdup ( groupMember->member );
  1934. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  1935. "Adding Group (%s) ParentGroup (%s) to the NOT IN GROUP List\n",
  1936. groupMember->member , parentGroup ? parentGroup->member: "NULL");
  1937. groupMember = parentGroup;
  1938. parentGroup = NULL;
  1939. }
  1940. } else if ( result == ACL_DONT_KNOW ) {
  1941. /*
  1942. * We terminated the search without reaching a conclusion--so
  1943. * don't cache any info based on this evaluation.
  1944. */
  1945. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_DONT_KNOW\n");
  1946. }
  1947. /* Unlock the group cache, we are done with updating */
  1948. aclg_unlock_groupCache ( 2 /* writer */ );
  1949. for (i=0; i <= info.lu_idx; i++) {
  1950. groupMember = info.memberInfo[i];
  1951. if ( NULL == groupMember ) continue;
  1952. slapi_ch_free ( (void **) &groupMember->member );
  1953. slapi_ch_free ( (void **) &groupMember );
  1954. }
  1955. /* free the pointer array.*/
  1956. slapi_ch_free ( (void **) &info.memberInfo);
  1957. return result;
  1958. }
  1959. /***************************************************************************
  1960. *
  1961. * acllas__handle_group_entry
  1962. *
  1963. * handler called. Compares the userdn value and determines if it's
  1964. * a member of not.
  1965. *
  1966. * Input:
  1967. *
  1968. *
  1969. * Returns:
  1970. *
  1971. * Error Handling:
  1972. *
  1973. **************************************************************************/
  1974. static int
  1975. acllas__handle_group_entry (Slapi_Entry* e, void *callback_data)
  1976. {
  1977. struct eval_info *info;
  1978. Slapi_Attr *currAttr, *nextAttr;
  1979. char *n_dn, *attrType;
  1980. short n;
  1981. int i;
  1982. info = (struct eval_info *) callback_data;
  1983. info->result = ACL_FALSE;
  1984. if (e == NULL) {
  1985. return 0;
  1986. }
  1987. slapi_entry_first_attr ( e, &currAttr);
  1988. if ( NULL == currAttr ) return 0;
  1989. slapi_attr_get_type ( currAttr, &attrType );
  1990. if (NULL == attrType ) return 0;
  1991. do {
  1992. Slapi_Value *sval=NULL;
  1993. const struct berval *attrVal;
  1994. if ((strcasecmp (attrType, type_member) == 0) ||
  1995. (strcasecmp (attrType, type_uniquemember) == 0 )) {
  1996. i = slapi_attr_first_value ( currAttr,&sval );
  1997. while ( i != -1 ) {
  1998. struct member_info *groupMember = NULL;
  1999. attrVal = slapi_value_get_berval ( sval );
  2000. n_dn = slapi_dn_normalize ( slapi_ch_strdup( attrVal->bv_val));
  2001. info->lu_idx++;
  2002. n = info->lu_idx;
  2003. if (!(n % ACLLAS_MAX_GRP_MEMBER)) {
  2004. info->memberInfo = (struct member_info **) slapi_ch_realloc(
  2005. (void *) info->memberInfo,
  2006. (n+ACLLAS_MAX_GRP_MEMBER) *
  2007. sizeof(struct eval_info *));
  2008. }
  2009. /* allocate the space for the member and attch it to the list */
  2010. groupMember = (struct member_info *) slapi_ch_malloc ( sizeof ( struct member_info ) );
  2011. groupMember->member = n_dn;
  2012. groupMember->parent = info->memberInfo[info->c_idx];
  2013. info->memberInfo[n] = groupMember;
  2014. if (info->userDN &&
  2015. slapi_utf8casecmp((ACLUCHP)n_dn, (ACLUCHP)info->userDN) == 0) {
  2016. info->result = ACL_TRUE;
  2017. return 0;
  2018. }
  2019. i = slapi_attr_next_value ( currAttr, i, &sval );
  2020. }
  2021. /* Evaluate Dynamic groups */
  2022. } else if (strcasecmp ( attrType, type_memberURL) == 0) {
  2023. char *memberURL, *savURL;
  2024. if (!info->userDN) continue;
  2025. i= slapi_attr_first_value ( currAttr,&sval );
  2026. while ( i != -1 ) {
  2027. attrVal = slapi_value_get_berval ( sval );
  2028. /*
  2029. * memberURL may start with "ldap:///" or "ldap://host:port"
  2030. * ldap://localhost:11000/o=ace industry,c=us??
  2031. * or
  2032. * ldap:///o=ace industry,c=us??
  2033. */
  2034. if (strncasecmp( attrVal->bv_val, "ldap://",7) == 0 ||
  2035. strncasecmp( attrVal->bv_val, "ldaps://",8) == 0) {
  2036. savURL = memberURL = slapi_ch_strdup ( attrVal->bv_val);
  2037. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2038. "ACL Group Eval:MemberURL:%s\n", memberURL);
  2039. info->result = acllas__client_match_URL (
  2040. info->aclpb,
  2041. info->userDN,
  2042. memberURL);
  2043. slapi_ch_free ( (void**) &savURL);
  2044. if (info->result == ACL_TRUE)
  2045. return 0;
  2046. } else {
  2047. /* This means that the URL is ill-formed */
  2048. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2049. "ACL Group Eval:Badly Formed MemberURL:%s\n", attrVal->bv_val);
  2050. }
  2051. i = slapi_attr_next_value ( currAttr, i, &sval );
  2052. }
  2053. /* Evaluate Fortezza groups */
  2054. } else if ((strcasecmp (attrType, type_memberCert) == 0) ) {
  2055. /* Do we have the certificate around */
  2056. if (!info->clientCert) {
  2057. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2058. " acllas__handle_group_entry:Client Cert missing\n" );
  2059. continue;
  2060. }
  2061. i = slapi_attr_first_value ( currAttr,&sval );
  2062. while ( i != -1 ) {
  2063. attrVal = slapi_value_get_berval ( sval );
  2064. if (ldapu_member_certificate_match (
  2065. info->clientCert,
  2066. attrVal->bv_val) == LDAP_SUCCESS) {
  2067. info->result = ACL_TRUE;
  2068. return 0;
  2069. }
  2070. i = slapi_attr_next_value ( currAttr, i, &sval );
  2071. }
  2072. }
  2073. attrType = NULL;
  2074. /* get the next attr */
  2075. slapi_entry_next_attr ( e, currAttr, &nextAttr );
  2076. if ( NULL == nextAttr ) break;
  2077. currAttr = nextAttr;
  2078. slapi_attr_get_type ( currAttr, &attrType );
  2079. } while ( NULL != attrType );
  2080. return 0;
  2081. }
  2082. /***************************************************************************
  2083. *
  2084. * DS_LASGroupDnAttrEval
  2085. *
  2086. *
  2087. * Input:
  2088. * attr_name The string "groupdnattr" - in lower case.
  2089. * comparator CMP_OP_EQ or CMP_OP_NE only
  2090. * attr_pattern A comma-separated list of users
  2091. * cachable Always set to FALSE.
  2092. * subject Subject property list
  2093. * resource Resource property list
  2094. * auth_info Authentication info, if any
  2095. *
  2096. * Returns:
  2097. * retcode The usual LAS return codes.
  2098. *
  2099. * Error Handling:
  2100. * None.
  2101. *
  2102. **************************************************************************/
  2103. struct groupdnattr_info
  2104. {
  2105. char *attrName; /* name of the attribute */
  2106. int numofGroups; /* number of groups */
  2107. char **member;
  2108. };
  2109. int
  2110. DS_LASGroupDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  2111. char *attr_pattern, int *cachable, void **LAS_cookie,
  2112. PList_t subject, PList_t resource, PList_t auth_info,
  2113. PList_t global_auth)
  2114. {
  2115. char *s_attrName = NULL;
  2116. char *attrName;
  2117. char *ptr;
  2118. int matched;
  2119. int rc;
  2120. int len;
  2121. Slapi_Attr *attr;
  2122. int levels[ACLLAS_MAX_LEVELS];
  2123. int numOflevels = 0;
  2124. char *n_currEntryDn = NULL;
  2125. lasInfo lasinfo;
  2126. int got_undefined = 0;
  2127. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  2128. attr_pattern,cachable,LAS_cookie,
  2129. subject, resource, auth_info,global_auth,
  2130. DS_LAS_GROUPDNATTR, "DS_LASGroupDnAttrEval",
  2131. &lasinfo )) ) {
  2132. return LAS_EVAL_FAIL;
  2133. }
  2134. /* For anonymous client, the answer is XXX come back to this */
  2135. if ( lasinfo.anomUser )
  2136. return LAS_EVAL_FALSE;
  2137. /*
  2138. ** The groupdnAttr syntax is
  2139. ** groupdnattr = <attribute>
  2140. ** Ex:
  2141. ** groupdnattr = SIEmanager;
  2142. **
  2143. ** The function of this LAS is to find out if the client belongs
  2144. ** to any group that is specified in the attr.
  2145. */
  2146. attrName = attr_pattern;
  2147. if (strstr(attrName, LDAP_URL_prefix)) {
  2148. /* In this case "grppupdnattr="ldap:///base??attr" */
  2149. if ((strstr (attrName, ACL_RULE_MACRO_DN_KEY) != NULL) ||
  2150. (strstr (attrName, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) ||
  2151. (strstr (attrName, ACL_RULE_MACRO_ATTR_KEY) != NULL)) {
  2152. matched = aclutil_evaluate_macro( attrName, &lasinfo,
  2153. ACL_EVAL_GROUPDNATTR);
  2154. } else{
  2155. matched = acllas__eval_memberGroupDnAttr(attrName,
  2156. lasinfo.resourceEntry,
  2157. lasinfo.clientDn,
  2158. lasinfo.aclpb);
  2159. }
  2160. if ( matched == ACL_DONT_KNOW) {
  2161. got_undefined = 1;
  2162. }
  2163. } else {
  2164. int i;
  2165. char *n_groupdn;
  2166. /* ignore leading/trailing whitespace */
  2167. while(ldap_utf8isspace(attrName)) LDAP_UTF8INC(attrName);
  2168. len = strlen(attrName);
  2169. ptr = attrName+len-1;
  2170. while(ptr >= attrName && ldap_utf8isspace(ptr)) {
  2171. *ptr = '\0';
  2172. LDAP_UTF8DEC(ptr);
  2173. }
  2174. slapi_log_error( SLAPI_LOG_ACL, plugin_name,"Attr:%s\n" , attrName);
  2175. /* See if we have a parent[2].attr" rule */
  2176. if ( (ptr = strstr(attrName, "parent[")) != NULL) {
  2177. char *word, *str, *next;
  2178. numOflevels = 0;
  2179. n_currEntryDn = slapi_entry_get_ndn ( lasinfo.resourceEntry ) ;
  2180. s_attrName = attrName = slapi_ch_strdup ( attr_pattern );
  2181. str = attrName;
  2182. word = ldap_utf8strtok_r(str, "[],. ",&next);
  2183. /* The first word is "parent[" and so it's not important */
  2184. while ((word= ldap_utf8strtok_r(NULL, "[],.", &next)) != NULL) {
  2185. if (ldap_utf8isdigit(word)) {
  2186. while (word && ldap_utf8isspace(word)) LDAP_UTF8INC(word);
  2187. if (numOflevels < ACLLAS_MAX_LEVELS)
  2188. levels[numOflevels++] = atoi (word);
  2189. else {
  2190. /*
  2191. * Here, ignore the extra levels..it's really
  2192. * a syntax error which should have been ruled out at parse time
  2193. */
  2194. slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
  2195. "DS_LASGroupDnattr: Exceeded the ATTR LIMIT:%d: Ignoring extra levels\n",
  2196. ACLLAS_MAX_LEVELS);
  2197. }
  2198. } else {
  2199. /* Must be the attr name. We can goof of by
  2200. ** having parent[1,2,a] but then you have to be
  2201. ** stupid to do that.
  2202. */
  2203. char *p = word;
  2204. if (*--p == '.') {
  2205. attrName = word;
  2206. break;
  2207. }
  2208. }
  2209. }
  2210. } else {
  2211. levels[0] = 0;
  2212. numOflevels = 1;
  2213. }
  2214. matched = ACL_FALSE;
  2215. for (i=0; i < numOflevels; i++) {
  2216. if ( levels[i] == 0 ) {
  2217. Slapi_Value *sval=NULL;
  2218. const struct berval *attrVal;
  2219. int attr_i;
  2220. /*
  2221. * For the add operation, the resource itself (level 0)
  2222. * must never be allowed to grant access--
  2223. * This is because access would be granted based on a value
  2224. * of an attribute in the new entry--security hole.
  2225. * XXX is this therefore FALSE or DONT_KNOW ?
  2226. */
  2227. if ( lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
  2228. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2229. "ACL info: groupdnAttr does not allow ADD permission at level 0.\n");
  2230. got_undefined = 1;
  2231. continue;
  2232. }
  2233. slapi_entry_attr_find ( lasinfo.resourceEntry, attrName, &attr);
  2234. if ( !attr) continue;
  2235. attr_i= slapi_attr_first_value ( attr,&sval );
  2236. while ( attr_i != -1 ) {
  2237. attrVal = slapi_value_get_berval ( sval );
  2238. n_groupdn = slapi_dn_normalize(
  2239. slapi_ch_strdup( attrVal->bv_val));
  2240. matched = acllas__user_ismember_of_group (
  2241. lasinfo.aclpb, n_groupdn, lasinfo.clientDn,
  2242. ACLLAS_CACHE_MEMBER_GROUPS,
  2243. lasinfo.aclpb->aclpb_clientcert);
  2244. slapi_ch_free ( (void **) &n_groupdn);
  2245. if (matched == ACL_TRUE ) {
  2246. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2247. "groupdnattr matches at level (%d)\n", levels[i]);
  2248. break;
  2249. } else if ( matched == ACL_DONT_KNOW ) {
  2250. /* record this but keep going--maybe another group will evaluate to TRUE */
  2251. got_undefined = 1;
  2252. }
  2253. attr_i= slapi_attr_next_value ( attr, attr_i, &sval );
  2254. }
  2255. } else {
  2256. char *p_dn;
  2257. struct groupdnattr_info info;
  2258. char *attrs[2];
  2259. int j;
  2260. info.numofGroups = 0;
  2261. attrs[0] = info.attrName = attrName;
  2262. attrs[1] = NULL;
  2263. p_dn = acllas__dn_parent (n_currEntryDn, levels[i]);
  2264. if (p_dn == NULL) continue;
  2265. /* Use new search internal API */
  2266. {
  2267. Slapi_PBlock *aPb = slapi_pblock_new ();
  2268. /*
  2269. * This search may NOT be chained--if the user's definition is
  2270. * remote and the group is dynamic and the user entry
  2271. * changes then we would not notice--so don't go
  2272. * find the user entry in the first place.
  2273. */
  2274. slapi_search_internal_set_pb ( aPb,
  2275. p_dn,
  2276. LDAP_SCOPE_BASE,
  2277. "objectclass=*",
  2278. &attrs[0],
  2279. 0,
  2280. NULL /* controls */,
  2281. NULL /* uniqueid */,
  2282. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  2283. SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
  2284. slapi_search_internal_callback_pb(aPb,
  2285. &info /* callback_data */,
  2286. NULL/* result_callback */,
  2287. acllas__get_members,
  2288. NULL /* referral_callback */);
  2289. slapi_pblock_destroy (aPb);
  2290. }
  2291. if (info.numofGroups <= 0) {
  2292. continue;
  2293. }
  2294. for (j=0; j <info.numofGroups; j++) {
  2295. if (slapi_utf8casecmp((ACLUCHP)info.member[j],
  2296. (ACLUCHP)lasinfo.clientDn) == 0) {
  2297. matched = ACL_TRUE;
  2298. break;
  2299. }
  2300. matched = acllas__user_ismember_of_group (
  2301. lasinfo.aclpb, info.member[j],
  2302. lasinfo.clientDn, ACLLAS_CACHE_ALL_GROUPS,
  2303. lasinfo.aclpb->aclpb_clientcert);
  2304. if (matched == ACL_TRUE) {
  2305. break;
  2306. } else if ( matched == ACL_DONT_KNOW ) {
  2307. /* record this but keep going--maybe another group will evaluate to TRUE */
  2308. got_undefined = 1;
  2309. }
  2310. }
  2311. /* Deallocate the member array and the member struct */
  2312. for (j=0; j < info.numofGroups; j++)
  2313. slapi_ch_free ((void **) &info.member[j]);
  2314. slapi_ch_free ((void **) &info.member);
  2315. }
  2316. if (matched == ACL_TRUE) {
  2317. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2318. "groupdnattr matches at level (%d)\n", levels[i]);
  2319. break;
  2320. } else if ( matched == ACL_DONT_KNOW ) {
  2321. /* record this but keep going--maybe another group at another level
  2322. * will evaluate to TRUE.
  2323. */
  2324. got_undefined = 1;
  2325. }
  2326. } /* NumofLevels */
  2327. }
  2328. if (s_attrName) slapi_ch_free ((void**) &s_attrName );
  2329. /*
  2330. * If no terms were undefined, then evaluate as normal.
  2331. * If there was an undefined term, but another one was TRUE, then we also evaluate
  2332. * as normal. Otherwise, the whole expression is UNDEFINED.
  2333. */
  2334. if ( matched == ACL_TRUE || !got_undefined ) {
  2335. if (comparator == CMP_OP_EQ) {
  2336. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  2337. } else {
  2338. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  2339. }
  2340. } else {
  2341. rc = LAS_EVAL_FAIL;
  2342. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2343. "Returning UNDEFINED for groupdnattr evaluation.\n");
  2344. }
  2345. return rc;
  2346. }
  2347. /*
  2348. * acllas__eval_memberGroupDnAttr
  2349. *
  2350. * return ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW
  2351. *
  2352. * Inverse group evaluation. Find all the groups that the user is a
  2353. * member of. Find all teh groups that contain those groups. Do an
  2354. * upward nested level search. By the end of it, we will know all the
  2355. * groups that the clinet is a member of under that search scope.
  2356. *
  2357. * This model seems to be very fast if we have few groups at the
  2358. * leaf level.
  2359. *
  2360. */
  2361. static int
  2362. acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e,
  2363. char *n_clientdn, struct acl_pblock *aclpb)
  2364. {
  2365. Slapi_Attr *attr;
  2366. char *s, *p;
  2367. char *str, *s_str, *base, *groupattr = NULL;
  2368. int i,j,k,matched, enumerate_groups;
  2369. aclUserGroup *u_group;
  2370. char ebuf [ BUFSIZ ];
  2371. Slapi_Value *sval=NULL;
  2372. const struct berval *attrVal;
  2373. /* Parse the URL -- getting the group attr and counting up '?'s.
  2374. * If there is no group attr and there are 3 '?' marks,
  2375. * we parse the URL with ldap_url_parse to get base dn and filter.
  2376. */
  2377. s_str = str = slapi_ch_strdup(attrName);
  2378. while (str && ldap_utf8isspace(str)) LDAP_UTF8INC( str );
  2379. str +=8;
  2380. s = strchr (str, '?');
  2381. if (s) {
  2382. p = s;
  2383. p++;
  2384. *s = '\0';
  2385. base = str;
  2386. s = strchr (p, '?');
  2387. if (s) *s = '\0';
  2388. groupattr = p;
  2389. } else {
  2390. slapi_ch_free ( (void **)&s_str );
  2391. return ACL_FALSE;
  2392. }
  2393. if ( (u_group = aclg_get_usersGroup ( aclpb , n_clientdn )) == NULL) {
  2394. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2395. "Failed to find/allocate a usergroup--aborting evaluation\n");
  2396. slapi_ch_free ( (void **)&s_str );
  2397. return(ACL_DONT_KNOW);
  2398. }
  2399. /*
  2400. ** First find out if we have already searched this base or
  2401. ** if we are searching a subtree to an already enumerated base.
  2402. */
  2403. enumerate_groups = 1;
  2404. for (j=0; j < aclpb->aclpb_numof_bases; j++) {
  2405. if (slapi_dn_issuffix(aclpb->aclpb_grpsearchbase[j], base)) {
  2406. enumerate_groups = 0;
  2407. break;
  2408. }
  2409. }
  2410. /* See if we have already enumerated all the groups which the
  2411. ** client is a member of.
  2412. */
  2413. if (enumerate_groups) {
  2414. char filter_str[BUFSIZ];
  2415. char *attrs[3];
  2416. struct eval_info info;
  2417. char *curMemberDn;
  2418. int Done = 0;
  2419. int ngr, tt;
  2420. /* Add the scope to the list of scopes */
  2421. if (aclpb->aclpb_numof_bases >= (aclpb->aclpb_grpsearchbase_size-1)) {
  2422. aclpb->aclpb_grpsearchbase = (char **)
  2423. slapi_ch_realloc (
  2424. (void *) aclpb->aclpb_grpsearchbase,
  2425. (aclpb->aclpb_grpsearchbase_size +
  2426. ACLPB_INCR_BASES) *
  2427. sizeof (char *));
  2428. aclpb->aclpb_grpsearchbase_size += ACLPB_INCR_BASES;
  2429. }
  2430. aclpb->aclpb_grpsearchbase[aclpb->aclpb_numof_bases++] =
  2431. slapi_dn_normalize(slapi_ch_strdup(base));
  2432. /* Set up info to do a search */
  2433. attrs[0] = type_member;
  2434. attrs[1] = type_uniquemember;
  2435. attrs[2] = NULL;
  2436. info.c_idx = info.lu_idx = 0;
  2437. info.member =
  2438. (char **) slapi_ch_malloc (ACLLAS_MAX_GRP_MEMBER * sizeof(char *));
  2439. curMemberDn = n_clientdn;
  2440. while (!Done) {
  2441. char *filter_str_ptr = &filter_str[0];
  2442. char *new_filter_str = NULL;
  2443. int lenf = strlen(curMemberDn)<<1;
  2444. if (lenf > (BUFSIZ - 28)) { /* 28 for "(|(uniquemember=%s)(member=%s))" */
  2445. new_filter_str = slapi_ch_malloc(lenf + 28);
  2446. filter_str_ptr = new_filter_str;
  2447. }
  2448. /*
  2449. ** Search the db for groups that the client is a member of.
  2450. ** Once found cache it. cache only unique groups.
  2451. */
  2452. tt = info.lu_idx;
  2453. sprintf (filter_str_ptr,"(|(uniquemember=%s)(member=%s))",
  2454. curMemberDn, curMemberDn);
  2455. /* Use new search internal API */
  2456. {
  2457. Slapi_PBlock *aPb = slapi_pblock_new ();
  2458. /*
  2459. * This search may NOT be chained--we demand that group
  2460. * definition be local.
  2461. */
  2462. slapi_search_internal_set_pb ( aPb,
  2463. base,
  2464. LDAP_SCOPE_SUBTREE,
  2465. filter_str_ptr,
  2466. &attrs[0],
  2467. 0,
  2468. NULL /* controls */,
  2469. NULL /* uniqueid */,
  2470. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  2471. SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
  2472. slapi_search_internal_callback_pb(aPb,
  2473. &info /* callback_data */,
  2474. NULL/* result_callback */,
  2475. acllas__add_allgroups,
  2476. NULL /* referral_callback */);
  2477. slapi_pblock_destroy (aPb);
  2478. }
  2479. if (new_filter_str) slapi_ch_free((void **) &new_filter_str);
  2480. if (tt == info.lu_idx) {
  2481. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "currDn:(%s) \n\tNO MEMBER ADDED\n",
  2482. ACL_ESCAPE_STRING_WITH_PUNCTUATION (curMemberDn, ebuf));
  2483. } else {
  2484. for (i=tt; i < info.lu_idx; i++)
  2485. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2486. "currDn:(%s) \n\tADDED MEMBER[%d]=%s\n",
  2487. ACL_ESCAPE_STRING_WITH_PUNCTUATION (curMemberDn, ebuf), i, info.member[i]);
  2488. }
  2489. if (info.c_idx >= info.lu_idx) {
  2490. for (i=0; i < info.lu_idx; i++) {
  2491. int already_cached = 0;
  2492. for (j=0; j < u_group->aclug_numof_member_group;
  2493. j++){
  2494. if (slapi_utf8casecmp(
  2495. (ACLUCHP)info.member[i],
  2496. (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
  2497. slapi_ch_free ((void **) &info.member[i] );
  2498. info.member[i] = NULL;
  2499. already_cached = 1;
  2500. break;
  2501. }
  2502. }
  2503. if (already_cached) continue;
  2504. ngr = u_group->aclug_numof_member_group++;
  2505. if (u_group->aclug_numof_member_group >=
  2506. u_group->aclug_member_group_size){
  2507. u_group->aclug_member_groups =
  2508. (char **) slapi_ch_realloc (
  2509. (void *) u_group->aclug_member_groups,
  2510. (u_group->aclug_member_group_size +
  2511. ACLUG_INCR_GROUPS_LIST) * sizeof(char *));
  2512. u_group->aclug_member_group_size +=
  2513. ACLUG_INCR_GROUPS_LIST;
  2514. }
  2515. u_group->aclug_member_groups[ngr] = info.member[i];
  2516. info.member[i] = NULL;
  2517. }
  2518. slapi_ch_free ((void **) &info.member);
  2519. Done = 1;
  2520. } else {
  2521. curMemberDn = info.member[info.c_idx];
  2522. info.c_idx++;
  2523. }
  2524. }
  2525. }
  2526. for (j=0; j < u_group->aclug_numof_member_group; j++)
  2527. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2528. "acllas__eval_memberGroupDnAttr:GROUP[%d] IN CACHE:%s\n",
  2529. j, ACL_ESCAPE_STRING_WITH_PUNCTUATION (u_group->aclug_member_groups[j], ebuf));
  2530. matched = ACL_FALSE;
  2531. slapi_entry_attr_find( e, groupattr, &attr);
  2532. if (attr == NULL) {
  2533. slapi_ch_free ( (void **)&s_str );
  2534. return ACL_FALSE;
  2535. }
  2536. k = slapi_attr_first_value ( attr,&sval );
  2537. while ( k != -1 ) {
  2538. char *n_attrval;
  2539. attrVal = slapi_value_get_berval ( sval );
  2540. n_attrval = slapi_ch_strdup( attrVal->bv_val);
  2541. n_attrval = slapi_dn_normalize (n_attrval);
  2542. /* We support: The attribute value can be a USER or a GROUP.
  2543. ** Let's compare with the client, thi might be just an user. If it is not
  2544. ** then we test it against the list of groups.
  2545. */
  2546. if (slapi_utf8casecmp ((ACLUCHP)n_attrval, (ACLUCHP)n_clientdn) == 0 ) {
  2547. matched = ACL_TRUE;
  2548. slapi_ch_free ( (void **)&n_attrval );
  2549. break;
  2550. }
  2551. for (j=0; j <u_group->aclug_numof_member_group; j++) {
  2552. if ( slapi_utf8casecmp((ACLUCHP)n_attrval,
  2553. (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
  2554. matched = ACL_TRUE;
  2555. break;
  2556. }
  2557. }
  2558. slapi_ch_free ( (void **)&n_attrval );
  2559. if (matched == ACL_TRUE) break;
  2560. k= slapi_attr_next_value ( attr, k, &sval );
  2561. }
  2562. slapi_ch_free ( (void **)&s_str );
  2563. return matched;
  2564. }
  2565. static int
  2566. acllas__add_allgroups (Slapi_Entry* e, void *callback_data)
  2567. {
  2568. int i, n, m;
  2569. struct eval_info *info;
  2570. char *n_dn;
  2571. info = (struct eval_info *) callback_data;
  2572. /*
  2573. ** Once we are here means this is a valid group. First see
  2574. ** If we have already seen this group. If not, add it to the
  2575. ** member list.
  2576. */
  2577. n_dn = slapi_ch_strdup ( slapi_entry_get_ndn ( e ) );
  2578. for (i=0; i < info->lu_idx; i++) {
  2579. if (slapi_utf8casecmp((ACLUCHP)n_dn, (ACLUCHP)info->member[i]) == 0) {
  2580. slapi_ch_free ( (void **) &n_dn);
  2581. return 0;
  2582. }
  2583. }
  2584. m = info->lu_idx;
  2585. n = info->lu_idx++;
  2586. if (!(n % ACLLAS_MAX_GRP_MEMBER)) {
  2587. info->member = (char **) slapi_ch_realloc (
  2588. (void *) info->member,
  2589. (n+ACLLAS_MAX_GRP_MEMBER) * sizeof(char *));
  2590. }
  2591. info->member[m] = n_dn;
  2592. return 0;
  2593. }
  2594. /*
  2595. *
  2596. * acllas__dn_parent
  2597. *
  2598. * This code should belong to dn.c. However this is specific to acl and I had
  2599. * 2 choices 1) create a new API or 2) reuse the slapi_dN_parent
  2600. *
  2601. * Returns a ptr to the parent based on the level.
  2602. *
  2603. */
  2604. #define DNSEPARATOR(c) (c == ',' || c == ';')
  2605. static char*
  2606. acllas__dn_parent( char *dn, int level)
  2607. {
  2608. char *s, *dnstr;
  2609. int inquote;
  2610. int curLevel;
  2611. int lastLoop = 0;
  2612. if ( dn == NULL || *dn == '\0' ) {
  2613. return( NULL );
  2614. }
  2615. /* An X.500-style name, which looks like foo=bar,sha=baz,... */
  2616. /* Do we have any dn seprator or not */
  2617. if ((strchr(dn,',') == NULL) && (strchr(dn,';') == NULL))
  2618. return (NULL);
  2619. inquote = 0;
  2620. curLevel = 1;
  2621. dnstr = dn;
  2622. while ( curLevel <= level) {
  2623. if (lastLoop) break;
  2624. if (curLevel == level) lastLoop = 1;
  2625. for ( s = dnstr; *s; s++ ) {
  2626. if ( *s == '\\' ) {
  2627. if ( *(s + 1) )
  2628. s++;
  2629. continue;
  2630. }
  2631. if ( inquote ) {
  2632. if ( *s == '"' )
  2633. inquote = 0;
  2634. } else {
  2635. if ( *s == '"' )
  2636. inquote = 1;
  2637. else if ( DNSEPARATOR( *s ) ) {
  2638. if (curLevel == level)
  2639. return( s + 1 );
  2640. dnstr = s + 1;
  2641. curLevel++;
  2642. break;
  2643. }
  2644. }
  2645. }
  2646. if ( *s == '\0') {
  2647. /* Got to the end of the string without reaching level,
  2648. * so return NULL.
  2649. */
  2650. return(NULL);
  2651. }
  2652. }
  2653. return( NULL );
  2654. }
  2655. /*
  2656. * acllas__verify_client
  2657. *
  2658. * returns 1 if the attribute exists in the entry and
  2659. * it's value is equal to the client Dn.
  2660. * If the attribute is not in the entry, or it is and the
  2661. * value differs from the clientDn then returns FALSE.
  2662. *
  2663. * Verify if client's DN is stored in the attrbute or not.
  2664. * This is a handler from a search being done at
  2665. * DS_LASUserDnAttrEval().
  2666. *
  2667. */
  2668. static int
  2669. acllas__verify_client (Slapi_Entry* e, void *callback_data)
  2670. {
  2671. Slapi_Attr *attr;
  2672. char *val;
  2673. struct userdnattr_info *info;
  2674. Slapi_Value *sval;
  2675. const struct berval *attrVal;
  2676. int i;
  2677. info = (struct userdnattr_info *) callback_data;
  2678. slapi_entry_attr_find( e, info->attr, &attr);
  2679. if (attr == NULL) return 0;
  2680. i = slapi_attr_first_value ( attr,&sval );
  2681. while ( i != -1 ) {
  2682. attrVal = slapi_value_get_berval ( sval );
  2683. val = slapi_dn_normalize(slapi_ch_strdup(attrVal->bv_val));
  2684. if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)info->clientdn ) == 0) {
  2685. info->result = 1;
  2686. slapi_ch_free ( (void **) &val);
  2687. return 0;
  2688. }
  2689. slapi_ch_free ( (void **) &val);
  2690. i = slapi_attr_next_value ( attr, i, &sval );
  2691. }
  2692. return 0;
  2693. }
  2694. /*
  2695. * acllas__verify_ldapurl
  2696. *
  2697. * returns 1 if the attribute exists in the entry and
  2698. * it's value is equal to the client Dn.
  2699. * If the attribute is not in the entry, or it is and the
  2700. * value differs from the clientDn then returns FALSE.
  2701. *
  2702. * Verify if client's entry includes the attribute value that
  2703. * matches the filter in LDAPURL
  2704. * This is a handler from a search being done at DS_LASLdapUrlAttrEval().
  2705. *
  2706. */
  2707. static int
  2708. acllas__verify_ldapurl(Slapi_Entry* e, void *callback_data)
  2709. {
  2710. Slapi_Attr *attr;
  2711. struct userdnattr_info *info;
  2712. Slapi_Value *sval;
  2713. const struct berval *attrVal;
  2714. int rc;
  2715. info = (struct userdnattr_info *) callback_data;
  2716. info->result = ACL_FALSE;
  2717. rc = slapi_entry_attr_find( e, info->attr, &attr);
  2718. if (rc != 0 || attr == NULL) {
  2719. return 0;
  2720. }
  2721. rc = slapi_attr_first_value ( attr, &sval );
  2722. if ( rc == -1 ) {
  2723. return 0;
  2724. }
  2725. while (rc != -1 && sval != NULL) {
  2726. attrVal = slapi_value_get_berval ( sval );
  2727. info->result = acllas__client_match_URL ( info->aclpb,
  2728. info->clientdn,
  2729. attrVal->bv_val);
  2730. if ( info->result == ACL_TRUE ) {
  2731. return 0;
  2732. }
  2733. rc = slapi_attr_next_value ( attr, rc, &sval );
  2734. }
  2735. return 0;
  2736. }
  2737. /*
  2738. *
  2739. * acllas__get_members
  2740. *
  2741. * Collects all the values of the specified attribute which should be group names.
  2742. */
  2743. static int
  2744. acllas__get_members (Slapi_Entry* e, void *callback_data)
  2745. {
  2746. Slapi_Attr *attr;
  2747. struct groupdnattr_info *info;
  2748. Slapi_Value *sval=NULL;
  2749. const struct berval *attrVal;
  2750. int i;
  2751. info = (struct groupdnattr_info *) callback_data;
  2752. slapi_entry_attr_find (e, info->attrName, &attr);
  2753. if ( !attr ) return 0;
  2754. slapi_attr_get_numvalues ( attr, &info->numofGroups );
  2755. info->member = (char **) slapi_ch_malloc (info->numofGroups * sizeof(char *));
  2756. i = slapi_attr_first_value ( attr,&sval );
  2757. while ( i != -1 ) {
  2758. attrVal =slapi_value_get_berval ( sval );
  2759. info->member[i] = slapi_dn_normalize ( slapi_ch_strdup(attrVal->bv_val));
  2760. i = slapi_attr_next_value ( attr, i, &sval );
  2761. }
  2762. return 0;
  2763. }
  2764. /*
  2765. * DS_LASUserAttrEval
  2766. * LAS to evaluate the userattr rule
  2767. *
  2768. * userAttr = "attrName#Type"
  2769. *
  2770. * <Type> ::= "USERDN" | "GROUPDN" | "ROLEDN" | "LDAPURL" | <value>
  2771. * <value>::== <any printable String>
  2772. *
  2773. * Example:
  2774. * userAttr = "manager#USERDN" --- same as userdnattr
  2775. * userAttr = "owner#GROUPDN" --- same as groupdnattr
  2776. * = "ldap:///o=sun.com?owner#GROUPDN
  2777. * userAttr = "attr#ROLEDN" --- The value of attr contains a roledn
  2778. * userAttr = "myattr#LDAPURL" --- The value contains a LDAP URL
  2779. * which can have scope and filter
  2780. * bits.
  2781. * userAttr = "OU#Directory Server"
  2782. * --- In this case the client's OU and the
  2783. * resource entry's OU must have
  2784. * "Directory Server" value.
  2785. *
  2786. * Returns:
  2787. * retcode The usual LAS return codes.
  2788. */
  2789. int
  2790. DS_LASUserAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  2791. char *attr_pattern, int *cachable, void **LAS_cookie,
  2792. PList_t subject, PList_t resource, PList_t auth_info,
  2793. PList_t global_auth)
  2794. {
  2795. char *attrName;
  2796. char *attrValue = NULL;
  2797. int rc;
  2798. int matched = ACL_FALSE;
  2799. char *p;
  2800. lasInfo lasinfo;
  2801. int got_undefined = 0;
  2802. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  2803. attr_pattern,cachable,LAS_cookie,
  2804. subject, resource, auth_info,global_auth,
  2805. DS_LAS_USERATTR, "DS_LASUserAttrEval",
  2806. &lasinfo )) ) {
  2807. return LAS_EVAL_FAIL;
  2808. }
  2809. /* Which rule are we evaluating ? */
  2810. attrName = slapi_ch_strdup (attr_pattern );
  2811. if ( NULL == (p = strchr ( attrName, '#' ))) {
  2812. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  2813. "DS_LASUserAttrEval:Invalid value(%s)\n", attr_pattern);
  2814. slapi_ch_free ( (void **) &attrName );
  2815. return LAS_EVAL_FAIL;
  2816. }
  2817. attrValue = p;
  2818. attrValue++; /* skip the # */
  2819. *p = '\0'; /* null terminate the attr name */
  2820. if ( 0 == strncasecmp ( attrValue, "USERDN", 6)) {
  2821. matched = DS_LASUserDnAttrEval (errp,DS_LAS_USERDNATTR, comparator,
  2822. attrName, cachable, LAS_cookie,
  2823. subject, resource, auth_info, global_auth);
  2824. goto done_las;
  2825. } else if ( 0 == strncasecmp ( attrValue, "GROUPDN", 7)) {
  2826. matched = DS_LASGroupDnAttrEval (errp,DS_LAS_GROUPDNATTR, comparator,
  2827. attrName, cachable, LAS_cookie,
  2828. subject, resource, auth_info, global_auth);
  2829. goto done_las;
  2830. } else if ( 0 == strncasecmp ( attrValue, "LDAPURL", 7) ) {
  2831. matched = DS_LASLdapUrlAttrEval(errp, DS_LAS_USERATTR, comparator,
  2832. attrName, cachable, LAS_cookie,
  2833. subject, resource, auth_info, global_auth, lasinfo);
  2834. goto done_las;
  2835. } else if ( 0 == strncasecmp ( attrValue, "ROLEDN", 6)) {
  2836. matched = DS_LASRoleDnAttrEval (errp,DS_LAS_ROLEDN, comparator,
  2837. attrName, cachable, LAS_cookie,
  2838. subject, resource, auth_info, global_auth);
  2839. goto done_las;
  2840. }
  2841. if ( lasinfo.aclpb && ( NULL == lasinfo.aclpb->aclpb_client_entry )) {
  2842. /* SD 00/16/03 pass NULL in case the req is chained */
  2843. char **attrs=NULL;
  2844. /* Use new search internal API */
  2845. Slapi_PBlock *aPb = slapi_pblock_new ();
  2846. /*
  2847. * This search may be chained if chaining for ACL is
  2848. * is enabled in the backend and the entry is in
  2849. * a chained backend.
  2850. */
  2851. slapi_search_internal_set_pb ( aPb,
  2852. lasinfo.clientDn,
  2853. LDAP_SCOPE_BASE,
  2854. "objectclass=*",
  2855. attrs,
  2856. 0,
  2857. NULL /* controls */,
  2858. NULL /* uniqueid */,
  2859. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  2860. 0 /* actions */);
  2861. slapi_search_internal_callback_pb(aPb,
  2862. lasinfo.aclpb /* callback_data */,
  2863. NULL/* result_callback */,
  2864. acllas__handle_client_search,
  2865. NULL /* referral_callback */);
  2866. slapi_pblock_destroy (aPb);
  2867. }
  2868. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  2869. "DS_LASUserAttrEval: AttrName:%s, attrVal:%s\n", attrName, attrValue );
  2870. /*
  2871. * Here it's the userAttr = "OU#Directory Server" case.
  2872. * Allocate the Slapi_Value on the stack and init it by reference
  2873. * to avoid having to malloc and free memory.
  2874. */
  2875. Slapi_Value v;
  2876. slapi_value_init_string_passin(&v, attrValue);
  2877. rc = slapi_entry_attr_has_syntax_value ( lasinfo.resourceEntry, attrName,
  2878. &v );
  2879. if (rc) {
  2880. rc = slapi_entry_attr_has_syntax_value (
  2881. lasinfo.aclpb->aclpb_client_entry,
  2882. attrName, &v );
  2883. if (rc) matched = ACL_TRUE;
  2884. }
  2885. /* Nothing to free--cool */
  2886. /*
  2887. * Find out what the result is, in
  2888. * this case matched is one of ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW
  2889. * and got_undefined says whether a logical term evaluated to ACL_DONT_KNOW.
  2890. *
  2891. */
  2892. if ( matched == ACL_TRUE || !got_undefined) {
  2893. if (comparator == CMP_OP_EQ) {
  2894. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  2895. } else {
  2896. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  2897. }
  2898. } else {
  2899. rc = LAS_EVAL_FAIL;
  2900. }
  2901. slapi_ch_free ( (void **) &attrName );
  2902. return rc;
  2903. done_las:
  2904. /*
  2905. * In this case matched is already LAS_EVAL_TRUE or LAS_EVAL_FALSE or
  2906. * LAS_EVAL_FAIL.
  2907. */
  2908. if ( matched != LAS_EVAL_FAIL ) {
  2909. if (comparator == CMP_OP_EQ) {
  2910. rc = matched;
  2911. } else {
  2912. rc = (matched == LAS_EVAL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  2913. }
  2914. }
  2915. slapi_ch_free ( (void **) &attrName );
  2916. return rc;
  2917. }
  2918. /*
  2919. * acllas__client_match_URL
  2920. * Match a client to a URL.
  2921. *
  2922. * Returns:
  2923. * ACL_TRUE - matched the URL
  2924. * ACL_FALSE - Sorry; no match
  2925. *
  2926. */
  2927. static int
  2928. acllas__client_match_URL (struct acl_pblock *aclpb, char *n_clientdn, char *url )
  2929. {
  2930. LDAPURLDesc *ludp;
  2931. int rc;
  2932. Slapi_Filter *f = NULL;
  2933. /* Get the client's entry if we don't have already */
  2934. if ( aclpb && ( NULL == aclpb->aclpb_client_entry )) {
  2935. /* SD 00/16/03 Get every attr in case req chained */
  2936. char **attrs=NULL;
  2937. /* Use new search internal API */
  2938. Slapi_PBlock * aPb = slapi_pblock_new ();
  2939. /*
  2940. * This search may be chained if chaining for ACL is
  2941. * is enabled in the backend and the entry is in
  2942. * a chained backend.
  2943. */
  2944. slapi_search_internal_set_pb ( aPb,
  2945. n_clientdn,
  2946. LDAP_SCOPE_BASE,
  2947. "objectclass=*",
  2948. attrs,
  2949. 0,
  2950. NULL /* controls */,
  2951. NULL /* uniqueid */,
  2952. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  2953. 0 /* actions */);
  2954. slapi_search_internal_callback_pb(aPb,
  2955. aclpb /* callback_data */,
  2956. NULL/* result_callback */,
  2957. acllas__handle_client_search,
  2958. NULL /* referral_callback */);
  2959. slapi_pblock_destroy (aPb);
  2960. }
  2961. if ( NULL == aclpb->aclpb_client_entry ) {
  2962. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  2963. "DS_LASUserAttrEval: Unable to get client's entry\n");
  2964. return ACL_FALSE;
  2965. }
  2966. if (( rc = ldap_url_parse( url, &ludp)) != 0 ) {
  2967. return ACL_FALSE;
  2968. }
  2969. if ( ( NULL == ludp->lud_dn) || ( NULL == ludp->lud_filter) ) {
  2970. ldap_free_urldesc( ludp );
  2971. return ACL_FALSE;
  2972. }
  2973. /* Normalize in place the dn */
  2974. slapi_dn_normalize ( ludp->lud_dn );
  2975. /* Check the scope */
  2976. if ( ludp->lud_scope == LDAP_SCOPE_SUBTREE ) {
  2977. if (!slapi_dn_issuffix(n_clientdn, ludp->lud_dn)) {
  2978. ldap_free_urldesc( ludp );
  2979. return ACL_FALSE;
  2980. }
  2981. } else if ( ludp->lud_scope == LDAP_SCOPE_ONELEVEL ) {
  2982. char *parent = slapi_dn_parent (n_clientdn);
  2983. if (slapi_utf8casecmp ((ACLUCHP)parent, (ACLUCHP)ludp->lud_dn) != 0 ) {
  2984. slapi_ch_free ( (void **) &parent);
  2985. ldap_free_urldesc( ludp );
  2986. return ACL_FALSE;
  2987. }
  2988. slapi_ch_free ( (void **) &parent);
  2989. } else { /* default */
  2990. if (slapi_utf8casecmp ( (ACLUCHP)n_clientdn, (ACLUCHP)ludp->lud_dn) != 0 ) {
  2991. ldap_free_urldesc( ludp );
  2992. return ACL_FALSE;
  2993. }
  2994. }
  2995. /* Convert the filter string */
  2996. f = slapi_str2filter ( ludp->lud_filter );
  2997. if (ludp->lud_filter && (f == NULL)) { /* bogus filter */
  2998. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  2999. "DS_LASUserAttrEval: The member URL search filter in entry [%s] is not valid: [%s]\n",
  3000. n_clientdn, ludp->lud_filter);
  3001. ldap_free_urldesc( ludp );
  3002. return ACL_FALSE;
  3003. }
  3004. rc = ACL_TRUE;
  3005. if (f && (0 != slapi_vattr_filter_test ( aclpb->aclpb_pblock,
  3006. aclpb->aclpb_client_entry, f, 0 /* no acces chk */ )))
  3007. rc = ACL_FALSE;
  3008. ldap_free_urldesc( ludp );
  3009. slapi_filter_free ( f, 1 ) ;
  3010. return rc;
  3011. }
  3012. static int
  3013. acllas__handle_client_search ( Slapi_Entry *e, void *callback_data )
  3014. {
  3015. struct acl_pblock *aclpb = (struct acl_pblock *) callback_data;
  3016. /* If we are here means we have found the entry */
  3017. if ( NULL == aclpb-> aclpb_client_entry)
  3018. aclpb->aclpb_client_entry = slapi_entry_dup ( e );
  3019. return 0;
  3020. }
  3021. /*
  3022. *
  3023. * Do all the necessary setup for all the
  3024. * LASes.
  3025. * It will only fail if it's passed garbage (which should not happen) or
  3026. * if the data it needs to stock the lasinfo is not available, which
  3027. * also should not happen.
  3028. *
  3029. *
  3030. * Return value: 0 or one of these
  3031. * #define LAS_EVAL_TRUE -1
  3032. * #define LAS_EVAL_FALSE -2
  3033. * #define LAS_EVAL_DECLINE -3
  3034. * #define LAS_EVAL_FAIL -4
  3035. * #define LAS_EVAL_INVALID -5
  3036. */
  3037. static int
  3038. __acllas_setup ( NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  3039. char *attr_pattern, int *cachable, void **LAS_cookie,
  3040. PList_t subject, PList_t resource, PList_t auth_info,
  3041. PList_t global_auth, char *lasType, char*lasName, lasInfo *linfo)
  3042. {
  3043. int rc;
  3044. memset ( linfo, 0, sizeof ( lasInfo) );
  3045. *cachable = 0;
  3046. *LAS_cookie = (void *)0;
  3047. if (strcmp(attr_name, lasType) != 0) {
  3048. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3049. "%s:Invalid LAS(%s)\n", lasName, attr_name);
  3050. return LAS_EVAL_INVALID;
  3051. }
  3052. if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
  3053. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3054. "%s:Invalid comparator(%d)\n", lasName, (int)comparator);
  3055. return LAS_EVAL_INVALID;
  3056. }
  3057. /* Get the client DN */
  3058. rc = ACL_GetAttribute(errp, DS_ATTR_USERDN, (void **)&linfo->clientDn,
  3059. subject, resource, auth_info, global_auth);
  3060. if ( rc != LAS_EVAL_TRUE ) {
  3061. acl_print_acllib_err(errp, NULL);
  3062. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3063. "%s:Unable to get the clientdn attribute(%d)\n",lasName, rc);
  3064. return LAS_EVAL_FAIL;
  3065. }
  3066. /* Check if we have a user or not */
  3067. if (linfo->clientDn) {
  3068. /* See if it's a anonymous user */
  3069. if (*(linfo->clientDn) == '\0')
  3070. linfo->anomUser = ACL_TRUE;
  3071. } else {
  3072. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3073. "%s: No user\n",lasName);
  3074. return LAS_EVAL_FAIL;
  3075. }
  3076. if ((rc = PListFindValue(subject, DS_ATTR_ENTRY,
  3077. (void **)&linfo->resourceEntry, NULL)) < 0) {
  3078. acl_print_acllib_err(errp, NULL);
  3079. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3080. "%s:Unable to get the Slapi_Entry attr(%d)\n",lasName, rc);
  3081. return LAS_EVAL_FAIL;
  3082. }
  3083. /* Get ACLPB */
  3084. rc = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&linfo->aclpb,
  3085. subject, resource, auth_info, global_auth);
  3086. if ( rc != LAS_EVAL_TRUE ) {
  3087. acl_print_acllib_err(errp, NULL);
  3088. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3089. "%s:Unable to get the ACLPB(%d)\n", lasName, rc);
  3090. return LAS_EVAL_FAIL;
  3091. }
  3092. if (NULL == attr_pattern ) {
  3093. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3094. "%s:No rule value in the ACL\n", lasName);
  3095. return LAS_EVAL_FAIL;
  3096. }
  3097. /* get the authentication type */
  3098. if ((rc = PListFindValue(subject, DS_ATTR_AUTHTYPE,
  3099. (void **)&linfo->authType, NULL)) < 0) {
  3100. acl_print_acllib_err(errp, NULL);
  3101. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3102. "%s:Unable to get the auth type(%d)\n", lasName, rc);
  3103. return LAS_EVAL_FAIL;
  3104. }
  3105. return 0;
  3106. }
  3107. /*
  3108. * See if clientDN has role roleDN.
  3109. * Here we know the user is not anon and that the role
  3110. * is not the anyone role ie. it's actually worth invoking the roles code.
  3111. */
  3112. static int acllas__user_has_role( struct acl_pblock *aclpb,
  3113. Slapi_DN *roleDN, Slapi_DN *clientDn) {
  3114. int present = 0;
  3115. /* Get the client's entry if we don't have already */
  3116. if ( aclpb && ( NULL == aclpb->aclpb_client_entry )) {
  3117. /* SD 00/16/03 Get every attr in case req chained */
  3118. char **attrs=NULL;
  3119. /* Use new search internal API */
  3120. Slapi_PBlock * aPb = slapi_pblock_new ();
  3121. /*
  3122. * This search may NOT be chained--the user and the role definition
  3123. * must be co-located (chaining is not supported for the roles
  3124. * plugin in 5.0
  3125. */
  3126. slapi_search_internal_set_pb ( aPb,
  3127. slapi_sdn_get_ndn(clientDn),
  3128. LDAP_SCOPE_BASE,
  3129. "objectclass=*",
  3130. attrs,
  3131. 0,
  3132. NULL /* controls */,
  3133. NULL /* uniqueid */,
  3134. aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
  3135. SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
  3136. slapi_search_internal_callback_pb(aPb,
  3137. aclpb /* callback_data */,
  3138. NULL/* result_callback */,
  3139. acllas__handle_client_search,
  3140. NULL /* referral_callback */);
  3141. slapi_pblock_destroy (aPb);
  3142. }
  3143. if ( NULL == aclpb->aclpb_client_entry ) {
  3144. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  3145. "acllas__user_has_role: Unable to get client's entry\n");
  3146. return ACL_FALSE;
  3147. }
  3148. /* If the client has the role then it's a match, otherwise no */
  3149. slapi_role_check( aclpb->aclpb_client_entry, roleDN, &present);
  3150. if ( present ) {
  3151. return(ACL_TRUE);
  3152. }
  3153. return(ACL_FALSE);
  3154. }
  3155. int
  3156. DS_LASRoleDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
  3157. char *attr_pattern, int *cachable, void **LAS_cookie,
  3158. PList_t subject, PList_t resource, PList_t auth_info,
  3159. PList_t global_auth)
  3160. {
  3161. char *attrName;
  3162. int matched;
  3163. int rc;
  3164. Slapi_Attr *attr;
  3165. lasInfo lasinfo;
  3166. Slapi_Value *sval=NULL;
  3167. const struct berval *attrVal;
  3168. int k=0;
  3169. int got_undefined = 0;
  3170. if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
  3171. attr_pattern,cachable,LAS_cookie,
  3172. subject, resource, auth_info,global_auth,
  3173. DS_LAS_ROLEDN, "DS_LASRoleDnAttrEval",
  3174. &lasinfo )) ) {
  3175. return LAS_EVAL_FAIL;
  3176. }
  3177. /* For anonymous client, they have no roles so the match is false. */
  3178. if ( lasinfo.anomUser )
  3179. return LAS_EVAL_FALSE;
  3180. /*
  3181. **
  3182. ** The function of this LAS is to find out if the client has
  3183. ** the role specified in the attr.
  3184. ** attr_pattern looks like: "ROLEDN cn=role1,o=sun.com"
  3185. */
  3186. attrName = attr_pattern;
  3187. matched = ACL_FALSE;
  3188. slapi_entry_attr_find( lasinfo.resourceEntry, attrName, &attr);
  3189. if (attr == NULL) {
  3190. /*
  3191. * Here the entry does not contain the attribute so the user
  3192. * cannot have this "null" role
  3193. */
  3194. return LAS_EVAL_FALSE;
  3195. }
  3196. if (lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
  3197. /*
  3198. * Here the entry does not contain the attribute so the user
  3199. * cannot have this "null" role or
  3200. * For the add operation, the resource itself
  3201. * must never be allowed to grant access--
  3202. * This is because access would be granted based on a value
  3203. * of an attribute in the new entry--security hole.
  3204. * XXX is this therefore FALSE or DONT_KNOW ?
  3205. *
  3206. *
  3207. */
  3208. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3209. "ACL info: userattr=XXX#ROLEDN does not allow ADD permission.\n");
  3210. got_undefined = 1;
  3211. } else {
  3212. /*
  3213. * Got the first value.
  3214. * Test all the values of this attribute--if the client has _any_
  3215. * of the roles then it's a match.
  3216. */
  3217. k = slapi_attr_first_value ( attr,&sval );
  3218. while ( k != -1 ) {
  3219. char *n_attrval;
  3220. Slapi_DN *roleDN;
  3221. attrVal = slapi_value_get_berval ( sval );
  3222. n_attrval = slapi_ch_strdup( attrVal->bv_val);
  3223. n_attrval = slapi_dn_normalize (n_attrval);
  3224. roleDN = slapi_sdn_new_dn_byval(n_attrval);
  3225. /* We support: The attribute value can be a USER or a GROUP.
  3226. ** Let's compare with the client, thi might be just an user. If it is not
  3227. ** then we test it against the list of groups.
  3228. */
  3229. if ((matched = acllas__user_has_role(
  3230. lasinfo.aclpb,
  3231. roleDN,
  3232. lasinfo.aclpb->aclpb_authorization_sdn)) == ACL_TRUE){
  3233. slapi_ch_free ( (void **)&n_attrval );
  3234. slapi_sdn_free(&roleDN );
  3235. break;
  3236. }
  3237. slapi_ch_free ( (void **)&n_attrval );
  3238. slapi_sdn_free(&roleDN );
  3239. if (matched == ACL_TRUE) {
  3240. break;
  3241. } else if ( matched == ACL_DONT_KNOW ) {
  3242. /* record this but keep going--maybe another group will evaluate to TRUE */
  3243. got_undefined = 1;
  3244. }
  3245. k= slapi_attr_next_value ( attr, k, &sval );
  3246. }/* while */
  3247. }
  3248. /*
  3249. * If no terms were undefined, then evaluate as normal.
  3250. * If there was an undefined term, but another one was TRUE, then we also evaluate
  3251. * as normal. Otherwise, the whole expression is UNDEFINED.
  3252. */
  3253. if ( matched == ACL_TRUE || !got_undefined ) {
  3254. if (comparator == CMP_OP_EQ) {
  3255. rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
  3256. } else {
  3257. rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
  3258. }
  3259. } else {
  3260. rc = LAS_EVAL_FAIL;
  3261. }
  3262. return (rc);
  3263. }
  3264. /*
  3265. * Here, determine if lasinfo->clientDn matches user (which contains
  3266. * a ($dn) or a $attr component or both.) As defined in the aci
  3267. * lasinfo->aclpb->aclpb_curr_aci,
  3268. * which is the current aci being evaluated.
  3269. *
  3270. * returns: ACL_TRUE for matched,
  3271. * ACL_FALSE for matched.
  3272. * ACL_DONT_KNOW otherwise.
  3273. *
  3274. *
  3275. */
  3276. int
  3277. aclutil_evaluate_macro( char * rule, lasInfo *lasinfo,
  3278. acl_eval_types evalType ) {
  3279. int matched = 0;
  3280. aci_t *aci;
  3281. char *matched_val = NULL;
  3282. char **candidate_list = NULL;
  3283. char **inner_list = NULL;
  3284. char **sptr = NULL;
  3285. char **tptr = NULL;
  3286. char *t = NULL;
  3287. char *s = NULL;
  3288. struct acl_pblock *aclpb = lasinfo->aclpb;
  3289. aci = lasinfo->aclpb->aclpb_curr_aci;
  3290. /* Get a pointer to the ndn in the resouirce */
  3291. slapi_entry_get_ndn ( lasinfo->resourceEntry );
  3292. /*
  3293. * First, get the matched value from the target resource.
  3294. * We have alredy done this matching once beofer at tasrget match time.
  3295. */
  3296. LDAPDebug ( LDAP_DEBUG_ACL, "aclutil_evaluate_macro for aci '%s'"
  3297. "index '%d'\n",
  3298. aci->aclName, aci->aci_index,0);
  3299. if ( aci->aci_macro == NULL ) {
  3300. /* No $dn in the target, it's a $attr type subject rule */
  3301. matched_val = NULL;
  3302. } else {
  3303. /*
  3304. * Look up the matched_val value calculated
  3305. * from the target and stored judiciously there for us.
  3306. */
  3307. if ( (matched_val = (char *)acl_ht_lookup( aclpb->aclpb_macro_ht,
  3308. (PLHashNumber)aci->aci_index)) == NULL) {
  3309. LDAPDebug( LDAP_DEBUG_ACL,
  3310. "ACL info: failed to locate the calculated target"
  3311. "macro for aci '%s' index '%d'\n",
  3312. aci->aclName, aci->aci_index,0);
  3313. return(ACL_FALSE); /* Not a match */
  3314. } else {
  3315. LDAPDebug( LDAP_DEBUG_ACL,
  3316. "ACL info: found matched_val (%s) for aci index %d"
  3317. "in macro ht\n",
  3318. aci->aclName, aci->aci_index,0);
  3319. }
  3320. }
  3321. /*
  3322. * Now, make a candidate
  3323. * list of strings to match against the client.
  3324. * This involves replacing ($dn) or [$dn] by either the matched
  3325. * value, or all the suffix substrings of matched_val.
  3326. * If there is no $dn then the candidate list is just
  3327. * user itself.
  3328. *
  3329. */
  3330. candidate_list = acllas_replace_dn_macro( rule, matched_val, lasinfo);
  3331. sptr= candidate_list;
  3332. while( *sptr != NULL && !matched) {
  3333. s = *sptr;
  3334. /*
  3335. * Now s may contain some $attr macros.
  3336. * So, make a candidate list, got by replacing each occurence
  3337. * of $attr with all the values that attribute has in
  3338. * the resource entry.
  3339. */
  3340. inner_list = acllas_replace_attr_macro( s, lasinfo);
  3341. tptr = inner_list;
  3342. while( *tptr != NULL && (matched != ACL_TRUE) ){
  3343. t = *tptr;
  3344. /*
  3345. * Now, at last t is a candidate string we can
  3346. * match agains the client.
  3347. *
  3348. * $dn and $attr can appear in userdn, graoupdn and roledn
  3349. * rules, so we we need to decide which type we
  3350. * currently evaluating and evaluate that.
  3351. *
  3352. * If the string generated was undefined, eg it contained
  3353. * ($attr.ou) and the entry did not have an ou attribute,then
  3354. * the empty string is returned for this. So it we find
  3355. * an empty string in the list, skip it--it does not match.
  3356. */
  3357. if ( *t != '\0') {
  3358. if ( evalType == ACL_EVAL_USER ) {
  3359. matched = acllas_eval_one_user( lasinfo->aclpb,
  3360. lasinfo->clientDn, t);
  3361. } else if (evalType == ACL_EVAL_GROUP) {
  3362. matched = acllas_eval_one_group(t, lasinfo);
  3363. } else if (evalType == ACL_EVAL_ROLE) {
  3364. matched = acllas_eval_one_role(t, lasinfo);
  3365. } else if (evalType == ACL_EVAL_GROUPDNATTR) {
  3366. matched = acllas__eval_memberGroupDnAttr(t,
  3367. lasinfo->resourceEntry,
  3368. lasinfo->clientDn,
  3369. lasinfo->aclpb);
  3370. } else if ( evalType == ACL_EVAL_TARGET_FILTER) {
  3371. matched = acllas_eval_one_target_filter(t,
  3372. lasinfo->resourceEntry);
  3373. }
  3374. }
  3375. tptr++;
  3376. }/*inner while*/
  3377. charray_free(inner_list);
  3378. sptr++;
  3379. }/* outer while */
  3380. charray_free(candidate_list);
  3381. return(matched);
  3382. }
  3383. /*
  3384. * Here, replace the first occurrence of $(dn) with matched_val.
  3385. * replace any occurrence of $[dn] with each of the suffix substrings
  3386. * of matched_val.
  3387. * Each of these strings is returned in a NULL terminated list of strings.
  3388. *
  3389. * If there is no $dn thing then the returned list just contains rule itself.
  3390. *
  3391. * eg. rule: cn=fred,ou=*, ($dn), o=sun.com
  3392. * matched_val: ou=People,o=icnc
  3393. *
  3394. * Then we return the list
  3395. * cn=fred,ou=*,ou=People,o=icnc,o=sun.com NULL
  3396. *
  3397. * eg. rule: cn=fred,ou=*,[$dn], o=sun.com
  3398. * matched_val: ou=People,o=icnc
  3399. *
  3400. * Then we return the list
  3401. * cn=fred,ou=*,ou=People,o=icnc,o=sun.com
  3402. * cn=fred,ou=*,o=icnc,o=sun.com
  3403. * NULL
  3404. *
  3405. *
  3406. */
  3407. static char **
  3408. acllas_replace_dn_macro( char *rule, char *matched_val, lasInfo *lasinfo) {
  3409. char **a = NULL;
  3410. char *patched_rule = NULL;
  3411. char *rule_to_use = NULL;
  3412. char *new_patched_rule = NULL;
  3413. int matched_val_len = 0;
  3414. int j = 0;
  3415. int has_macro_dn = 0;
  3416. int has_macro_levels = 0;
  3417. /* Determine what the rule's got once */
  3418. if ( strstr(rule, ACL_RULE_MACRO_DN_KEY) != NULL) {
  3419. has_macro_dn = 1;
  3420. }
  3421. if ( strstr(rule, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) {
  3422. has_macro_levels = 1;
  3423. }
  3424. if ( !has_macro_dn && !has_macro_levels ) {
  3425. /*
  3426. * No $dn thing, just return a list with two elements, rule and NULL.
  3427. * charray_add will create the list and null terminate it.
  3428. */
  3429. charray_add( &a, slapi_ch_strdup(rule));
  3430. return(a);
  3431. } else {
  3432. /*
  3433. * Have an occurrence of the macro rules
  3434. *
  3435. * First, replace all occurrencers of ($dn) with the matched_val
  3436. */
  3437. if ( has_macro_dn) {
  3438. patched_rule =
  3439. acl_replace_str(rule, ACL_RULE_MACRO_DN_KEY, matched_val);
  3440. }
  3441. /* If there are no [$dn] we're done */
  3442. if ( !has_macro_levels ) {
  3443. charray_add( &a, patched_rule);
  3444. return(a);
  3445. } else {
  3446. /*
  3447. * It's a [$dn] type, so walk matched_val, splicing in all
  3448. * the suffix substrings and adding each such string to
  3449. * to the returned list.
  3450. * get_next_component() does not return the commas--the
  3451. * prefix and suffix should come with their commas.
  3452. *
  3453. * All occurrences of each [$dn] are replaced with each level.
  3454. *
  3455. * If has_macro_dn then patched_rule is the rule to strart with,
  3456. * and this needs to be freed at the end, otherwise
  3457. * just use rule.
  3458. */
  3459. if (patched_rule) {
  3460. rule_to_use = patched_rule;
  3461. } else {
  3462. rule_to_use = rule;
  3463. }
  3464. matched_val_len = strlen(matched_val);
  3465. j = 0;
  3466. while( j < matched_val_len) {
  3467. new_patched_rule =
  3468. acl_replace_str(rule_to_use, ACL_RULE_MACRO_DN_LEVELS_KEY,
  3469. &matched_val[j]);
  3470. charray_add( &a, new_patched_rule);
  3471. j += acl_find_comp_end(&matched_val[j]);
  3472. }
  3473. if (patched_rule) {
  3474. slapi_ch_free((void**)&patched_rule);
  3475. }
  3476. return(a);
  3477. }
  3478. }
  3479. }
  3480. /*
  3481. * Here, replace any occurrence of $attr.attrname with the
  3482. * value of attrname from lasinfo->resourceEntry.
  3483. *
  3484. *
  3485. * If there is no $attr thing then the returned list just contains rule
  3486. * itself.
  3487. *
  3488. * eg. rule: cn=fred,ou=*,ou=$attr.ou,o=sun.com
  3489. * ou: People
  3490. * ou: icnc
  3491. *
  3492. * Then we return the list
  3493. * cn=fred,ou=*,ou=People,o=sun.com
  3494. * cn=fred,ou=*,ou=icnc,o=sun.com
  3495. *
  3496. */
  3497. static char **
  3498. acllas_replace_attr_macro( char *rule, lasInfo *lasinfo) {
  3499. char **a = NULL;
  3500. char **working_list = NULL;
  3501. Slapi_Entry *e = lasinfo->resourceEntry;
  3502. char *str, *working_rule;
  3503. char *macro_str, *macro_attr_name;
  3504. int l;
  3505. Slapi_Attr *attr = NULL;
  3506. str = strstr(rule, ACL_RULE_MACRO_ATTR_KEY);
  3507. if ( str == NULL ) {
  3508. charray_add(&a, slapi_ch_strdup(rule));
  3509. return(a);
  3510. } else {
  3511. working_rule = slapi_ch_strdup(rule);
  3512. str = strstr(working_rule, ACL_RULE_MACRO_ATTR_KEY);
  3513. charray_add(&working_list, working_rule );
  3514. while( str != NULL) {
  3515. /*
  3516. * working_rule is the first member of working_list.
  3517. * str points to the next $attr.attrName in working_rule.
  3518. * each member of working_list needs to have each occurence of
  3519. * $attr.atrName replaced with the value of attrName in e.
  3520. * If attrName is multi valued then this generates another
  3521. * list which replaces the old one.
  3522. */
  3523. l = acl_strstr(&str[0], ")");
  3524. macro_str = slapi_ch_malloc(l+2);
  3525. strncpy( macro_str, &str[0], l+1);
  3526. macro_str[l+1] = '\0';
  3527. str = strstr(macro_str, ".");
  3528. str++; /* skip the . */
  3529. l = acl_strstr(&str[0], ")");
  3530. macro_attr_name = slapi_ch_malloc(l+1);
  3531. strncpy( macro_attr_name, &str[0], l);
  3532. macro_attr_name[l] = '\0';
  3533. slapi_entry_attr_find ( e, macro_attr_name, &attr );
  3534. if ( NULL == attr ) {
  3535. /*
  3536. * Here, if a $attr.attrName is such that the attrName
  3537. * does not occur in the entry then return a ""--
  3538. * this will go back to the matching code in
  3539. * aclutil_evaluate_macro() where "" will
  3540. * be taken as the candidate.
  3541. */
  3542. slapi_ch_free((void **)&macro_str);
  3543. slapi_ch_free((void **)&macro_attr_name);
  3544. charray_free(working_list);
  3545. charray_add(&a, slapi_ch_strdup(""));
  3546. return(a);
  3547. } else{
  3548. const struct berval *attrValue;
  3549. Slapi_Value *sval;
  3550. int i, j;
  3551. char *patched_rule;
  3552. a = NULL;
  3553. i= slapi_attr_first_value ( attr, &sval );
  3554. while(i != -1) {
  3555. attrValue = slapi_value_get_berval(sval);
  3556. j = 0;
  3557. while( working_list[j] != NULL) {
  3558. patched_rule =
  3559. acl_replace_str(working_list[j],
  3560. macro_str, attrValue->bv_val);
  3561. charray_add(&a, patched_rule);
  3562. j++;
  3563. }
  3564. i= slapi_attr_next_value( attr, i, &sval );
  3565. }/* while */
  3566. /*
  3567. * Here, a is working_list, where each member has had
  3568. * macro_str replaced with attrVal.
  3569. */
  3570. charray_free(working_list);
  3571. working_list = a;
  3572. working_rule = a[0];
  3573. }
  3574. slapi_ch_free((void **)&macro_str);
  3575. slapi_ch_free((void **)&macro_attr_name);
  3576. str = strstr(working_rule, ACL_RULE_MACRO_ATTR_KEY);
  3577. }/* while */
  3578. return(working_list);
  3579. }
  3580. }
  3581. /*
  3582. * returns ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW.
  3583. *
  3584. * user is a string from the userdn keyword which may contain
  3585. * * components. This routine does the compare component by component, so
  3586. * that * behaves differently to "normal".
  3587. * Any ($dn) or $attr must have been removed from user before this is called.
  3588. */
  3589. static int
  3590. acllas_eval_one_user( struct acl_pblock *aclpb, char * clientDN, char *rule) {
  3591. int exact_match = 0;
  3592. const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
  3593. /* URL format */
  3594. if (strchr (rule, '?') != NULL) {
  3595. /* URL format */
  3596. if (acllas__client_match_URL ( aclpb, clientDN,
  3597. rule) == ACL_TRUE) {
  3598. exact_match = 1;
  3599. }
  3600. } else if ( strstr(rule, "=*") == NULL ) {
  3601. /* Just a straight compare */
  3602. /* skip the ldap:/// part */
  3603. rule += LDAP_URL_prefix_len;
  3604. exact_match = !slapi_utf8casecmp((ACLUCHP)clientDN,
  3605. (ACLUCHP)rule);
  3606. } else{
  3607. /* Here, contains a =*, so need to match comp by comp */
  3608. /* skip the ldap:/// part */
  3609. rule += LDAP_URL_prefix_len;
  3610. acl_match_prefix( rule, clientDN, &exact_match);
  3611. }
  3612. if ( exact_match) {
  3613. return( ACL_TRUE);
  3614. } else {
  3615. return(ACL_FALSE);
  3616. }
  3617. }
  3618. /*
  3619. * returns ACL_TRUE, ACL_FALSE and ACL_DONT_KNOW.
  3620. *
  3621. * The user string has had all ($dn) and $attr replaced
  3622. * so the only dodgy thing left is a *.
  3623. *
  3624. * If * appears in such a user string, then it matches only that
  3625. * component, not .*, like it would otherwise.
  3626. *
  3627. */
  3628. static int
  3629. acllas_eval_one_group(char *groupbuf, lasInfo *lasinfo) {
  3630. if (groupbuf) {
  3631. return( acllas__user_ismember_of_group (
  3632. lasinfo->aclpb,
  3633. groupbuf,
  3634. lasinfo->clientDn,
  3635. ACLLAS_CACHE_ALL_GROUPS,
  3636. lasinfo->aclpb->aclpb_clientcert
  3637. ));
  3638. } else {
  3639. return(ACL_FALSE); /* not in the empty group */
  3640. }
  3641. }
  3642. /*
  3643. * returns ACL_TRUE for match, ACL_FALSE for not a match, ACL_DONT_KNOW otherwise.
  3644. */
  3645. static int
  3646. acllas_eval_one_role(char *role, lasInfo *lasinfo) {
  3647. Slapi_DN *roleDN = NULL;
  3648. int rc = ACL_FALSE;
  3649. char ebuf [ BUFSIZ ];
  3650. /*
  3651. * See if lasinfo.clientDn has role rolebuf.
  3652. * Here we know it's not an anom user nor
  3653. * a an anyone user--the client dn must be matched against
  3654. * a real role.
  3655. */
  3656. roleDN = slapi_sdn_new_dn_byval(role);
  3657. if (role) {
  3658. rc = acllas__user_has_role(
  3659. lasinfo->aclpb,
  3660. roleDN,
  3661. lasinfo->aclpb->aclpb_authorization_sdn);
  3662. } else { /* The user does not have the empty role */
  3663. rc = ACL_FALSE;
  3664. }
  3665. slapi_sdn_free(&roleDN );
  3666. /* Some useful logging */
  3667. if (rc == ACL_TRUE ) {
  3668. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3669. "role evaluation: user '%s' does have role '%s'\n",
  3670. ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo->clientDn, ebuf),
  3671. role);
  3672. } else {
  3673. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  3674. "role evaluation: user '%s' does NOT have role '%s'\n",
  3675. ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo->clientDn, ebuf),
  3676. role);
  3677. }
  3678. return(rc);
  3679. }
  3680. /*
  3681. * returns ACL_TRUE if e matches the filter str, ACL_FALSE if not,
  3682. * ACL_DONT_KNOW otherwise.
  3683. */
  3684. static int acllas_eval_one_target_filter( char * str, Slapi_Entry *e) {
  3685. int rc = ACL_FALSE;
  3686. Slapi_Filter *f = NULL;
  3687. PR_ASSERT(str);
  3688. if ((f = slapi_str2filter(str)) == NULL) {
  3689. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  3690. "Warning: Bad targetfilter(%s) in aci: does not match\n", str);
  3691. return(ACL_DONT_KNOW);
  3692. }
  3693. if (slapi_vattr_filter_test(NULL, e, f, 0 /*don't do acess chk*/)!= 0) {
  3694. rc = ACL_FALSE; /* Filter does not match */
  3695. } else {
  3696. rc = ACL_TRUE; /* filter does match */
  3697. }
  3698. slapi_filter_free(f, 1);
  3699. return(rc);
  3700. }
  3701. /***************************************************************************/
  3702. /* E N D */
  3703. /***************************************************************************/