]>
Commit | Line | Data |
---|---|---|
df0e469f A |
1 | /* |
2 | * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please | |
7 | * obtain a copy of the License at http://www.apple.com/publicsource and | |
8 | * read it before using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
12 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
13 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
14 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
15 | * Please see the License for the specific language governing rights and | |
16 | * limitations under the License. | |
17 | */ | |
18 | ||
19 | /* | |
20 | * ldapFetch.cpp - fetch an entity via LDAP | |
21 | */ | |
22 | ||
23 | #include "ldapFetch.h" | |
24 | #include <LDAP/ldap.h> | |
25 | #include <Security/cssmapple.h> | |
26 | #include <stdlib.h> | |
27 | #include <stdio.h> | |
28 | #include <string.h> | |
29 | #include <CoreFoundation/CoreFoundation.h> | |
30 | ||
31 | #define DEBUG_PRINT 1 | |
32 | #if DEBUG_PRINT | |
33 | #define dprintf(args...) printf(args) | |
34 | #else | |
35 | #define dprintf(args...) | |
36 | #endif | |
37 | ||
38 | /* | |
39 | * LDAP attribute names, used if not present in URI. | |
40 | */ | |
41 | #define LDAP_ATTR_CERT "cacertificate;binary" | |
42 | #define LDAP_ATTR_CRL "certificaterevocationlist;binary" | |
43 | ||
44 | /* | |
45 | * Default LDAP options. | |
46 | */ | |
47 | #define LDAP_REFERRAL_DEFAULT LDAP_OPT_ON | |
48 | ||
49 | static CSSM_RETURN ldapRtnToCssm( | |
50 | int rtn) | |
51 | { | |
52 | switch(rtn) { | |
53 | case LDAP_SERVER_DOWN: | |
54 | case LDAP_TIMEOUT: | |
55 | case LDAP_CONNECT_ERROR: | |
56 | return CSSMERR_APPLETP_CRL_SERVER_DOWN; | |
57 | case LDAP_PARAM_ERROR: | |
58 | case LDAP_FILTER_ERROR: | |
59 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
60 | default: | |
61 | return CSSMERR_APPLETP_CRL_NOT_FOUND; | |
62 | } | |
63 | } | |
64 | ||
65 | CSSM_RETURN ldapFetch( | |
66 | const CSSM_DATA &url, | |
67 | LF_Type lfType, | |
68 | CSSM_DATA &fetched) // mallocd and RETURNED | |
69 | { | |
70 | BerValue **value = NULL; | |
71 | LDAPURLDesc *urlDesc = NULL; | |
72 | int rtn; | |
73 | LDAPMessage *msg = NULL; | |
74 | LDAP *ldap = NULL; | |
75 | LDAPMessage *entry = NULL; | |
76 | bool mallocdString = false; | |
77 | char *urlStr; | |
78 | int numEntries; | |
79 | CSSM_RETURN ourRtn = CSSM_OK; | |
80 | /* attr input to ldap_search_s() */ | |
81 | char *attrArray[2]; | |
82 | char **attrArrayP = NULL; | |
83 | ||
84 | /* don't assume URL string is NULL terminated */ | |
85 | if(url.Data[url.Length - 1] == '\0') { | |
86 | urlStr = (char *)url.Data; | |
87 | } | |
88 | else { | |
89 | urlStr = (char *)malloc(url.Length + 1); | |
90 | memmove(urlStr, url.Data, url.Length); | |
91 | urlStr[url.Length] = '\0'; | |
92 | mallocdString = true; | |
93 | } | |
94 | ||
95 | /* break up the URL into something usable */ | |
96 | rtn = ldap_url_parse(urlStr, &urlDesc); | |
97 | if(rtn) { | |
98 | dprintf("ldap_url_parse returned %d", rtn); | |
99 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
100 | } | |
101 | ||
102 | /* | |
103 | * Determine what attr we're looking for. | |
104 | */ | |
105 | if((urlDesc->lud_attrs != NULL) && // attrs present in URL | |
106 | (urlDesc->lud_attrs[0] != NULL) && // at least one attr present | |
107 | (urlDesc->lud_attrs[1] == NULL)) { | |
108 | /* | |
109 | * Exactly one attr present in the caller-specified URL; | |
110 | * assume that this is exactly what we want. | |
111 | */ | |
112 | attrArrayP = &urlDesc->lud_attrs[0]; | |
113 | } | |
114 | else { | |
115 | /* use caller-specified attr */ | |
116 | switch(lfType) { | |
117 | case LT_Crl: | |
118 | attrArray[0] = (char *)LDAP_ATTR_CRL; | |
119 | break; | |
120 | case LT_Cert: | |
121 | attrArray[0] = (char *)LDAP_ATTR_CERT; | |
122 | break; | |
123 | default: | |
124 | printf("***ldapFetch screwup: bogus lfType (%d)\n", | |
125 | (int)lfType); | |
126 | return CSSMERR_CSSM_INTERNAL_ERROR; | |
127 | } | |
128 | attrArray[1] = NULL; | |
129 | attrArrayP = &attrArray[0]; | |
130 | } | |
131 | ||
132 | /* establish connection */ | |
133 | rtn = ldap_initialize(&ldap, urlStr); | |
134 | if(rtn) { | |
135 | dprintf("ldap_initialize returned %d\n", rtn); | |
136 | return ldapRtnToCssm(rtn); | |
137 | } | |
138 | /* subsequent errors to cleanup: */ | |
139 | rtn = ldap_simple_bind_s(ldap, NULL, NULL); | |
140 | if(rtn) { | |
141 | dprintf("ldap_simple_bind_s returned %d\n", rtn); | |
142 | ourRtn = ldapRtnToCssm(rtn); | |
143 | goto cleanup; | |
144 | } | |
145 | ||
146 | rtn = ldap_set_option(ldap, LDAP_OPT_REFERRALS, LDAP_REFERRAL_DEFAULT); | |
147 | if(rtn) { | |
148 | dprintf("ldap_set_option(referrals) returned %d\n", rtn); | |
149 | ourRtn = ldapRtnToCssm(rtn); | |
150 | goto cleanup; | |
151 | } | |
152 | ||
153 | rtn = ldap_search_s( | |
154 | ldap, | |
155 | urlDesc->lud_dn, | |
156 | LDAP_SCOPE_SUBTREE, | |
157 | urlDesc->lud_filter, | |
158 | urlDesc->lud_attrs, | |
159 | 0, // attrsonly | |
160 | &msg); | |
161 | if(rtn) { | |
162 | dprintf("ldap_search_s returned %d\n", rtn); | |
163 | ourRtn = ldapRtnToCssm(rtn); | |
164 | goto cleanup; | |
165 | } | |
166 | ||
167 | /* | |
168 | * We require exactly one entry (for now). | |
169 | */ | |
170 | numEntries = ldap_count_entries(ldap, msg); | |
171 | if(numEntries != 1) { | |
172 | dprintf("tpCrlViaLdap: numEntries %d\n", numEntries); | |
173 | ourRtn = CSSMERR_APPLETP_CRL_NOT_FOUND; | |
174 | goto cleanup; | |
175 | } | |
176 | ||
177 | entry = ldap_first_entry(ldap, msg); | |
178 | value = ldap_get_values_len(ldap, msg, attrArrayP[0]); | |
179 | if(value == NULL) { | |
180 | dprintf("Error on ldap_get_values_len\n"); | |
181 | ourRtn = CSSMERR_APPLETP_CRL_NOT_FOUND; | |
182 | goto cleanup; | |
183 | } | |
184 | ||
185 | fetched.Length = value[0]->bv_len; | |
186 | fetched.Data = (uint8 *)malloc(fetched.Length); | |
187 | memmove(fetched.Data, value[0]->bv_val, fetched.Length); | |
188 | ||
189 | ldap_value_free_len(value); | |
190 | ourRtn = CSSM_OK; | |
191 | cleanup: | |
192 | if(msg) { | |
193 | ldap_msgfree(msg); | |
194 | } | |
195 | if(mallocdString) { | |
196 | free(urlStr); | |
197 | } | |
198 | ldap_free_urldesc(urlDesc); | |
199 | rtn = ldap_unbind(ldap); | |
200 | if(rtn) { | |
201 | dprintf("Error %d on ldap_unbind\n", rtn); | |
202 | /* oh well */ | |
203 | } | |
204 | return ourRtn; | |
205 | } | |
206 | ||
207 | /* fetch via HTTP */ | |
208 | CSSM_RETURN httpFetch( | |
209 | const CSSM_DATA &url, | |
210 | CSSM_DATA &fetched) // mallocd and RETURNED | |
211 | { | |
212 | /* trim off possible NULL terminator */ | |
213 | CSSM_DATA theUrl = url; | |
214 | if(theUrl.Data[theUrl.Length - 1] == '\0') { | |
215 | theUrl.Length--; | |
216 | } | |
217 | CFURLRef cfUrl = CFURLCreateWithBytes(NULL, | |
218 | theUrl.Data, theUrl.Length, | |
219 | kCFStringEncodingUTF8, // right? | |
220 | //kCFStringEncodingASCII, // right? | |
221 | NULL); // this is absolute path | |
222 | if(cfUrl == NULL) { | |
223 | dprintf("CFURLCreateWithBytes returned NULL\n"); | |
224 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
225 | } | |
226 | CFDataRef urlData = NULL; | |
227 | SInt32 errorCode; | |
228 | Boolean brtn = CFURLCreateDataAndPropertiesFromResource(NULL, | |
229 | cfUrl, | |
230 | &urlData, | |
231 | NULL, // no properties | |
232 | NULL, | |
233 | &errorCode); | |
234 | CFRelease(cfUrl); | |
235 | if(!brtn) { | |
236 | dprintf("CFURLCreateDataAndPropertiesFromResource err: %d\n", | |
237 | (int)errorCode); | |
238 | if(urlData) { | |
239 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
240 | } | |
241 | } | |
242 | if(urlData == NULL) { | |
243 | dprintf("CFURLCreateDataAndPropertiesFromResource: no data\n"); | |
244 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
245 | } | |
246 | CFIndex len = CFDataGetLength(urlData); | |
247 | fetched.Data = (uint8 *)malloc(len); | |
248 | fetched.Length = len; | |
249 | memmove(fetched.Data, CFDataGetBytePtr(urlData), len); | |
250 | CFRelease(urlData); | |
251 | return CSSM_OK; | |
252 | } | |
253 | ||
254 | /* Fetch from net, we figure out the schema */ | |
255 | CSSM_RETURN netFetch( | |
256 | const CSSM_DATA &url, | |
257 | LF_Type lfType, | |
258 | CSSM_DATA &fetched) // mallocd and RETURNED | |
259 | { | |
260 | if(url.Length < 5) { | |
261 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
262 | } | |
263 | if(!strncmp((char *)url.Data, "ldap:", 5)) { | |
264 | return ldapFetch(url, lfType, fetched); | |
265 | } | |
266 | if(!strncmp((char *)url.Data, "http:", 5) || | |
267 | !strncmp((char *)url.Data, "https:", 6)) { | |
268 | return httpFetch(url, fetched); | |
269 | } | |
270 | return CSSMERR_APPLETP_CRL_BAD_URI; | |
271 | } | |
272 |