File: Search.hsc

package info (click to toggle)
ldap-haskell 0.6.11-6
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 164 kB
  • sloc: haskell: 83; ansic: 34; makefile: 2
file content (169 lines) | stat: -rw-r--r-- 5,923 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
{- -*- Mode: haskell; -*-
Haskell LDAP Interface
Copyright (C) 2005 John Goerzen <jgoerzen@complete.org>

This code is under a 3-clause BSD license; see COPYING for details.
-}

{- |
   Module     : LDAP.Search
   Copyright  : Copyright (C) 2005 John Goerzen
   License    : BSD

   Maintainer : John Goerzen,
   Maintainer : jgoerzen\@complete.org
   Stability  : provisional
   Portability: portable

LDAP Searching

Written by John Goerzen, jgoerzen\@complete.org
-}

module LDAP.Search (SearchAttributes(..),
                    LDAPEntry(..), LDAPScope(..),
                    ldapSearch, 
                   )
where

import LDAP.Utils
import LDAP.Types
import LDAP.TypesLL
import LDAP.Data
import Foreign
import Foreign.C.String
#if (__GLASGOW_HASKELL__>=705)
import Foreign.C.Types(CInt(..))
#endif
import LDAP.Result
import Control.Exception(finally)

#include <ldap.h>

{- | Defines what attributes to return with the search result. -}
data SearchAttributes =
   LDAPNoAttrs                   -- ^ No attributes
 | LDAPAllUserAttrs              -- ^ User attributes only
 | LDAPAttrList [String]         -- ^ User-specified list
   deriving (Eq, Show)

sa2sl :: SearchAttributes -> [String]
sa2sl LDAPNoAttrs = [ #{const_str LDAP_NO_ATTRS} ]
sa2sl LDAPAllUserAttrs = [ #{const_str LDAP_ALL_USER_ATTRIBUTES} ]
sa2sl (LDAPAttrList x) = x

data LDAPEntry = LDAPEntry 
    {ledn :: String             -- ^ Distinguished Name of this object
    ,leattrs :: [(String, [String])] -- ^ Mapping from attribute name to values
                           }
    deriving (Eq, Show)

ldapSearch :: LDAP              -- ^ LDAP connection object
           -> Maybe String      -- ^ Base DN for search, if any
           -> LDAPScope         -- ^ Scope of the search
           -> Maybe String      -- ^ Filter to be used (none if Nothing)
           -> SearchAttributes  -- ^ Desired attributes in result set
           -> Bool              -- ^ If True, exclude attribute values (return types only)
           -> IO [LDAPEntry]

ldapSearch ld base scope filter attrs attrsonly =
  withLDAPPtr ld (\cld ->
  withMString base (\cbase ->
  withMString filter (\cfilter ->
  withCStringArr0 (sa2sl attrs) (\cattrs ->
  do msgid <- checkLEn1 "ldapSearch" ld $
              ldap_search cld cbase (fromIntegral $ fromEnum scope)
                          cfilter cattrs (fromBool attrsonly)
     procSR ld cld msgid
                               )
                      )
                    )
                  )

procSR :: LDAP -> Ptr CLDAP -> LDAPInt -> IO [LDAPEntry]
procSR ld cld msgid =
  do res1 <- ldap_1result ld msgid
     --putStrLn "Have 1result"
     withForeignPtr res1 (\cres1 ->
      do felm <- ldap_first_entry cld cres1
         if felm == nullPtr
            then return []
            else do --putStrLn "Have first entry"
                    cdn <- ldap_get_dn cld felm -- FIXME: check null
                    dn <- peekCString cdn
                    ldap_memfree cdn
                    attrs <- getattrs ld felm
                    next <- procSR ld cld msgid
                    --putStrLn $ "Next is " ++ (show next)
                    return $ (LDAPEntry {ledn = dn, leattrs = attrs}):next
                         )
      


data BerElement

getattrs :: LDAP -> (Ptr CLDAPMessage) -> IO [(String, [String])]
getattrs ld lmptr =
    withLDAPPtr ld (\cld -> alloca (f cld))
    where f cld (ptr::Ptr (Ptr BerElement)) =
              do cstr <- ldap_first_attribute cld lmptr ptr
                 if cstr == nullPtr
                    then return []
                    else do str <- peekCString cstr
                            ldap_memfree cstr
                            bptr <- peek ptr
                            values <- getvalues cld lmptr str
                            nextitems <- getnextitems cld lmptr bptr
                            return $ (str, values):nextitems

getnextitems :: Ptr CLDAP -> Ptr CLDAPMessage -> Ptr BerElement 
             -> IO [(String, [String])]
getnextitems cld lmptr bptr =
    do cstr <- ldap_next_attribute cld lmptr bptr
       if cstr == nullPtr
          then return []
          else do str <- peekCString cstr
                  ldap_memfree cstr
                  values <- getvalues cld lmptr str
                  nextitems <- getnextitems cld lmptr bptr
                  return $ (str, values):nextitems

getvalues :: LDAPPtr -> Ptr CLDAPMessage -> String -> IO [String]
getvalues cld clm attr =
    withCString attr (\cattr ->
    do berarr <- ldap_get_values_len cld clm cattr
       if berarr == nullPtr
            -- Work around bug between Fedora DS and OpenLDAP (ldapvi
            -- does the same thing)
            then return []
            else finally (procberarr berarr) (ldap_value_free_len berarr)
    )

procberarr :: Ptr (Ptr Berval) -> IO [String]
procberarr pbv =
    do bvl <- peekArray0 nullPtr pbv
       mapM bv2str bvl

foreign import ccall unsafe "ldap.h ldap_get_dn"
  ldap_get_dn :: LDAPPtr -> Ptr CLDAPMessage -> IO CString

foreign import ccall unsafe "ldap.h ldap_get_values_len"
  ldap_get_values_len :: LDAPPtr -> Ptr CLDAPMessage -> CString -> IO (Ptr (Ptr Berval))

foreign import ccall unsafe "ldap.h ldap_value_free_len"
  ldap_value_free_len :: Ptr (Ptr Berval) -> IO ()

foreign import ccall safe "ldap.h ldap_search"
  ldap_search :: LDAPPtr -> CString -> LDAPInt -> CString -> Ptr CString ->
                 LDAPInt -> IO LDAPInt

foreign import ccall unsafe "ldap.h ldap_first_entry"
  ldap_first_entry :: LDAPPtr -> Ptr CLDAPMessage -> IO (Ptr CLDAPMessage)

foreign import ccall unsafe "ldap.h ldap_first_attribute"
  ldap_first_attribute :: LDAPPtr -> Ptr CLDAPMessage -> Ptr (Ptr BerElement) 
                       -> IO CString

foreign import ccall unsafe "ldap.h ldap_next_attribute"
  ldap_next_attribute :: LDAPPtr -> Ptr CLDAPMessage -> Ptr BerElement
                       -> IO CString