import cyrus-sasl-2.1.23
[cyrus-sasl.git] / mac / mac_lib / mac_dyn_dlopen.c
1 /*
2  * load the sasl plugins
3  * $Id: mac_dyn_dlopen.c,v 1.3 2003/02/13 19:55:59 rjs3 Exp $
4  */
5 /* 
6  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The name "Carnegie Mellon University" must not be used to
21  *    endorse or promote products derived from this software without
22  *    prior written permission. For permission or any other legal
23  *    details, please contact  
24  *      Office of Technology Transfer
25  *      Carnegie Mellon University
26  *      5000 Forbes Avenue
27  *      Pittsburgh, PA  15213-3890
28  *      (412) 268-4387, fax: (412) 268-7395
29  *      tech-transfer@andrew.cmu.edu
30  *
31  * 4. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by Computing Services
34  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35  *
36  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43  */
44
45
46 #include <config.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sasl.h>
50 #include "saslint.h"
51
52 #include <CodeFragments.h>
53 #include <Errors.h>
54 #include <Resources.h>
55 #include <Strings.h>
56 #include <Folders.h>
57
58 #ifdef RUBBISH
59 #include <FSpCompat.h>
60 #endif
61
62 /*
63  * The following data structure defines the structure of a code fragment
64  * resource.  We can cast the resource to be of this type to access
65  * any fields we need to see.
66  */
67 struct CfrgHeader {
68     long        res1;
69     long        res2;
70     long        version;
71     long        res3;
72     long        res4;
73     long        filler1;
74     long        filler2;
75     long        itemCount;
76     char        arrayStart;     /* Array of externalItems begins here. */
77 };
78 typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderPtrHand;
79
80 /*
81  * The below structure defines a cfrag item within the cfrag resource.
82  */
83 struct CfrgItem {
84     OSType      archType;
85     long        updateLevel;
86     long        currVersion;
87     long        oldDefVersion;
88     long        appStackSize;
89     short       appSubFolder;
90     char        usage;
91     char        location;
92     long        codeOffset;
93     long        codeLength;
94     long        res1;
95     long        res2;
96     short       itemSize;
97     Str255      name;           /* This is actually variable sized. */
98 };
99 typedef struct CfrgItem CfrgItem;
100
101 #ifndef TRUE
102 #define TRUE 1
103 #endif
104 #ifndef FALSE
105 #define FALSE 0
106 #endif
107
108 #if TARGET_API_MAC_CARBON
109 #define SASL_PLUGIN_DIR "\p:sasl v2:carbon:biff"
110 #else
111 #define SASL_PLUGIN_DIR "\p:sasl v2:biff"
112 #endif
113
114 typedef struct lib_list 
115 {
116     struct lib_list *next;
117     void *library;
118 } lib_list_t;
119
120 static lib_list_t *lib_list_head = NULL;
121
122 /*
123  * add the passed extension
124  */
125 int _macsasl_get_fsspec(FSSpec *fspec,
126         void **libraryptr)
127 {
128         int rc;
129     CFragConnectionID connID;
130     Ptr dummy;
131     unsigned long offset = 0;
132     unsigned long length = kCFragGoesToEOF;
133     unsigned char package_name[255];
134         Str255 error_text;
135         lib_list_t *newhead;
136
137     newhead = sasl_ALLOC(sizeof(lib_list_t));
138     if(!newhead) return SASL_NOMEM;
139
140         package_name[0] = 0;
141     rc=GetDiskFragment(fspec,offset,length,package_name,
142             kLoadCFrag,&connID,&dummy,error_text);
143         if(rc!=0) {
144                 sasl_FREE(newhead);
145                 return rc;
146         }
147
148     newhead->library = (void *)connID;
149     newhead->next = lib_list_head;
150     lib_list_head = newhead;
151
152     *libraryptr = (void *)connID;
153     return SASL_OK;
154 }
155
156 int _sasl_locate_entry(void *library, const char *entryname,
157                        void **entry_point) 
158 {
159         int result;
160 #if TARGET_API_MAC_CARBON
161     char cstr[256];
162 #endif
163         Str255 pentry;
164     CFragSymbolClass symClass;
165     OSErr rc;
166
167     if(!entryname) {
168         return SASL_BADPARAM;
169     }
170
171     if(!library) {
172         return SASL_BADPARAM;
173     }
174
175     if(!entry_point) {
176         return SASL_BADPARAM;
177     }
178
179 #if TARGET_API_MAC_CARBON
180         strcpy(cstr,entryname);
181     CopyCStringToPascal(cstr, pentry);
182 #else
183         strcpy(pentry,entryname);
184     c2pstr(pentry);
185 #endif
186
187     rc = FindSymbol((CFragConnectionID)library,pentry,entry_point, &symClass);
188     if ((rc!=noErr) || (symClass==kDataCFragSymbol))
189         return SASL_FAIL;
190
191         return SASL_OK;
192 }
193
194 static int _sasl_plugin_load(char *plugin, void *library,
195                              const char *entryname,
196                              int (*add_plugin)(const char *, void *)) 
197 {
198     void *entry_point;
199     int result;
200     
201     result = _sasl_locate_entry(library, entryname, &entry_point);
202     if(result == SASL_OK) {
203         result = add_plugin(plugin, entry_point);
204 //      if(result != SASL_OK)
205 //          _sasl_log(NULL, SASL_LOG_ERR,
206 //                    "_sasl_plugin_load failed on %s for plugin: %s\n",
207 //                    entryname, plugin);
208     }
209
210     return result;
211 }
212
213 /*
214  * does the passed string a occur and the end of string b?
215  */
216 int _macsasl_ends_in(char *a, char *b)
217 {
218         int alen=strlen(a);
219         int blen=strlen(b);
220         if(blen<alen)
221                 return FALSE;
222         return (memcmp(a,b+(blen-alen),alen)==0);
223 }
224
225 /*
226  * scan the passed directory loading sasl extensions
227  */
228 int _macsasl_find_extensions_in_dir(short vref,long dir_id,
229         const add_plugin_list_t *entrypoints)
230 {
231         CInfoPBRec cinfo;
232         unsigned char aname[300];
233         char plugname[256];
234         int findex=0;
235         FSSpec a_plugin;
236         lib_list_t *library;
237         char *c;
238         const add_plugin_list_t *cur_ep;
239
240         while(TRUE) {
241                 int os;
242                 memset(&cinfo,0,sizeof(cinfo));
243                 aname[0] = 0;
244                 cinfo.hFileInfo.ioVRefNum=vref;
245                 cinfo.hFileInfo.ioNamePtr=aname;
246                 cinfo.hFileInfo.ioFDirIndex=findex++;
247                 cinfo.hFileInfo.ioDirID=dir_id;
248                 os=PBGetCatInfo(&cinfo,FALSE);
249                 if(os!=0)
250                         return SASL_OK;
251                 aname[aname[0]+1] = 0;
252
253                 /* skip over non shlb files */
254                 if(!_macsasl_ends_in(".shlb",aname+1))
255                         continue;
256                 os=FSMakeFSSpec(vref,dir_id,aname,&a_plugin);
257                 if(os!=0)
258                         continue;
259
260                 /* skip "lib" and cut off suffix --
261                    this only need be approximate */
262                 strcpy(plugname, aname + 1);
263                 c = strchr(plugname, (int)'.');
264                 if(c) *c = '\0';
265
266                 if (!_macsasl_get_fsspec(&a_plugin,&library))
267                         for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
268                                 _sasl_plugin_load(plugname, library, cur_ep->entryname,
269                                                   cur_ep->add_plugin);
270                                 /* If this fails, it's not the end of the world */
271                         }
272         }
273         return SASL_OK;
274 }
275
276 /* gets the list of mechanisms */
277 int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
278                         const sasl_callback_t *getpath_cb,
279                         const sasl_callback_t *verifyfile_cb)
280 {
281         int rc;
282         short extensions_vref;
283         long extensions_dirid;
284         FSSpec sasl_dir;
285         /* find the extensions folder */
286         rc=FindFolder(kOnSystemDisk,kExtensionFolderType,FALSE,
287                 &extensions_vref,&extensions_dirid);
288         if(rc!=0)
289                 return SASL_BADPARAM;
290         rc=FSMakeFSSpec(extensions_vref,extensions_dirid,SASL_PLUGIN_DIR,&sasl_dir);
291         /*
292          * if a plugin named biff exits or not we really dont care
293          * if it does get rc 0 if it does not get -43 (fnfErr)
294          * if the sasl dir doesnt exist we get -120 (dirNFFErr)
295          */
296         if((rc!=0)&&(rc!=fnfErr))
297                 return SASL_BADPARAM;
298         /*
299          * now extensions_vref is volume
300          * sasl_dir.parID is dirid for sasl plugins folder
301          */
302         
303         return _macsasl_find_extensions_in_dir(extensions_vref,sasl_dir.parID,entrypoints);
304 }
305
306 int
307 _sasl_done_with_plugins(void)
308 {
309     lib_list_t *libptr, *libptr_next;
310     
311     for(libptr = lib_list_head; libptr; libptr = libptr_next) {
312         libptr_next = libptr->next;
313         if(libptr->library)
314             CloseConnection((CFragConnectionID*)&libptr->library);
315         sasl_FREE(libptr);
316     }
317
318     lib_list_head = NULL;
319
320     return SASL_OK;
321 }