]> git.saurik.com Git - apple/security.git/blob - CrlRefresh/ldapFetch.cpp
Security-177.tar.gz
[apple/security.git] / CrlRefresh / ldapFetch.cpp
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