1 /*******************************************************************************
5 ** $XConsortium: dtfns.c /main/3 1995/11/03 10:37:35 rswiston $
7 ** RESTRICTED CONFIDENTIAL INFORMATION:
9 ** The information in this document is subject to special
10 ** restrictions in a confidential disclosure agreement between
11 ** HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
12 ** document outside HP, IBM, Sun, USL, SCO, or Univel without
13 ** Sun's specific written approval. This document and all copies
14 ** and derivative works thereof must be returned or destroyed at
17 ** Copyright 1993 Sun Microsystems, Inc. All rights reserved.
19 *******************************************************************************/
22 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
23 * (c) Copyright 1993, 1994 International Business Machines Corp. *
24 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
25 * (c) Copyright 1993, 1994 Novell, Inc. *
30 static char sccsid[] = "@(#)dtfns.c 1.3 94/11/07 Copyr 1993 Sun Microsystems, Inc.";
34 * Copyright 1993 Sun Microsystems, Inc. All rights reserved
39 #include <EUSCompat.h>
43 #include <sys/types.h>
49 #include <rpcsvc/nis.h>
50 #include <rpcsvc/nislib.h>
51 #include <rpcsvc/ypclnt.h>
63 extern char *strdup(const char *);
66 * Names found in the initial context. Used by isa_helix_name()
68 * XXX We have a bug here. If a string happens to start with
69 * thisuser, myorg, etc we'll recognize it as an FNS name even
70 * though it may not be one.
72 static char *initial_context_names[] = {
82 static void *libfns_handle = NULL;
83 static int initialized = 0;
84 static NS_Context_t *initial_ctx = NULL;
87 * These are dynamically bound entry points into libfns. We dlopen()
88 * libfns so that cm can still run even if libfns does not exist
90 static NS_Context_t *(*NS_Context_get_initial_p)(NS_ContextStatus_t *);
91 static NS_ContextStatus_t *(*NS_ContextStatus_new_p)(void);
92 static void (*NS_ContextStatus_delete_p)(NS_ContextStatus_t *);
93 static NS_Reference_t *(*NS_Context_lookup_p)(const NS_Context_t *,
94 const NS_CompositeName_t *,
95 NS_ContextStatus_t *);
96 static int (*NS_Context_bind_p)(const NS_Context_t *,
97 const NS_CompositeName_t *,
98 const NS_Reference_t *,
100 NS_ContextStatus_t *);
102 static NS_Reference_t *(*NS_Reference_new_p)(const NS_String_t *);
103 static void (*NS_Reference_delete_p)(const NS_Reference_t *);
104 static NS_String_t *(*NS_Reference_type_p)(const NS_Reference_t *);
105 static int (*NS_Reference_count_p)(const NS_Reference_t *);
106 static NS_ReferenceAddress_t *(*NS_Reference_first_p)(const NS_Reference_t *,
108 static NS_ReferenceAddress_t *(*NS_Reference_next_p)(const NS_Reference_t *,
110 static int (*NS_Reference_append_addr_p)(NS_Reference_t *,
111 const NS_ReferenceAddress_t *);
112 static int (*NS_Reference_prepend_addr_p)(NS_Reference_t *,
113 const NS_ReferenceAddress_t *);
114 static int (*NS_Reference_insert_addr_p)(NS_Reference_t *,
116 const NS_ReferenceAddress_t *);
117 static int (*NS_Reference_delete_addr_p)(NS_Reference_t *,
119 static void (*NS_ReferenceAddress_delete_p)(
120 NS_ReferenceAddress_t *);
122 static NS_ReferenceAddress_t *(*NS_ReferenceAddress_new_p)(const NS_String_t *,
125 static void * (*NS_ReferenceAddress_data_p)(const NS_ReferenceAddress_t *);
126 static unsigned (*NS_ReferenceAddress_length_p)(const NS_ReferenceAddress_t *);
127 static NS_String_t *(*NS_ReferenceAddress_type_p)(const NS_ReferenceAddress_t*);
130 static const char * (*NS_String_cstring_p)(const NS_String_t *);
131 static NS_String_t * (*NS_String_from_cstring_p)(const char *);
132 static NS_CompositeName_t * (*NS_CompositeName_from_cstring_p)(const char *);
135 static int get_helix_service_name(const char *name, const char *service,
136 const char *service_type, char **buf);
140 * Load libfns (with dlopen) and bind in the entry points we use (with dlsym).
142 * We dynamically load the FNS library so that we don't have an explicit
143 * dependency on it. This lets us run on systems which do not have FNS
147 * 0 FNS not available
154 char *libfns = FNS_LIBRARY;
157 if (libfns_handle != NULL) {
163 libfns_handle = dlopen(libfns, RTLD_LAZY);
164 if (libfns_handle == NULL) {
168 DP(("Could not dlopen %s\n", libfns));
170 DP(("Could not dlopen %s: %s\n", libfns, s));
176 NS_Context_get_initial_p = (NS_Context_t *(*)(NS_ContextStatus_t *))
177 dlsym(libfns_handle, "NS_Context_get_initial");
179 NS_ContextStatus_new_p = (NS_ContextStatus_t *(*)(void))
180 dlsym(libfns_handle, "NS_ContextStatus_new");
181 NS_ContextStatus_delete_p = (void(*)(NS_ContextStatus_t *))
182 dlsym(libfns_handle, "NS_ContextStatus_delete");
184 NS_Context_lookup_p = (NS_Reference_t *(*)(const NS_Context_t *,
185 const NS_CompositeName_t *,
186 NS_ContextStatus_t *))
187 dlsym(libfns_handle, "NS_Context_lookup");
189 NS_Context_bind_p = (int(*)(const NS_Context_t *,
190 const NS_CompositeName_t *,
191 const NS_Reference_t *,
193 NS_ContextStatus_t *))
194 dlsym(libfns_handle, "NS_Context_bind");
196 NS_Reference_new_p = (NS_Reference_t *(*)(const NS_String_t *))
197 dlsym(libfns_handle, "NS_Reference_new");
198 NS_Reference_delete_p = (void(*)(const NS_Reference_t *))
199 dlsym(libfns_handle, "NS_Reference_delete");;
201 NS_Reference_type_p = (NS_String_t *(*)(const NS_Reference_t *))
202 dlsym(libfns_handle, "NS_Reference_type");
204 NS_Reference_count_p = (int(*)(const NS_Reference_t *))
205 dlsym(libfns_handle, "NS_Reference_count");
207 NS_Reference_first_p = (NS_ReferenceAddress_t *(*)
208 (const NS_Reference_t *, void **))
209 dlsym(libfns_handle, "NS_Reference_first");
211 NS_Reference_next_p = (NS_ReferenceAddress_t *(*)
212 (const NS_Reference_t *, void **))
213 dlsym(libfns_handle, "NS_Reference_next");
215 NS_Reference_append_addr_p = (int(*)(NS_Reference_t *,
216 const NS_ReferenceAddress_t *))
217 dlsym(libfns_handle, "NS_Reference_append_addr");
219 NS_Reference_prepend_addr_p = (int(*)(NS_Reference_t *,
220 const NS_ReferenceAddress_t *))
221 dlsym(libfns_handle, "NS_Reference_prepend_addr");
223 NS_Reference_insert_addr_p = (int(*)(NS_Reference_t *,
225 const NS_ReferenceAddress_t *))
226 dlsym(libfns_handle, "NS_Reference_insert_addr");
228 NS_Reference_delete_addr_p = (int(*)(NS_Reference_t *, void **))
229 dlsym(libfns_handle, "NS_Reference_delete_addr");
231 NS_ReferenceAddress_delete_p = (void(*)(NS_ReferenceAddress_t *))
232 dlsym(libfns_handle, "NS_ReferenceAddress_delete");
235 NS_ReferenceAddress_new_p = (NS_ReferenceAddress_t *(*)
236 (const NS_String_t *, unsigned, const void *))
237 dlsym(libfns_handle, "NS_ReferenceAddress_new");
239 NS_ReferenceAddress_data_p = (void *(*)(const NS_ReferenceAddress_t *))
240 dlsym(libfns_handle, "NS_ReferenceAddress_data");
242 NS_ReferenceAddress_length_p = (unsigned(*)
243 (const NS_ReferenceAddress_t *))
244 dlsym(libfns_handle, "NS_ReferenceAddress_length");
246 NS_ReferenceAddress_type_p = (NS_String_t *(*)
247 (const NS_ReferenceAddress_t *))
248 dlsym(libfns_handle, "NS_ReferenceAddress_type");
250 NS_String_cstring_p = (const char *(*)(const NS_String_t *))
251 dlsym(libfns_handle, "NS_String_cstring");
253 NS_String_from_cstring_p = (NS_String_t * (*)(const char *))
254 dlsym(libfns_handle, "NS_String_from_cstring");
256 NS_CompositeName_from_cstring_p =(NS_CompositeName_t *(*)(const char *))
257 dlsym(libfns_handle, "NS_CompositeName_from_cstring");
263 * Check if FNS is available for use.
265 * You must call dfsinit() before calling this routine.
267 * First call to this routine may be costly as we get the initial context.
268 * Subsequent calls are very cheap.
271 * 1 Yes, FNS is available.
272 * 0 No, FNS is not available.
273 * -1 You haven't called dtfns_init().
276 dtfns_available(void)
279 static int available;
286 if (libfns_handle != NULL) {
289 * libfns has been dlopened. Now see if an FNS namespace
290 * is reachable by getting the initial context.
292 if (dtfns_get_initial_ctx() == NULL) {
297 } else if (initialized) {
298 /* dlopen must have failed. FNS is not installed */
309 * Get the initial context. This routine caches the initial context.
310 * The first call to this routine may be costly, be subsequent calls
314 dtfns_get_initial_ctx(void)
317 DP(("dtfns_get_initial_ctx: Getting initial context\n"));
319 if (initial_ctx == NULL) {
320 NS_ContextStatus_t * status;
322 status = (*NS_ContextStatus_new_p)();
323 initial_ctx = (*NS_Context_get_initial_p)(status);
324 (*NS_ContextStatus_delete_p)(status);
331 * Generate a full Helix name for a service.
333 * 'name' may be a relative Helix name. I.e.:
336 * smith:service:calendar
337 * In this case dtfns_service_name() will use the type, service and org
338 * parameters (if needed) to construct the full Helix name.
340 * 'name' may also be an absolute Helix name. I.e.:
342 * org:ssi.eng:user:smith
344 * In this case dtfns_service_name() will use the type and service
345 * parameters (if needed) to construct the full Helix name. The org
346 * parameter should be NULL (since the organization is already
347 * determined by the absolute Helix name).
349 * 'type' specifies the type of object 'name' refers to (ie "user").
351 * 'service' specifies what service is desired (ie "calendar").
353 * 'service_type' specifies the reference type of the service
354 * (ie SUNW_fns_calendar);
356 * 'org' is the organization name. This must be NULL if 'name' is
357 * an absolute Helix name. 'org' may be NULL in all other cases if the
358 * default organization is to be used.
360 * 'buf' is a buffer provided by the caller in which the expanded name
363 * 'size' is the size of 'buf'
366 * The string returned in buf may be used in calls to dtfns_lookup_str() and
367 * dtfns_lookup_ref().
370 * -1 Name not found / Error
371 * 0 FNS not available
376 const char *name, /* Name to lookup */
377 const char *type, /* Type of object name is (ie "user") */
378 const char *service, /* Service name (ie "calendar") */
379 const char *service_type, /* Service reference type */
380 /* (ie "SUNW_fns_calendar"); */
381 const char *org, /* Org name (ie "ssi"). NULL for default org */
382 char *buf, /* Buffer to place name in */
383 const int size) /* Size of value_buf */
389 if (libfns_handle == NULL) {
397 if (org != NULL && *org != '\0') {
398 /* Sanity check for size */
399 if (strlen(org) + strlen(name) > (size_t)size - 50) {
403 /*Construct Helix name from name and organization */
404 sprintf(buf,"%s:%s:%s:%s:%s:%s", DTFNS_ORG_NAME,
405 org, type, name, DTFNS_SERVICE_NAME, service);
406 } else if (dtfns_isa_helix_name(name)) {
407 /* Helix name. Expand it to point to calendar service */
408 if (get_helix_service_name(name, service, service_type,
412 buf[size - 1] = '\0';
413 strncpy(buf, tmp_buf, size - 1);
417 /* Construct Helix name from name */
418 sprintf(buf,"%s:%s:%s:%s", type,
419 name, DTFNS_SERVICE_NAME, service);
426 * Return TRUE if 'name' is an absolute Helix name
429 dtfns_isa_helix_name(const char *name)
435 for (p = initial_context_names; *p != NULL; p++) {
437 if (strncmp(name, *p, len) == 0) {
446 * Get the org name for "myorg" (ie ssi.eng)
449 dtfns_myorg_name(char *buf, int len)
452 char *__nis_local_root();
453 static char *myorg_name;
454 char *principal_name;
458 char *myorg_p, *root_p;
460 if (myorg_name == NULL) {
461 principal_name = nis_local_principal();
462 host_domain = nis_local_directory();
463 root_domain = __nis_local_root();
465 if (principal_name) {
466 /* Get the domain this principal is in */
467 pd = nis_domain_of(principal_name);
468 if (pd && *pd == '.') {
473 /* If no domain for the principal, use the one for the host */
474 myorg_name = strdup(pd ? pd : (host_domain ? host_domain : ""));
477 * We want to strip the root domain name off of the
478 * end of the myorg name. Set pointers to the end
481 myorg_p = myorg_name + strlen(myorg_name) - 1;
482 root_p = root_domain + strlen(root_domain) - 1;
484 while (tolower(*myorg_p) == tolower(*root_p)) {
485 if (root_p == root_domain) {
486 /* Matched all of root domain name. Truncate */
487 if (myorg_p != myorg_name) {
491 } else if (myorg_p == myorg_name) {
499 if (myorg_name != NULL) {
501 strncpy(buf, myorg_name, len - 1);
508 * Return the string value bound to an absolute Helix name
512 * 0 FNS not available
517 const char *name, /* Absolute Helix name */
518 char *types[], /* Type of data to get */
519 char *dbuf, /* Buffer to place data value in */
520 int dsize, /* Size of dbuf */
521 char *tbuf, /* Buffer to place address type in */
522 int tsize) /* Size of tbuf */
525 NS_Reference_t * ref;
526 const NS_ReferenceAddress_t * addr;
529 if (libfns_handle == NULL) {
533 /* Get the reference from the name */
534 if ((ref = dtfns_lookup_ref(name)) == NULL) {
538 /* Get the address that matches at least one of the specified types */
539 if ((addr = dtfns_addr_from_ref(ref, types, &iter_pos)) == NULL) {
540 (*NS_Reference_delete_p)(ref);
544 (*NS_Reference_delete_p)(ref);
546 /* Return data bound to that address */
547 return dtfns_str_from_addr(addr, dbuf, dsize, tbuf, tsize);
552 * Bind a string to a name.
554 * name Absolute Helix name to bind string to
556 * ref_type Reference type. We need this to create
557 * the reference if it does not already exist.
559 * types Array of address types. This routine looks for
560 * the address that matches at least one of these
561 * types. The first type is used when the new
564 * new_str String to bind to name
568 * 0 FNS not available
573 const char *name, /* Absolute Helix name */
574 const char *ref_type, /* Reference type */
575 char *types[], /* Address type of data to operate on */
576 const char *new_str /* String to bind to name */
579 NS_Reference_t *ref = NULL;
580 const NS_ReferenceAddress_t *addr = NULL;
581 NS_ReferenceAddress_t *new_addr = NULL;
582 NS_CompositeName_t *comp_name;
583 NS_ContextStatus_t *status = NULL;
584 NS_Context_t *ctx = NULL;
586 void *iter_pos = NULL;
590 if (libfns_handle == NULL) {
594 /* Get the reference from the name */
595 if ((ref = dtfns_lookup_ref(name)) != NULL) {
597 * A value is already bound to this name.
598 * Get the address that matches at least one of
599 * the specified types
601 addr = dtfns_addr_from_ref(ref, types, &iter_pos);
603 /* Get string bound to that address */
605 dtfns_str_from_addr(addr, buf, sizeof(buf), NULL, 0);
607 /* Are we changing the string? */
608 if (strcmp(buf, new_str) == 0) {
609 /* Bound value is the same as new value */
613 /* Delete old address string */
614 (*NS_Reference_delete_addr_p)(ref, &iter_pos);
618 /* Nothing bound to name. Create an empty reference */
619 nstr = (*NS_String_from_cstring_p)(ref_type);
620 ref = (*NS_Reference_new_p)(nstr);
624 /* Create new address */
625 if ((new_addr = dtfns_create_str_addr(new_str, types[0])) == NULL) {
629 /* Insert new address into reference */
630 if (dtfns_insert_addr(ref, &iter_pos, new_addr) < 1) {
634 /* Bind reference into name space */
635 if ((ctx = dtfns_get_initial_ctx()) == NULL) {
639 status = (*NS_ContextStatus_new_p)();
640 comp_name = (*NS_CompositeName_from_cstring_p)(name);
642 if ((*NS_Context_bind_p)(ctx, comp_name, ref, 0, status) < 1) {
649 /* Clean up and return */
650 if (new_addr != NULL) (*NS_ReferenceAddress_delete_p)(new_addr);
651 if (ref != NULL) (*NS_Reference_delete_p)(ref);
652 if (status != NULL) (*NS_ContextStatus_delete_p)(status);
658 * Return the reference bound to an absolute Helix name
662 * NS_Reference_t * for reference
666 const char *name)/* Absolute Helix name to lookup */
669 NS_Reference_t * ref = NULL;
670 NS_ContextStatus_t * status = NULL;
671 NS_CompositeName_t * comp_name = NULL;
674 if (libfns_handle == NULL) {
678 status = (*NS_ContextStatus_new_p)();
679 if ((ctx = dtfns_get_initial_ctx()) != NULL) {
680 /* Lookup the Helix name specified by "name" */
681 comp_name = (*NS_CompositeName_from_cstring_p)(name);
682 ref = (*NS_Context_lookup_p)(ctx, comp_name, status);
685 (*NS_ContextStatus_delete_p)(status);
690 * Takes a Helix name and converts it to a full name for a service.
691 * I.e. if service is "calendar":
694 * org:ss-eng:user:dipol --> org:ss-eng:user:dipol:service:calendar
695 * org:ss-eng --> org:ss-eng:service:calendar
696 * org:ss-eng:service: --> org:ss-eng:service:calendar
699 * -1 Error. buf not set
700 * 0 name already points to the service
701 * buf is a duplicate of name.
702 * 1 name resolved. buf is set. Caller
703 * is responsible for freeing memory.
706 get_helix_service_name(
709 const char *service_type,
721 tmp_name = strdup(name);
723 /* Remove trailing : if there is one */
724 if (tmp_name[n - 1] == ':') {
725 tmp_name[n - 1] = '\0';
729 /* Get reference and extract reference type */
730 if ((ref = dtfns_lookup_ref(tmp_name)) == NULL) {
734 nstr = (*NS_Reference_type_p)(ref);
735 type = (*NS_String_cstring_p)(nstr);
737 (*NS_Reference_delete_p)(ref);
739 /* If name is already bound to a calendar service then we are done */
740 if (strcmp(type, service_type) == 0) {
745 if ((p = strrchr(tmp_name, ':')) != NULL) {
750 * If name is a service context or the "service" null context
751 * then we want to append ":calendar"
753 if (strcmp(type, DTFNS_SERVICE_CONTEXT_TYPE) == 0 ||
754 (strcmp(type, DTFNS_NULL_CONTEXT_TYPE) == 0 && p != NULL &&
755 strcmp(p, DTFNS_SERVICE_NAME) == 0)) {
757 *buf = (char *)malloc(n + strlen(service) + 2);
761 strcpy(*buf, tmp_name);
763 strcat(*buf, service);
766 /* Append ":service:calendar" */
767 *buf = (char *)malloc(n +
768 strlen(DTFNS_SERVICE_NAME) +
769 strlen(service) + 3);
770 sprintf(*buf, "%s:%s:%s", tmp_name,
771 DTFNS_SERVICE_NAME, service);
777 * Get an FNS Address from a Reference.
779 * ref The Reference to get the address from
781 * types NULL terminated array of one or more type strings.
782 * This routine returns the first address that matches
783 * a type specified in this array. NULL to just
784 * get the first address.
786 * iter_pos Updated to point after retrieved address.
789 * Pointer to the found address
790 * NULL if no address is found
793 const NS_ReferenceAddress_t *
795 const NS_Reference_t *ref, /* Reference to get addr from */
796 char *types[], /* Types of addrs to get */
797 void **iter_pos /* Returned pos where addr was found */
801 const NS_ReferenceAddress_t *addr;
805 if (libfns_handle == NULL) {
809 addr = (*NS_Reference_first_p)(ref, iter_pos);
814 while (addr != NULL) {
815 /* Get the type, and see if it is one we want */
816 dtfns_str_from_addr(addr, NULL, 0, type, sizeof(type));
817 for (p = types; *p != NULL && strcmp(*p, type) != 0; *p++)
824 /* Get next address */
825 addr = (*NS_Reference_next_p)(ref, iter_pos);
833 * Get the string and type out of an Address
837 * 0 FNS not available
842 const NS_ReferenceAddress_t *addr, /* Addr to get string from */
843 char *dbuf, /* Buf to hold string data */
844 int dbuf_size, /* Size of dbuf */
845 char *tbuf, /* Buf to hold string type */
846 int tbuf_size /* size of tbuf */
855 if (libfns_handle == NULL) {
860 /* Convert data from XDR to a string */
862 (caddr_t)(*NS_ReferenceAddress_data_p)(addr),
863 (*NS_ReferenceAddress_length_p)(addr), XDR_DECODE);
865 if (xdr_string(&xdr, &s, ~0) == FALSE) {
869 dbuf[dbuf_size - 1] = '\0';
870 strncpy(dbuf, s, dbuf_size - 1);
875 tbuf[tbuf_size - 1] = '\0';
876 nstr = (*NS_ReferenceAddress_type_p)(addr);
877 cs = (*NS_String_cstring_p)(nstr);
878 strncpy(tbuf, cs, tbuf_size - 1);
885 * Create an Address of type "type" for the string specified by "data"
888 * A new address contianing the specified data
891 NS_ReferenceAddress_t *
892 dtfns_create_str_addr(
900 NS_String_t *nstring;
902 if (libfns_handle == NULL) {
906 xdrmem_create(&xdr, (caddr_t)buf, sizeof(buf), XDR_ENCODE);
907 if (xdr_string(&xdr, (char**)&data, ~0) == FALSE) {
911 nstring = (*NS_String_from_cstring_p)(type);
912 return (*NS_ReferenceAddress_new_p)(nstring, xdr_getpos(&xdr), buf);
916 * Add an address to a reference at the location specified by iter_pos.
917 * The address is inserted before iter_pos.
918 * If *iter_pos is NULL then put the address in the first slot.
922 * 0 FNS not available
929 const NS_ReferenceAddress_t *addr
933 if (libfns_handle == NULL) {
937 if (*iter_pos == NULL) {
938 if ((*NS_Reference_prepend_addr_p)(ref, addr) < 1)
941 if ((*NS_Reference_insert_addr_p)(ref, iter_pos, addr) < 1)
949 * Delete the Address at position "iter_pos" from a Reference
953 * 0 FNS not available
963 if (libfns_handle == NULL) {
967 (*NS_Reference_delete_addr_p)(ref, iter_pos);