1/*
2 * load the sasl plugins
3 * $Id: mac_dyn_dlopen.c,v 1.4 2005/01/10 19:09:04 snsimon 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 */
67struct 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};
78typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderPtrHand;
79
80/*
81 * The below structure defines a cfrag item within the cfrag resource.
82 */
83struct 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};
99typedef 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
114typedef struct lib_list
115{
116    struct lib_list *next;
117    void *library;
118} lib_list_t;
119
120static lib_list_t *lib_list_head = NULL;
121
122/*
123 * add the passed extension
124 */
125int _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
156int _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
194static 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 */
216int _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 */
228int _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 */
277int _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
306int
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}
322